ALL: sync with scummvm
This commit is contained in:
parent
a59b2167b8
commit
c6c4bc7566
16 changed files with 425 additions and 190 deletions
|
@ -387,4 +387,42 @@ Timestamp convertTimeToStreamPos(const Timestamp &where, int rate, bool isStereo
|
|||
return Timestamp(result.secs(), result.numberOfFrames(), result.framerate());
|
||||
}
|
||||
|
||||
/**
|
||||
* An AudioStream wrapper that cuts off the amount of samples read after a
|
||||
* given time length is reached.
|
||||
*/
|
||||
class LimitingAudioStream : public AudioStream {
|
||||
public:
|
||||
LimitingAudioStream(AudioStream *parentStream, const Audio::Timestamp &length, DisposeAfterUse::Flag disposeAfterUse) :
|
||||
_parentStream(parentStream), _samplesRead(0), _disposeAfterUse(disposeAfterUse),
|
||||
_totalSamples(length.convertToFramerate(getRate()).totalNumberOfFrames() * getChannels()) {}
|
||||
|
||||
~LimitingAudioStream() {
|
||||
if (_disposeAfterUse == DisposeAfterUse::YES)
|
||||
delete _parentStream;
|
||||
}
|
||||
|
||||
int readBuffer(int16 *buffer, const int numSamples) {
|
||||
// Cap us off so we don't read past _totalSamples
|
||||
int samplesRead = _parentStream->readBuffer(buffer, MIN<int>(numSamples, _totalSamples - _samplesRead));
|
||||
_samplesRead += samplesRead;
|
||||
return samplesRead;
|
||||
}
|
||||
|
||||
bool endOfData() const { return _parentStream->endOfData() || _samplesRead >= _totalSamples; }
|
||||
bool isStereo() const { return _parentStream->isStereo(); }
|
||||
int getRate() const { return _parentStream->getRate(); }
|
||||
|
||||
private:
|
||||
int getChannels() const { return isStereo() ? 2 : 1; }
|
||||
|
||||
AudioStream *_parentStream;
|
||||
DisposeAfterUse::Flag _disposeAfterUse;
|
||||
uint32 _totalSamples, _samplesRead;
|
||||
};
|
||||
|
||||
AudioStream *makeLimitingAudioStream(AudioStream *parentStream, const Timestamp &length, DisposeAfterUse::Flag disposeAfterUse) {
|
||||
return new LimitingAudioStream(parentStream, length, disposeAfterUse);
|
||||
}
|
||||
|
||||
} // End of namespace Audio
|
||||
|
|
|
@ -356,6 +356,16 @@ QueuingAudioStream *makeQueuingAudioStream(int rate, bool stereo);
|
|||
*/
|
||||
Timestamp convertTimeToStreamPos(const Timestamp &where, int rate, bool isStereo);
|
||||
|
||||
/**
|
||||
* Factory function for an AudioStream wrapper that cuts off the amount of samples read after a
|
||||
* given time length is reached.
|
||||
*
|
||||
* @param parentStream The stream to limit
|
||||
* @param length The time length to limit the stream to
|
||||
* @param disposeAfterUse Whether the parent stream object should be destroyed on destruction of the returned stream
|
||||
*/
|
||||
AudioStream *makeLimitingAudioStream(AudioStream *parentStream, const Timestamp &length, DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES);
|
||||
|
||||
} // End of namespace Audio
|
||||
|
||||
#endif
|
||||
|
|
|
@ -32,24 +32,24 @@
|
|||
//////////////////////////////////////////////////
|
||||
|
||||
MidiParser::MidiParser() :
|
||||
_hanging_notes_count(0),
|
||||
_hangingNotesCount(0),
|
||||
_driver(0),
|
||||
_timer_rate(0x4A0000),
|
||||
_timerRate(0x4A0000),
|
||||
_ppqn(96),
|
||||
_tempo(500000),
|
||||
_psec_per_tick(5208), // 500000 / 96
|
||||
_psecPerTick(5208), // 500000 / 96
|
||||
_autoLoop(false),
|
||||
_smartJump(false),
|
||||
_centerPitchWheelOnUnload(false),
|
||||
_sendSustainOffOnNotesOff(false),
|
||||
_num_tracks(0),
|
||||
_active_track(255),
|
||||
_abort_parse(0) {
|
||||
memset(_active_notes, 0, sizeof(_active_notes));
|
||||
_next_event.start = NULL;
|
||||
_next_event.delta = 0;
|
||||
_next_event.event = 0;
|
||||
_next_event.length = 0;
|
||||
_numTracks(0),
|
||||
_activeTrack(255),
|
||||
_abortParse(0) {
|
||||
memset(_activeNotes, 0, sizeof(_activeNotes));
|
||||
_nextEvent.start = NULL;
|
||||
_nextEvent.delta = 0;
|
||||
_nextEvent.event = 0;
|
||||
_nextEvent.length = 0;
|
||||
}
|
||||
|
||||
void MidiParser::property(int prop, int value) {
|
||||
|
@ -76,7 +76,7 @@ void MidiParser::sendToDriver(uint32 b) {
|
|||
void MidiParser::setTempo(uint32 tempo) {
|
||||
_tempo = tempo;
|
||||
if (_ppqn)
|
||||
_psec_per_tick = (tempo + (_ppqn >> 2)) / _ppqn;
|
||||
_psecPerTick = (tempo + (_ppqn >> 2)) / _ppqn;
|
||||
}
|
||||
|
||||
// This is the conventional (i.e. SMF) variable length quantity
|
||||
|
@ -100,44 +100,44 @@ void MidiParser::activeNote(byte channel, byte note, bool active) {
|
|||
return;
|
||||
|
||||
if (active)
|
||||
_active_notes[note] |= (1 << channel);
|
||||
_activeNotes[note] |= (1 << channel);
|
||||
else
|
||||
_active_notes[note] &= ~(1 << channel);
|
||||
_activeNotes[note] &= ~(1 << channel);
|
||||
|
||||
// See if there are hanging notes that we can cancel
|
||||
NoteTimer *ptr = _hanging_notes;
|
||||
NoteTimer *ptr = _hangingNotes;
|
||||
int i;
|
||||
for (i = ARRAYSIZE(_hanging_notes); i; --i, ++ptr) {
|
||||
if (ptr->channel == channel && ptr->note == note && ptr->time_left) {
|
||||
ptr->time_left = 0;
|
||||
--_hanging_notes_count;
|
||||
for (i = ARRAYSIZE(_hangingNotes); i; --i, ++ptr) {
|
||||
if (ptr->channel == channel && ptr->note == note && ptr->timeLeft) {
|
||||
ptr->timeLeft = 0;
|
||||
--_hangingNotesCount;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MidiParser::hangingNote(byte channel, byte note, uint32 time_left, bool recycle) {
|
||||
void MidiParser::hangingNote(byte channel, byte note, uint32 timeLeft, bool recycle) {
|
||||
NoteTimer *best = 0;
|
||||
NoteTimer *ptr = _hanging_notes;
|
||||
NoteTimer *ptr = _hangingNotes;
|
||||
int i;
|
||||
|
||||
if (_hanging_notes_count >= ARRAYSIZE(_hanging_notes)) {
|
||||
if (_hangingNotesCount >= ARRAYSIZE(_hangingNotes)) {
|
||||
warning("MidiParser::hangingNote(): Exceeded polyphony");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = ARRAYSIZE(_hanging_notes); i; --i, ++ptr) {
|
||||
for (i = ARRAYSIZE(_hangingNotes); i; --i, ++ptr) {
|
||||
if (ptr->channel == channel && ptr->note == note) {
|
||||
if (ptr->time_left && ptr->time_left < time_left && recycle)
|
||||
if (ptr->timeLeft && ptr->timeLeft < timeLeft && recycle)
|
||||
return;
|
||||
best = ptr;
|
||||
if (ptr->time_left) {
|
||||
if (ptr->timeLeft) {
|
||||
if (recycle)
|
||||
sendToDriver(0x80 | channel, note, 0);
|
||||
--_hanging_notes_count;
|
||||
--_hangingNotesCount;
|
||||
}
|
||||
break;
|
||||
} else if (!best && ptr->time_left == 0) {
|
||||
} else if (!best && ptr->timeLeft == 0) {
|
||||
best = ptr;
|
||||
}
|
||||
}
|
||||
|
@ -146,14 +146,14 @@ void MidiParser::hangingNote(byte channel, byte note, uint32 time_left, bool rec
|
|||
// length, if the note should be turned on and off in
|
||||
// the same iteration. For now just set it to 1 and
|
||||
// we'll turn it off in the next cycle.
|
||||
if (!time_left || time_left & 0x80000000)
|
||||
time_left = 1;
|
||||
if (!timeLeft || timeLeft & 0x80000000)
|
||||
timeLeft = 1;
|
||||
|
||||
if (best) {
|
||||
best->channel = channel;
|
||||
best->note = note;
|
||||
best->time_left = time_left;
|
||||
++_hanging_notes_count;
|
||||
best->timeLeft = timeLeft;
|
||||
++_hangingNotesCount;
|
||||
} else {
|
||||
// We checked this up top. We should never get here!
|
||||
warning("MidiParser::hangingNote(): Internal error");
|
||||
|
@ -161,45 +161,45 @@ void MidiParser::hangingNote(byte channel, byte note, uint32 time_left, bool rec
|
|||
}
|
||||
|
||||
void MidiParser::onTimer() {
|
||||
uint32 end_time;
|
||||
uint32 event_time;
|
||||
uint32 endTime;
|
||||
uint32 eventTime;
|
||||
|
||||
if (!_position._play_pos || !_driver)
|
||||
if (!_position._playPos || !_driver)
|
||||
return;
|
||||
|
||||
_abort_parse = false;
|
||||
end_time = _position._play_time + _timer_rate;
|
||||
_abortParse = false;
|
||||
endTime = _position._playTime + _timerRate;
|
||||
|
||||
// Scan our hanging notes for any
|
||||
// that should be turned off.
|
||||
if (_hanging_notes_count) {
|
||||
NoteTimer *ptr = &_hanging_notes[0];
|
||||
if (_hangingNotesCount) {
|
||||
NoteTimer *ptr = &_hangingNotes[0];
|
||||
int i;
|
||||
for (i = ARRAYSIZE(_hanging_notes); i; --i, ++ptr) {
|
||||
if (ptr->time_left) {
|
||||
if (ptr->time_left <= _timer_rate) {
|
||||
for (i = ARRAYSIZE(_hangingNotes); i; --i, ++ptr) {
|
||||
if (ptr->timeLeft) {
|
||||
if (ptr->timeLeft <= _timerRate) {
|
||||
sendToDriver(0x80 | ptr->channel, ptr->note, 0);
|
||||
ptr->time_left = 0;
|
||||
--_hanging_notes_count;
|
||||
ptr->timeLeft = 0;
|
||||
--_hangingNotesCount;
|
||||
} else {
|
||||
ptr->time_left -= _timer_rate;
|
||||
ptr->timeLeft -= _timerRate;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (!_abort_parse) {
|
||||
EventInfo &info = _next_event;
|
||||
while (!_abortParse) {
|
||||
EventInfo &info = _nextEvent;
|
||||
|
||||
event_time = _position._last_event_time + info.delta * _psec_per_tick;
|
||||
if (event_time > end_time)
|
||||
eventTime = _position._lastEventTime + info.delta * _psecPerTick;
|
||||
if (eventTime > endTime)
|
||||
break;
|
||||
|
||||
// Process the next info.
|
||||
_position._last_event_tick += info.delta;
|
||||
_position._lastEventTick += info.delta;
|
||||
if (info.event < 0x80) {
|
||||
warning("Bad command or running status %02X", info.event);
|
||||
_position._play_pos = 0;
|
||||
_position._playPos = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -217,7 +217,7 @@ void MidiParser::onTimer() {
|
|||
// as well as sending it to the output device.
|
||||
if (_autoLoop) {
|
||||
jumpToTick(0);
|
||||
parseNextEvent(_next_event);
|
||||
parseNextEvent(_nextEvent);
|
||||
} else {
|
||||
stopPlaying();
|
||||
_driver->metaEvent(info.ext.type, info.ext.data, (uint16)info.length);
|
||||
|
@ -234,7 +234,7 @@ void MidiParser::onTimer() {
|
|||
activeNote(info.channel(), info.basic.param1, false);
|
||||
} else if (info.command() == 0x9) {
|
||||
if (info.length > 0)
|
||||
hangingNote(info.channel(), info.basic.param1, info.length * _psec_per_tick - (end_time - event_time));
|
||||
hangingNote(info.channel(), info.basic.param1, info.length * _psecPerTick - (endTime - eventTime));
|
||||
else
|
||||
activeNote(info.channel(), info.basic.param1, true);
|
||||
}
|
||||
|
@ -242,15 +242,15 @@ void MidiParser::onTimer() {
|
|||
}
|
||||
|
||||
|
||||
if (!_abort_parse) {
|
||||
_position._last_event_time = event_time;
|
||||
parseNextEvent(_next_event);
|
||||
if (!_abortParse) {
|
||||
_position._lastEventTime = eventTime;
|
||||
parseNextEvent(_nextEvent);
|
||||
}
|
||||
}
|
||||
|
||||
if (!_abort_parse) {
|
||||
_position._play_time = end_time;
|
||||
_position._play_tick = (_position._play_time - _position._last_event_time) / _psec_per_tick + _position._last_event_tick;
|
||||
if (!_abortParse) {
|
||||
_position._playTime = endTime;
|
||||
_position._playTick = (_position._playTime - _position._lastEventTime) / _psecPerTick + _position._lastEventTick;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -263,20 +263,20 @@ void MidiParser::allNotesOff() {
|
|||
// Turn off all active notes
|
||||
for (i = 0; i < 128; ++i) {
|
||||
for (j = 0; j < 16; ++j) {
|
||||
if (_active_notes[i] & (1 << j)) {
|
||||
if (_activeNotes[i] & (1 << j)) {
|
||||
sendToDriver(0x80 | j, i, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Turn off all hanging notes
|
||||
for (i = 0; i < ARRAYSIZE(_hanging_notes); i++) {
|
||||
if (_hanging_notes[i].time_left) {
|
||||
sendToDriver(0x80 | _hanging_notes[i].channel, _hanging_notes[i].note, 0);
|
||||
_hanging_notes[i].time_left = 0;
|
||||
for (i = 0; i < ARRAYSIZE(_hangingNotes); i++) {
|
||||
if (_hangingNotes[i].timeLeft) {
|
||||
sendToDriver(0x80 | _hangingNotes[i].channel, _hangingNotes[i].note, 0);
|
||||
_hangingNotes[i].timeLeft = 0;
|
||||
}
|
||||
}
|
||||
_hanging_notes_count = 0;
|
||||
_hangingNotesCount = 0;
|
||||
|
||||
// To be sure, send an "All Note Off" event (but not all MIDI devices
|
||||
// support this...).
|
||||
|
@ -287,7 +287,7 @@ void MidiParser::allNotesOff() {
|
|||
sendToDriver(0xB0 | i, 0x40, 0); // Also send a sustain off event (bug #3116608)
|
||||
}
|
||||
|
||||
memset(_active_notes, 0, sizeof(_active_notes));
|
||||
memset(_activeNotes, 0, sizeof(_activeNotes));
|
||||
}
|
||||
|
||||
void MidiParser::resetTracking() {
|
||||
|
@ -295,7 +295,7 @@ void MidiParser::resetTracking() {
|
|||
}
|
||||
|
||||
bool MidiParser::setTrack(int track) {
|
||||
if (track < 0 || track >= _num_tracks)
|
||||
if (track < 0 || track >= _numTracks)
|
||||
return false;
|
||||
// We allow restarting the track via setTrack when
|
||||
// it isn't playing anymore. This allows us to reuse
|
||||
|
@ -308,7 +308,7 @@ bool MidiParser::setTrack(int track) {
|
|||
// TODO: Check if any engine has problem with this
|
||||
// handling, if so we need to find a better way to handle
|
||||
// track restarts. (KYRA relies on this working)
|
||||
else if (track == _active_track && isPlaying())
|
||||
else if (track == _activeTrack && isPlaying())
|
||||
return true;
|
||||
|
||||
if (_smartJump)
|
||||
|
@ -317,10 +317,10 @@ bool MidiParser::setTrack(int track) {
|
|||
allNotesOff();
|
||||
|
||||
resetTracking();
|
||||
memset(_active_notes, 0, sizeof(_active_notes));
|
||||
_active_track = track;
|
||||
_position._play_pos = _tracks[track];
|
||||
parseNextEvent(_next_event);
|
||||
memset(_activeNotes, 0, sizeof(_activeNotes));
|
||||
_activeTrack = track;
|
||||
_position._playPos = _tracks[track];
|
||||
parseNextEvent(_nextEvent);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -332,29 +332,29 @@ void MidiParser::stopPlaying() {
|
|||
void MidiParser::hangAllActiveNotes() {
|
||||
// Search for note off events until we have
|
||||
// accounted for every active note.
|
||||
uint16 temp_active[128];
|
||||
memcpy(temp_active, _active_notes, sizeof (temp_active));
|
||||
uint16 tempActive[128];
|
||||
memcpy(tempActive, _activeNotes, sizeof (tempActive));
|
||||
|
||||
uint32 advance_tick = _position._last_event_tick;
|
||||
uint32 advanceTick = _position._lastEventTick;
|
||||
while (true) {
|
||||
int i;
|
||||
for (i = 0; i < 128; ++i)
|
||||
if (temp_active[i] != 0)
|
||||
if (tempActive[i] != 0)
|
||||
break;
|
||||
if (i == 128)
|
||||
break;
|
||||
parseNextEvent(_next_event);
|
||||
advance_tick += _next_event.delta;
|
||||
if (_next_event.command() == 0x8) {
|
||||
if (temp_active[_next_event.basic.param1] & (1 << _next_event.channel())) {
|
||||
hangingNote(_next_event.channel(), _next_event.basic.param1, (advance_tick - _position._last_event_tick) * _psec_per_tick, false);
|
||||
temp_active[_next_event.basic.param1] &= ~(1 << _next_event.channel());
|
||||
parseNextEvent(_nextEvent);
|
||||
advanceTick += _nextEvent.delta;
|
||||
if (_nextEvent.command() == 0x8) {
|
||||
if (tempActive[_nextEvent.basic.param1] & (1 << _nextEvent.channel())) {
|
||||
hangingNote(_nextEvent.channel(), _nextEvent.basic.param1, (advanceTick - _position._lastEventTick) * _psecPerTick, false);
|
||||
tempActive[_nextEvent.basic.param1] &= ~(1 << _nextEvent.channel());
|
||||
}
|
||||
} else if (_next_event.event == 0xFF && _next_event.ext.type == 0x2F) {
|
||||
} else if (_nextEvent.event == 0xFF && _nextEvent.ext.type == 0x2F) {
|
||||
// warning("MidiParser::hangAllActiveNotes(): Hit End of Track with active notes left");
|
||||
for (i = 0; i < 128; ++i) {
|
||||
for (int j = 0; j < 16; ++j) {
|
||||
if (temp_active[i] & (1 << j)) {
|
||||
if (tempActive[i] & (1 << j)) {
|
||||
activeNote(j, i, false);
|
||||
sendToDriver(0x80 | j, i, 0);
|
||||
}
|
||||
|
@ -366,33 +366,33 @@ void MidiParser::hangAllActiveNotes() {
|
|||
}
|
||||
|
||||
bool MidiParser::jumpToTick(uint32 tick, bool fireEvents, bool stopNotes, bool dontSendNoteOn) {
|
||||
if (_active_track >= _num_tracks)
|
||||
if (_activeTrack >= _numTracks)
|
||||
return false;
|
||||
|
||||
Tracker currentPos(_position);
|
||||
EventInfo currentEvent(_next_event);
|
||||
EventInfo currentEvent(_nextEvent);
|
||||
|
||||
resetTracking();
|
||||
_position._play_pos = _tracks[_active_track];
|
||||
parseNextEvent(_next_event);
|
||||
_position._playPos = _tracks[_activeTrack];
|
||||
parseNextEvent(_nextEvent);
|
||||
if (tick > 0) {
|
||||
while (true) {
|
||||
EventInfo &info = _next_event;
|
||||
if (_position._last_event_tick + info.delta >= tick) {
|
||||
_position._play_time += (tick - _position._last_event_tick) * _psec_per_tick;
|
||||
_position._play_tick = tick;
|
||||
EventInfo &info = _nextEvent;
|
||||
if (_position._lastEventTick + info.delta >= tick) {
|
||||
_position._playTime += (tick - _position._lastEventTick) * _psecPerTick;
|
||||
_position._playTick = tick;
|
||||
break;
|
||||
}
|
||||
|
||||
_position._last_event_tick += info.delta;
|
||||
_position._last_event_time += info.delta * _psec_per_tick;
|
||||
_position._play_tick = _position._last_event_tick;
|
||||
_position._play_time = _position._last_event_time;
|
||||
_position._lastEventTick += info.delta;
|
||||
_position._lastEventTime += info.delta * _psecPerTick;
|
||||
_position._playTick = _position._lastEventTick;
|
||||
_position._playTime = _position._lastEventTime;
|
||||
|
||||
if (info.event == 0xFF) {
|
||||
if (info.ext.type == 0x2F) { // End of track
|
||||
_position = currentPos;
|
||||
_next_event = currentEvent;
|
||||
_nextEvent = currentEvent;
|
||||
return false;
|
||||
} else {
|
||||
if (info.ext.type == 0x51 && info.length >= 3) // Tempo
|
||||
|
@ -419,36 +419,36 @@ bool MidiParser::jumpToTick(uint32 tick, bool fireEvents, bool stopNotes, bool d
|
|||
}
|
||||
}
|
||||
|
||||
parseNextEvent(_next_event);
|
||||
parseNextEvent(_nextEvent);
|
||||
}
|
||||
}
|
||||
|
||||
if (stopNotes) {
|
||||
if (!_smartJump || !currentPos._play_pos) {
|
||||
if (!_smartJump || !currentPos._playPos) {
|
||||
allNotesOff();
|
||||
} else {
|
||||
EventInfo targetEvent(_next_event);
|
||||
EventInfo targetEvent(_nextEvent);
|
||||
Tracker targetPosition(_position);
|
||||
|
||||
_position = currentPos;
|
||||
_next_event = currentEvent;
|
||||
_nextEvent = currentEvent;
|
||||
hangAllActiveNotes();
|
||||
|
||||
_next_event = targetEvent;
|
||||
_nextEvent = targetEvent;
|
||||
_position = targetPosition;
|
||||
}
|
||||
}
|
||||
|
||||
_abort_parse = true;
|
||||
_abortParse = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void MidiParser::unloadMusic() {
|
||||
resetTracking();
|
||||
allNotesOff();
|
||||
_num_tracks = 0;
|
||||
_active_track = 255;
|
||||
_abort_parse = true;
|
||||
_numTracks = 0;
|
||||
_activeTrack = 255;
|
||||
_abortParse = true;
|
||||
|
||||
if (_centerPitchWheelOnUnload) {
|
||||
// Center the pitch wheels in preparation for the next piece of
|
||||
|
|
|
@ -49,33 +49,33 @@ class MidiDriver_BASE;
|
|||
* each Tracker location.
|
||||
*/
|
||||
struct Tracker {
|
||||
byte * _play_pos; ///< A pointer to the next event to be parsed
|
||||
uint32 _play_time; ///< Current time in microseconds; may be in between event times
|
||||
uint32 _play_tick; ///< Current MIDI tick; may be in between event ticks
|
||||
uint32 _last_event_time; ///< The time, in microseconds, of the last event that was parsed
|
||||
uint32 _last_event_tick; ///< The tick at which the last parsed event occurs
|
||||
byte _running_status; ///< Cached MIDI command, for MIDI streams that rely on implied event codes
|
||||
byte * _playPos; ///< A pointer to the next event to be parsed
|
||||
uint32 _playTime; ///< Current time in microseconds; may be in between event times
|
||||
uint32 _playTick; ///< Current MIDI tick; may be in between event ticks
|
||||
uint32 _lastEventTime; ///< The time, in microseconds, of the last event that was parsed
|
||||
uint32 _lastEventTick; ///< The tick at which the last parsed event occurs
|
||||
byte _runningStatus; ///< Cached MIDI command, for MIDI streams that rely on implied event codes
|
||||
|
||||
Tracker() { clear(); }
|
||||
|
||||
/// Copy constructor for each duplication of Tracker information.
|
||||
Tracker(const Tracker ©) :
|
||||
_play_pos(copy._play_pos),
|
||||
_play_time(copy._play_time),
|
||||
_play_tick(copy._play_tick),
|
||||
_last_event_time(copy._last_event_time),
|
||||
_last_event_tick(copy._last_event_tick),
|
||||
_running_status(copy._running_status)
|
||||
_playPos(copy._playPos),
|
||||
_playTime(copy._playTime),
|
||||
_playTick(copy._playTick),
|
||||
_lastEventTime(copy._lastEventTime),
|
||||
_lastEventTick(copy._lastEventTick),
|
||||
_runningStatus(copy._runningStatus)
|
||||
{ }
|
||||
|
||||
/// Clears all data; used by the constructor for initialization.
|
||||
void clear() {
|
||||
_play_pos = 0;
|
||||
_play_time = 0;
|
||||
_play_tick = 0;
|
||||
_last_event_time = 0;
|
||||
_last_event_tick = 0;
|
||||
_running_status = 0;
|
||||
_playPos = 0;
|
||||
_playTime = 0;
|
||||
_playTick = 0;
|
||||
_lastEventTime = 0;
|
||||
_lastEventTick = 0;
|
||||
_runningStatus = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -119,8 +119,8 @@ struct EventInfo {
|
|||
struct NoteTimer {
|
||||
byte channel; ///< The MIDI channel on which the note was played
|
||||
byte note; ///< The note number for the active note
|
||||
uint32 time_left; ///< The time, in microseconds, remaining before the note should be turned off
|
||||
NoteTimer() : channel(0), note(0), time_left(0) {}
|
||||
uint32 timeLeft; ///< The time, in microseconds, remaining before the note should be turned off
|
||||
NoteTimer() : channel(0), note(0), timeLeft(0) {}
|
||||
};
|
||||
|
||||
|
||||
|
@ -264,29 +264,29 @@ struct NoteTimer {
|
|||
*/
|
||||
class MidiParser {
|
||||
protected:
|
||||
uint16 _active_notes[128]; ///< Each uint16 is a bit mask for channels that have that note on.
|
||||
NoteTimer _hanging_notes[32]; ///< Maintains expiration info for up to 32 notes.
|
||||
uint16 _activeNotes[128]; ///< Each uint16 is a bit mask for channels that have that note on.
|
||||
NoteTimer _hangingNotes[32]; ///< Maintains expiration info for up to 32 notes.
|
||||
///< Used for "Smart Jump" and MIDI formats that do not include explicit Note Off events.
|
||||
byte _hanging_notes_count; ///< Count of hanging notes, used to optimize expiration.
|
||||
byte _hangingNotesCount; ///< Count of hanging notes, used to optimize expiration.
|
||||
|
||||
MidiDriver_BASE *_driver; ///< The device to which all events will be transmitted.
|
||||
uint32 _timer_rate; ///< The time in microseconds between onTimer() calls. Obtained from the MidiDriver.
|
||||
uint32 _timerRate; ///< The time in microseconds between onTimer() calls. Obtained from the MidiDriver.
|
||||
uint32 _ppqn; ///< Pulses Per Quarter Note. (We refer to "pulses" as "ticks".)
|
||||
uint32 _tempo; ///< Microseconds per quarter note.
|
||||
uint32 _psec_per_tick; ///< Microseconds per tick (_tempo / _ppqn).
|
||||
uint32 _psecPerTick; ///< Microseconds per tick (_tempo / _ppqn).
|
||||
bool _autoLoop; ///< For lightweight clients that don't provide their own flow control.
|
||||
bool _smartJump; ///< Support smart expiration of hanging notes when jumping
|
||||
bool _centerPitchWheelOnUnload; ///< Center the pitch wheels when unloading a song
|
||||
bool _sendSustainOffOnNotesOff; ///< Send a sustain off on a notes off event, stopping hanging notes
|
||||
byte *_tracks[120]; ///< Multi-track MIDI formats are supported, up to 120 tracks.
|
||||
byte _num_tracks; ///< Count of total tracks for multi-track MIDI formats. 1 for single-track formats.
|
||||
byte _active_track; ///< Keeps track of the currently active track, in multi-track formats.
|
||||
byte _numTracks; ///< Count of total tracks for multi-track MIDI formats. 1 for single-track formats.
|
||||
byte _activeTrack; ///< Keeps track of the currently active track, in multi-track formats.
|
||||
|
||||
Tracker _position; ///< The current time/position in the active track.
|
||||
EventInfo _next_event; ///< The next event to transmit. Events are preparsed
|
||||
EventInfo _nextEvent; ///< The next event to transmit. Events are preparsed
|
||||
///< so each event is parsed only once; this permits
|
||||
///< simulated events in certain formats.
|
||||
bool _abort_parse; ///< If a jump or other operation interrupts parsing, flag to abort.
|
||||
bool _abortParse; ///< If a jump or other operation interrupts parsing, flag to abort.
|
||||
|
||||
protected:
|
||||
static uint32 readVLQ(byte * &data);
|
||||
|
@ -295,7 +295,7 @@ protected:
|
|||
virtual void parseNextEvent(EventInfo &info) = 0;
|
||||
|
||||
void activeNote(byte channel, byte note, bool active);
|
||||
void hangingNote(byte channel, byte note, uint32 ticks_left, bool recycle = true);
|
||||
void hangingNote(byte channel, byte note, uint32 ticksLeft, bool recycle = true);
|
||||
void hangAllActiveNotes();
|
||||
|
||||
virtual void sendToDriver(uint32 b);
|
||||
|
@ -377,18 +377,18 @@ public:
|
|||
virtual void property(int prop, int value);
|
||||
|
||||
void setMidiDriver(MidiDriver_BASE *driver) { _driver = driver; }
|
||||
void setTimerRate(uint32 rate) { _timer_rate = rate; }
|
||||
void setTimerRate(uint32 rate) { _timerRate = rate; }
|
||||
void setTempo(uint32 tempo);
|
||||
void onTimer();
|
||||
|
||||
bool isPlaying() const { return (_position._play_pos != 0); }
|
||||
bool isPlaying() const { return (_position._playPos != 0); }
|
||||
void stopPlaying();
|
||||
|
||||
bool setTrack(int track);
|
||||
bool jumpToTick(uint32 tick, bool fireEvents = false, bool stopNotes = true, bool dontSendNoteOn = false);
|
||||
|
||||
uint32 getPPQN() { return _ppqn; }
|
||||
virtual uint32 getTick() { return _position._play_tick; }
|
||||
virtual uint32 getTick() { return _position._playTick; }
|
||||
|
||||
static void defaultXMidiCallback(byte eventData, void *refCon);
|
||||
|
||||
|
|
|
@ -146,6 +146,12 @@
|
|||
*/
|
||||
#define MKTAG(a0,a1,a2,a3) ((uint32)((a3) | ((a2) << 8) | ((a1) << 16) | ((a0) << 24)))
|
||||
|
||||
/**
|
||||
* A wrapper macro used around two character constants, like 'wb', to
|
||||
* ensure portability. Typical usage: MKTAG16('w','b').
|
||||
*/
|
||||
#define MKTAG16(a0,a1) ((uint16)((a1) | ((a0) << 8)))
|
||||
|
||||
// Functions for reading/writing native integers.
|
||||
// They also transparently handle the need for alignment.
|
||||
|
||||
|
|
|
@ -85,6 +85,60 @@ bool inflateZlibHeaderless(byte *dst, uint dstLen, const byte *src, uint srcLen,
|
|||
return true;
|
||||
}
|
||||
|
||||
enum {
|
||||
kTempBufSize = 65536
|
||||
};
|
||||
|
||||
bool inflateZlibInstallShield(byte *dst, uint dstLen, const byte *src, uint srcLen) {
|
||||
if (!dst || !dstLen || !src || !srcLen)
|
||||
return false;
|
||||
|
||||
// See if we have sync bytes. If so, just use our function for that.
|
||||
if (srcLen >= 4 && READ_BE_UINT32(src + srcLen - 4) == 0xFFFF)
|
||||
return inflateZlibHeaderless(dst, dstLen, src, srcLen);
|
||||
|
||||
// Otherwise, we have some custom code we get to use here.
|
||||
|
||||
byte *temp = (byte *)malloc(kTempBufSize);
|
||||
|
||||
uint32 bytesRead = 0, bytesProcessed = 0;
|
||||
while (bytesRead < srcLen) {
|
||||
uint16 chunkSize = READ_LE_UINT16(src + bytesRead);
|
||||
bytesRead += 2;
|
||||
|
||||
// Initialize zlib
|
||||
z_stream stream;
|
||||
stream.next_in = const_cast<byte *>(src + bytesRead);
|
||||
stream.avail_in = chunkSize;
|
||||
stream.next_out = temp;
|
||||
stream.avail_out = kTempBufSize;
|
||||
stream.zalloc = Z_NULL;
|
||||
stream.zfree = Z_NULL;
|
||||
stream.opaque = Z_NULL;
|
||||
|
||||
// Negative MAX_WBITS tells zlib there's no zlib header
|
||||
int err = inflateInit2(&stream, -MAX_WBITS);
|
||||
if (err != Z_OK)
|
||||
return false;
|
||||
|
||||
err = inflate(&stream, Z_FINISH);
|
||||
if (err != Z_OK && err != Z_STREAM_END) {
|
||||
inflateEnd(&stream);
|
||||
free(temp);
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(dst + bytesProcessed, temp, stream.total_out);
|
||||
bytesProcessed += stream.total_out;
|
||||
|
||||
inflateEnd(&stream);
|
||||
bytesRead += chunkSize;
|
||||
}
|
||||
|
||||
free(temp);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple wrapper class which can be used to wrap around an arbitrary
|
||||
* other SeekableReadStream and will then provide on-the-fly decompression support.
|
||||
|
|
|
@ -77,6 +77,25 @@ bool uncompress(byte *dst, unsigned long *dstLen, const byte *src, unsigned long
|
|||
*/
|
||||
bool inflateZlibHeaderless(byte *dst, uint dstLen, const byte *src, uint srcLen, const byte *dict = 0, uint dictLen = 0);
|
||||
|
||||
/**
|
||||
* Wrapper around zlib's inflate functions. This function will call the
|
||||
* necessary inflate functions to uncompress data compressed for InstallShield
|
||||
* cabinet files.
|
||||
*
|
||||
* Decompresses the src buffer into the dst buffer.
|
||||
* srcLen is the byte length of the source buffer, dstLen is the byte
|
||||
* length of the output buffer.
|
||||
* It decompress as much data as possible, up to dstLen bytes.
|
||||
*
|
||||
* @param dst the buffer to store into.
|
||||
* @param dstLen the size of the destination buffer.
|
||||
* @param src the data to be decompressed.
|
||||
* @param dstLen the size of the compressed data.
|
||||
*
|
||||
* @return true on success (Z_OK or Z_STREAM_END), false otherwise.
|
||||
*/
|
||||
bool inflateZlibInstallShield(byte *dst, uint dstLen, const byte *src, uint srcLen);
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
|
80
configure
vendored
80
configure
vendored
|
@ -62,7 +62,7 @@ get_var() {
|
|||
eval echo \$${1}
|
||||
}
|
||||
|
||||
# Add an engine: id name build subengines
|
||||
# Add an engine: id name build subengines dependencies
|
||||
add_engine() {
|
||||
_engines="${_engines} ${1}"
|
||||
if test "${3}" = "no" ; then
|
||||
|
@ -72,11 +72,20 @@ 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}"
|
||||
for sub in ${4}; do
|
||||
set_var _engine_${sub}_sub "yes"
|
||||
done
|
||||
}
|
||||
|
||||
# Add a feature: id name settings-list
|
||||
add_feature() {
|
||||
set_var _feature_${1}_name "${2}"
|
||||
# This is a list of settings, where one must be "yes" for the feature to
|
||||
# be enabled
|
||||
set_var _feature_${1}_settings "${3}"
|
||||
}
|
||||
|
||||
_srcdir=`dirname $0`
|
||||
|
||||
# Read list of engines
|
||||
|
@ -166,6 +175,17 @@ _endian=unknown
|
|||
_need_memalign=yes
|
||||
_have_x86=no
|
||||
|
||||
# Add (virtual) features
|
||||
add_feature 16bit "16bit color" "_16bit"
|
||||
add_feature faad "libfaad" "_faad"
|
||||
add_feature flac "FLAC" "_flac"
|
||||
add_feature freetype2 "FreeType2" "_freetype2"
|
||||
add_feature mad "MAD" "_mad"
|
||||
add_feature png "PNG" "_png"
|
||||
add_feature theoradec "libtheoradec" "_theoradec"
|
||||
add_feature vorbis "Vorbis file support" "_vorbis _tremor"
|
||||
add_feature zlib "zlib" "_zlib"
|
||||
|
||||
|
||||
|
||||
# Directories for installing ScummVM.
|
||||
|
@ -443,6 +463,26 @@ Try \`$0 --help' for more information." >&2
|
|||
}
|
||||
|
||||
|
||||
#
|
||||
# Feature handling functions
|
||||
#
|
||||
|
||||
# Get the name of the feature
|
||||
get_feature_name() {
|
||||
get_var _feature_$1_name
|
||||
}
|
||||
|
||||
# Check whether the feature is enabled
|
||||
get_feature_state() {
|
||||
for i in `get_var _feature_$1_settings`; do
|
||||
if test `get_var $i` = "yes"; then
|
||||
echo "yes"
|
||||
return
|
||||
fi
|
||||
done
|
||||
echo "no"
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Engine handling functions
|
||||
|
@ -468,6 +508,11 @@ get_engine_subengines() {
|
|||
get_var _engine_$1_subengines
|
||||
}
|
||||
|
||||
# Get the dependencies
|
||||
get_engine_dependencies() {
|
||||
get_var _engine_$1_deps
|
||||
}
|
||||
|
||||
# Ask if this is a subengine
|
||||
get_engine_sub() {
|
||||
sub=`get_var _engine_$1_sub`
|
||||
|
@ -536,6 +581,29 @@ engine_disable() {
|
|||
fi
|
||||
}
|
||||
|
||||
# Check whether the engine's dependencies are met
|
||||
# If that is not the case disable the engine
|
||||
check_engine_deps() {
|
||||
unmet_deps=""
|
||||
|
||||
# Check whether the engine is enabled
|
||||
if test `get_engine_build $1` = yes ; then
|
||||
# Collect unmet dependencies
|
||||
for dep in `get_engine_dependencies $1`; do
|
||||
if test `get_feature_state $dep` = "no"; then
|
||||
feature_name=`get_feature_name $dep`
|
||||
unmet_deps="${unmet_deps}${feature_name} "
|
||||
fi
|
||||
done
|
||||
|
||||
# Check whether there is any unmet dependency
|
||||
if test -n "$unmet_deps"; then
|
||||
echo "WARNING: Disabling engine "`get_engine_name $1`" because the following dependencies are unmet: "$unmet_deps
|
||||
engine_disable $1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Show the configure help line for a given engine
|
||||
show_engine_help() {
|
||||
name=`get_engine_name $1`
|
||||
|
@ -1821,7 +1889,9 @@ case $_host_cpu in
|
|||
define_in_config_if_yes yes 'USE_ARM_SOUND_ASM'
|
||||
define_in_config_if_yes yes 'USE_ARM_SMUSH_ASM'
|
||||
define_in_config_if_yes yes 'USE_ARM_GFX_ASM'
|
||||
define_in_config_if_yes yes 'USE_ARM_COSTUME_ASM'
|
||||
# FIXME: The following feature exhibits a bug during the intro scene of Indy 4
|
||||
# (on Pandora and iPhone at least)
|
||||
#define_in_config_if_yes yes 'USE_ARM_COSTUME_ASM'
|
||||
|
||||
DEFINES="$DEFINES -DARM_TARGET"
|
||||
;;
|
||||
|
@ -2063,8 +2133,9 @@ case $_host_os in
|
|||
DEFINES="$DEFINES -D__PLAYSTATION2__"
|
||||
;;
|
||||
ps3)
|
||||
# Force use of SDL from the ps3 toolchain
|
||||
# Force use of SDL and freetype from the ps3 toolchain
|
||||
_sdlpath="$PS3DEV/portlibs/ppu:$PS3DEV/portlibs/ppu/bin"
|
||||
_freetypepath="$PS3DEV/portlibs/ppu:$PS3DEV/portlibs/ppu/bin"
|
||||
|
||||
DEFINES="$DEFINES -DPLAYSTATION3"
|
||||
CXXFLAGS="$CXXFLAGS -mcpu=cell -mminimal-toc -I$PSL1GHT/ppu/include -I$PS3DEV/portlibs/ppu/include"
|
||||
|
@ -3908,6 +3979,9 @@ sh -c "
|
|||
fi" 2>/dev/null &
|
||||
|
||||
for engine in $_engines; do
|
||||
# Check whether all dependencies are available
|
||||
check_engine_deps $engine
|
||||
|
||||
if test "`get_engine_sub $engine`" = "no" ; then
|
||||
# It's a main engine
|
||||
if test `get_engine_build $engine` = no ; then
|
||||
|
|
|
@ -28,6 +28,9 @@
|
|||
#define LIBS_DEFINE "RESIDUALVM_LIBS" // Name of the include environment variable
|
||||
#define REVISION_DEFINE "SCUMMVM_INTERNAL_REVISION"
|
||||
|
||||
#define ENABLE_LANGUAGE_EXTENSIONS "" // Comma separated list of projects that need language extensions
|
||||
#define DISABLE_EDIT_AND_CONTINUE "grim,myst3" // Comma separated list of projects that need Edit&Continue to be disabled for co-routine support (the main project is automatically added)
|
||||
|
||||
#define ADDITIONAL_LIBRARY "glu32"
|
||||
#define NEEDS_RTTI 0
|
||||
|
||||
|
|
|
@ -97,30 +97,6 @@ struct FSNode {
|
|||
};
|
||||
|
||||
typedef std::list<FSNode> FileList;
|
||||
|
||||
typedef StringList TokenList;
|
||||
|
||||
/**
|
||||
* Takes a given input line and creates a list of tokens out of it.
|
||||
*
|
||||
* A token in this context is separated by whitespaces. A special case
|
||||
* are quotation marks though. A string inside quotation marks is treated
|
||||
* as single token, even when it contains whitespaces.
|
||||
*
|
||||
* Thus for example the input:
|
||||
* foo bar "1 2 3 4" ScummVM
|
||||
* will create a list with the following entries:
|
||||
* "foo", "bar", "1 2 3 4", "ScummVM"
|
||||
* As you can see the quotation marks will get *removed* too.
|
||||
*
|
||||
* You can also use this with non-whitespace by passing another separator
|
||||
* character (e.g. ',').
|
||||
*
|
||||
* @param input The text to be tokenized.
|
||||
* @param separator The token separator.
|
||||
* @return A list of tokens.
|
||||
*/
|
||||
TokenList tokenize(const std::string &input, char separator = ' ');
|
||||
} // End of anonymous namespace
|
||||
|
||||
enum ProjectType {
|
||||
|
@ -787,6 +763,7 @@ bool parseEngine(const std::string &line, EngineDesc &engine) {
|
|||
|
||||
return true;
|
||||
}
|
||||
} // End of anonymous namespace
|
||||
|
||||
TokenList tokenize(const std::string &input, char separator) {
|
||||
TokenList result;
|
||||
|
|
|
@ -31,6 +31,30 @@
|
|||
|
||||
typedef std::list<std::string> StringList;
|
||||
|
||||
typedef StringList TokenList;
|
||||
|
||||
/**
|
||||
* Takes a given input line and creates a list of tokens out of it.
|
||||
*
|
||||
* A token in this context is separated by whitespaces. A special case
|
||||
* are quotation marks though. A string inside quotation marks is treated
|
||||
* as single token, even when it contains whitespaces.
|
||||
*
|
||||
* Thus for example the input:
|
||||
* foo bar "1 2 3 4" ScummVM
|
||||
* will create a list with the following entries:
|
||||
* "foo", "bar", "1 2 3 4", "ScummVM"
|
||||
* As you can see the quotation marks will get *removed* too.
|
||||
*
|
||||
* You can also use this with non-whitespace by passing another separator
|
||||
* character (e.g. ',').
|
||||
*
|
||||
* @param input The text to be tokenized.
|
||||
* @param separator The token separator.
|
||||
* @return A list of tokens.
|
||||
*/
|
||||
TokenList tokenize(const std::string &input, char separator = ' ');
|
||||
|
||||
/**
|
||||
* Structure to describe a game engine to be built into ScummVM.
|
||||
*
|
||||
|
|
|
@ -241,9 +241,11 @@ void MSBuildProvider::outputProjectSettings(std::ofstream &project, const std::s
|
|||
|
||||
// Check for project-specific warnings:
|
||||
std::map<std::string, StringList>::iterator warningsIterator = _projectWarnings.find(name);
|
||||
bool enableLanguageExtensions = find(_enableLanguageExtensions.begin(), _enableLanguageExtensions.end(), name) != _enableLanguageExtensions.end();
|
||||
bool disableEditAndContinue = find(_disableEditAndContinue.begin(), _disableEditAndContinue.end(), name) != _disableEditAndContinue.end();
|
||||
|
||||
// Nothing to add here, move along!
|
||||
if (!setup.devTools && name != setup.projectName && name != "sword25" && name != "tinsel" && name != "grim" && name != "myst3" && warningsIterator == _projectWarnings.end())
|
||||
if (!setup.devTools && name != setup.projectName && !enableLanguageExtensions && !disableEditAndContinue && warningsIterator == _projectWarnings.end())
|
||||
return;
|
||||
|
||||
std::string warnings = "";
|
||||
|
@ -254,16 +256,17 @@ void MSBuildProvider::outputProjectSettings(std::ofstream &project, const std::s
|
|||
project << "\t<ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='" << configuration << "|" << (isWin32 ? "Win32" : "x64") << "'\">\n"
|
||||
"\t\t<ClCompile>\n";
|
||||
|
||||
// Compile configuration
|
||||
if (setup.devTools || name == setup.projectName || name == "sword25" || name == "grim" || name == "myst3") {
|
||||
// Language Extensions
|
||||
if (setup.devTools || name == setup.projectName || enableLanguageExtensions)
|
||||
project << "\t\t\t<DisableLanguageExtensions>false</DisableLanguageExtensions>\n";
|
||||
|
||||
if (name == setup.projectName && !isRelease)
|
||||
// Edit and Continue
|
||||
if ((name == setup.projectName || disableEditAndContinue) && !isRelease)
|
||||
project << "\t\t\t<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n";
|
||||
} else {
|
||||
|
||||
// Warnings
|
||||
if (warningsIterator != _projectWarnings.end())
|
||||
project << "\t\t\t<DisableSpecificWarnings>" << warnings << ";%(DisableSpecificWarnings)</DisableSpecificWarnings>\n";
|
||||
}
|
||||
|
||||
project << "\t\t</ClCompile>\n";
|
||||
|
||||
|
|
|
@ -33,6 +33,9 @@ namespace CreateProjectTool {
|
|||
//////////////////////////////////////////////////////////////////////////
|
||||
MSVCProvider::MSVCProvider(StringList &global_warnings, std::map<std::string, StringList> &project_warnings, const int version)
|
||||
: ProjectProvider(global_warnings, project_warnings, version) {
|
||||
|
||||
_enableLanguageExtensions = tokenize(ENABLE_LANGUAGE_EXTENSIONS, ',');
|
||||
_disableEditAndContinue = tokenize(DISABLE_EDIT_AND_CONTINUE, ',');
|
||||
}
|
||||
|
||||
void MSVCProvider::createWorkspace(const BuildSetup &setup) {
|
||||
|
@ -139,7 +142,7 @@ void MSVCProvider::createGlobalProp(const BuildSetup &setup) {
|
|||
StringList x64EngineDefines = getEngineDefines(setup.engines);
|
||||
x64Defines.splice(x64Defines.end(), x64EngineDefines);
|
||||
|
||||
// HACK: This definitly should not be here, but otherwise we would not define SDL_BACKEND for x64.
|
||||
// HACK: This definitely should not be here, but otherwise we would not define SDL_BACKEND for x64.
|
||||
x64Defines.push_back("WIN32");
|
||||
x64Defines.push_back("SDL_BACKEND");
|
||||
|
||||
|
|
|
@ -32,6 +32,8 @@ public:
|
|||
MSVCProvider(StringList &global_warnings, std::map<std::string, StringList> &project_warnings, const int version);
|
||||
|
||||
protected:
|
||||
StringList _enableLanguageExtensions;
|
||||
StringList _disableEditAndContinue;
|
||||
|
||||
void createWorkspace(const BuildSetup &setup);
|
||||
|
||||
|
|
|
@ -103,6 +103,9 @@ void VisualStudioProvider::createProjectFile(const std::string &name, const std:
|
|||
outputConfiguration(project, setup, libraries, "Release", "x64", "64", false);
|
||||
|
||||
} else {
|
||||
bool enableLanguageExtensions = find(_enableLanguageExtensions.begin(), _enableLanguageExtensions.end(), name) != _enableLanguageExtensions.end();
|
||||
bool disableEditAndContinue = find(_disableEditAndContinue.begin(), _disableEditAndContinue.end(), name) != _disableEditAndContinue.end();
|
||||
|
||||
std::string warnings = "";
|
||||
if (warningsIterator != _projectWarnings.end())
|
||||
for (StringList::const_iterator i = warningsIterator->second.begin(); i != warningsIterator->second.end(); ++i)
|
||||
|
@ -110,10 +113,8 @@ void VisualStudioProvider::createProjectFile(const std::string &name, const std:
|
|||
|
||||
std::string toolConfig;
|
||||
toolConfig = (!warnings.empty() ? "DisableSpecificWarnings=\"" + warnings + "\"" : "");
|
||||
toolConfig += (name == setup.projectName ? "DebugInformationFormat=\"3\" " : "");
|
||||
toolConfig += (name == "sword25" ? "DisableLanguageExtensions=\"false\" " : "");
|
||||
toolConfig += (name == "grim" ? "DisableLanguageExtensions=\"false\" " : "");
|
||||
toolConfig += (name == "myst3" ? "DisableLanguageExtensions=\"false\" " : "");
|
||||
toolConfig += (disableEditAndContinue ? "DebugInformationFormat=\"3\" " : "");
|
||||
toolConfig += (enableLanguageExtensions ? "DisableLanguageExtensions=\"false\" " : "");
|
||||
|
||||
// Win32
|
||||
outputConfiguration(setup, project, toolConfig, "Debug", "Win32", "");
|
||||
|
|
|
@ -82,7 +82,7 @@ bool BitmapDecoder::loadStream(Common::SeekableReadStream &stream) {
|
|||
/* uint16 planes = */ stream.readUint16LE();
|
||||
uint16 bitsPerPixel = stream.readUint16LE();
|
||||
|
||||
if (bitsPerPixel != 8 && bitsPerPixel != 24) {
|
||||
if (bitsPerPixel != 8 && bitsPerPixel != 24 && bitsPerPixel != 32) {
|
||||
warning("%dbpp bitmaps not supported", bitsPerPixel);
|
||||
return false;
|
||||
}
|
||||
|
@ -119,8 +119,8 @@ bool BitmapDecoder::loadStream(Common::SeekableReadStream &stream) {
|
|||
|
||||
Graphics::PixelFormat format = Graphics::PixelFormat::createFormatCLUT8();
|
||||
|
||||
// BGRA for 24bpp
|
||||
if (bitsPerPixel == 24)
|
||||
// BGRA for 24bpp and 32 bpp
|
||||
if (bitsPerPixel == 24 || bitsPerPixel == 32)
|
||||
format = Graphics::PixelFormat(4, 8, 8, 8, 8, 8, 16, 24, 0);
|
||||
|
||||
_surface = new Graphics::Surface();
|
||||
|
@ -136,7 +136,7 @@ bool BitmapDecoder::loadStream(Common::SeekableReadStream &stream) {
|
|||
stream.read(dst + (height - i - 1) * width, width);
|
||||
stream.skip(extraDataLength);
|
||||
}
|
||||
} else {
|
||||
} else if (bitsPerPixel == 24) {
|
||||
byte *dst = (byte *)_surface->pixels + (height - 1) * _surface->pitch;
|
||||
|
||||
for (int32 i = 0; i < height; i++) {
|
||||
|
@ -150,6 +150,27 @@ bool BitmapDecoder::loadStream(Common::SeekableReadStream &stream) {
|
|||
dst += format.bytesPerPixel;
|
||||
}
|
||||
|
||||
stream.skip(extraDataLength);
|
||||
dst -= _surface->pitch * 2;
|
||||
}
|
||||
} 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();
|
||||
byte g = stream.readByte();
|
||||
byte r = stream.readByte();
|
||||
// Ignore the last byte, as in v3 it is unused
|
||||
// and should thus NOT be used as alpha.
|
||||
// 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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue