Ticket #8937: groovie.patch
File groovie.patch, 167.0 KB (added by , 16 years ago) |
---|
-
configure
89 89 add_engine cruise "Cinematique evo 2" no 90 90 add_engine drascula "Drascula: The Vampire Strikes Back" yes 91 91 add_engine gob "Gobli*ns" yes 92 add_engine groovie "Groovie" no 92 93 add_engine igor "Igor: Objective Uikokahonia" no 93 94 add_engine kyra "Legend of Kyrandia" yes 94 95 add_engine lure "Lure of the Temptress" yes -
engines/engines.mk
42 42 MODULES += engines/gob 43 43 endif 44 44 45 ifdef ENABLE_GROOVIE 46 DEFINES += -DENABLE_GROOVIE=$(ENABLE_GROOVIE) 47 MODULES += engines/groovie 48 endif 49 45 50 ifdef ENABLE_IGOR 46 51 DEFINES += -DENABLE_IGOR=$(ENABLE_IGOR) 47 52 MODULES += engines/igor -
engines/groovie/lzss.h
1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 * $URL$ 22 * $Id$ 23 * 24 */ 25 26 #include "common/stream.h" 27 28 class LzssReadStream : public Common::ReadStream { 29 private: 30 uint8 *_outLzssBufData; 31 uint32 _size; 32 uint32 _pos; 33 34 uint32 decodeLZSS(Common::ReadStream *in, uint8 lengthmask, uint8 lengthbits); 35 36 public: 37 LzssReadStream(Common::ReadStream *indata, uint8 lengthmask, uint8 lengthbits); 38 ~LzssReadStream(); 39 40 bool eos() const; 41 uint32 read(void *buf, uint32 size); 42 }; -
engines/groovie/graphics.cpp
1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 * $URL$ 22 * $Id$ 23 * 24 */ 25 26 #include "groovie/groovie.h" 27 #include "groovie/graphics.h" 28 29 namespace Groovie { 30 31 GraphicsMan::GraphicsMan(GroovieEngine *vm) : 32 _vm(vm), _changed(false), _fading(0) { 33 // Create the game surfaces 34 _foreground.create(640, 320, 1); 35 _background.create(640, 320, 1); 36 } 37 38 GraphicsMan::~GraphicsMan() { 39 // Free the game surfaces 40 _foreground.free(); 41 _background.free(); 42 } 43 44 void GraphicsMan::update() { 45 if (_fading) { 46 // Set the start time 47 uint32 time = _vm->_system->getMillis() - _fadeStartTime; 48 49 // Scale the time 50 int step = time / 4; 51 if (step > 256) { 52 step = 256; 53 } 54 55 if (_fading == 1) { 56 // Apply the fade in 57 applyFading(step); 58 } else if (_fading == 2) { 59 // Apply the fade out 60 applyFading(256 - step); 61 62 // Clear the buffer when ending the fade out 63 if (step == 256) 64 _foreground.fillRect(Common::Rect::Rect(640, 320), 0); 65 } 66 67 // Check for the end 68 if (step == 256) { 69 _fading = 0; 70 } 71 } 72 73 // Update the screen if needed and reset the status 74 if (_changed) { 75 _vm->_system->updateScreen(); 76 _changed = false; 77 } 78 } 79 80 void GraphicsMan::change() { 81 _changed = true; 82 } 83 84 void GraphicsMan::mergeFgAndBg() { 85 uint32 i; 86 byte *countf, *countb; 87 countf = (byte *)_foreground.getBasePtr(0, 0); 88 countb = (byte *)_background.getBasePtr(0, 0); 89 for (i = 640 * 320; i; i--) { 90 if (255 == *(countf)) { 91 *(countf) = *(countb); 92 } 93 countf++; 94 countb++; 95 } 96 } 97 98 99 void GraphicsMan::updateScreen(Graphics::Surface *source) { 100 _vm->_system->copyRectToScreen((byte *)source->getBasePtr(0, 0), 640, 0, 80, 640, 320); 101 change(); 102 } 103 104 bool GraphicsMan::isFading() { 105 return _fading; 106 } 107 108 void GraphicsMan::fadeIn(byte *pal) { 109 // Set the start time 110 _fadeStartTime = _vm->_system->getMillis(); 111 112 // Copy the target palette 113 for (int i = 0; i < 256; i++) { 114 _paletteFull[(i * 4) + 0] = pal[(i * 3) + 0]; 115 _paletteFull[(i * 4) + 1] = pal[(i * 3) + 1]; 116 _paletteFull[(i * 4) + 2] = pal[(i * 3) + 2]; 117 } 118 119 // Apply a black palette right now 120 applyFading(0); 121 122 // Set the current fading 123 _fading = 1; 124 } 125 126 void GraphicsMan::fadeOut() { 127 // Set the start time 128 _fadeStartTime = _vm->_system->getMillis(); 129 130 // Get the current palette 131 _vm->_system->grabPalette(_paletteFull, 0, 256); 132 133 // Set the current fading 134 _fading = 2; 135 } 136 137 void GraphicsMan::applyFading(int step) { 138 // Calculate the fade factor for the given step 139 int factorR = 256 - (256 - step) * 1; 140 if (factorR <= 0) factorR = 0; 141 int factorGB = 256 - (256 - step) * 2; 142 if (factorGB <= 0) factorGB = 0; 143 144 // Calculate the new palette 145 byte newpal[256 * 4]; 146 for (int i = 0; i < 256; i++) { 147 newpal[(i * 4) + 0] = (_paletteFull[(i * 4) + 0] * factorR) / 256; 148 newpal[(i * 4) + 1] = (_paletteFull[(i * 4) + 1] * factorGB) / 256; 149 newpal[(i * 4) + 2] = (_paletteFull[(i * 4) + 2] * factorGB) / 256; 150 } 151 152 // Set the screen palette 153 _vm->_system->setPalette(newpal, 0, 256); 154 155 // Request a screen update 156 change(); 157 } 158 159 } // End of Groovie namespace -
engines/groovie/roq.cpp
1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 * $URL$ 22 * $Id$ 23 * 24 */ 25 26 #include "groovie/groovie.h" 27 #include "groovie/jpeg.h" 28 #include "groovie/roq.h" 29 30 #include "sound/mixer.h" 31 32 namespace Groovie { 33 34 ROQPlayer::ROQPlayer(GroovieEngine *vm) : 35 VideoPlayer(vm) { 36 } 37 38 ROQPlayer::~ROQPlayer() { 39 } 40 41 uint16 ROQPlayer::loadInternal() { 42 // Begin reading the file 43 debugC(1, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::ROQ: Loading video"); 44 45 // Read the file header 46 ROQBlockHeader blockHeader; 47 if (!readBlockHeader(blockHeader)) { 48 return 0; 49 } 50 if (blockHeader.type != 0x1084 || blockHeader.size != 0 || blockHeader.param != 0) { 51 return 0; 52 } 53 54 // Hardcoded FPS 55 return 25; 56 } 57 58 bool ROQPlayer::playFrameInternal() { 59 debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::ROQ: Playing frame"); 60 61 // Process the needed blocks until the next video frame 62 bool endframe = false; 63 while (!endframe && !_file->eos()) { 64 endframe = processBlock(); 65 } 66 67 // Wait until the current frame can be shown 68 waitFrame(); 69 70 // Update the screen 71 _syst->updateScreen(); 72 73 // Return whether the video has ended 74 return _file->eos(); 75 } 76 77 bool ROQPlayer::readBlockHeader(ROQBlockHeader &blockHeader) { 78 if (_file->eos()) { 79 return false; 80 } else { 81 blockHeader.type = _file->readUint16LE(); 82 blockHeader.size = _file->readUint32LE(); 83 blockHeader.param = _file->readUint16LE(); 84 85 debugC(10, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::ROQ: Block type = 0x%02X", blockHeader.type); 86 debugC(10, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::ROQ: Block size = 0x%08X", blockHeader.size); 87 debugC(10, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::ROQ: Block param = 0x%04X", blockHeader.param); 88 89 return true; 90 } 91 } 92 93 bool ROQPlayer::processBlock() { 94 // Read the header of the block 95 ROQBlockHeader blockHeader; 96 if (!readBlockHeader(blockHeader)) { 97 return true; 98 } 99 100 bool ok = true; 101 bool endframe = false; 102 switch (blockHeader.type) { 103 case 0x1001: // Video info 104 ok = processBlockInfo(blockHeader); 105 break; 106 case 0x1002: // Quad codebook definition 107 ok = processBlockQuadCodebook(blockHeader); 108 break; 109 case 0x1011: // Quad vector quantised video frame 110 ok = processBlockQuadVector(blockHeader); 111 endframe = true; 112 break; 113 case 0x1012: // Still image (JPEG) 114 ok = processBlockStill(blockHeader); 115 endframe = true; 116 break; 117 case 0x1013: // Hang 118 //warning("Groovie::ROQ: Hang block (skipped)"); 119 break; 120 case 0x1020: // Mono sound samples 121 ok = processBlockSoundMono(blockHeader); 122 break; 123 case 0x1021: // Stereo sound samples 124 ok = processBlockSoundStereo(blockHeader); 125 break; 126 case 0x1030: // Audio container 127 ok = processBlockAudioContainer(blockHeader); 128 break; 129 default: 130 error("Groovie::ROQ: Unknown block type: 0x%04X", blockHeader.type); 131 ok = false; 132 } 133 134 // End the frame when the graphics have been modified or when there's an error 135 return endframe || !ok; 136 } 137 138 bool ROQPlayer::processBlockInfo(ROQBlockHeader &blockHeader) { 139 debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::ROQ: Processing info block"); 140 141 // Verify the block header 142 if (blockHeader.type != 0x1001 || blockHeader.size != 8 || blockHeader.param != 0) { 143 return false; 144 } 145 146 uint16 tmp; 147 tmp = _file->readUint16LE(); 148 printf("w = %d\n", tmp); 149 if (tmp != 640) { 150 return false; 151 } 152 tmp = _file->readUint16LE(); 153 printf("h = %d\n", tmp); 154 if (tmp != 320) { 155 return false; 156 } 157 tmp = _file->readUint16LE(); 158 printf("unk1 = %d\n", tmp); 159 if (tmp != 8) { 160 return false; 161 } 162 tmp = _file->readUint16LE(); 163 printf("unk2 = %d\n", tmp); 164 if (tmp != 4) { 165 return false; 166 } 167 return true; 168 } 169 170 bool ROQPlayer::processBlockQuadCodebook(ROQBlockHeader &blockHeader) { 171 debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::ROQ: Processing quad codebook block"); 172 173 // Get the number of 2x2 pixel blocks 174 _num2blocks = blockHeader.param >> 8; 175 if (_num2blocks == 0) { 176 _num2blocks = 256; 177 } 178 179 // Get the number of 4x4 pixel blocks 180 _num4blocks = blockHeader.param & 0xFF; 181 if (_num4blocks == 0 && (blockHeader.size > (uint32)_num2blocks * 6)) { 182 _num4blocks = 256; 183 } 184 185 _file->skip(_num2blocks * 6); 186 _file->skip(_num4blocks * 4); 187 188 return true; 189 } 190 191 bool ROQPlayer::processBlockQuadVector(ROQBlockHeader &blockHeader) { 192 debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::ROQ: Processing quad vector block"); 193 _file->skip(blockHeader.size); 194 return true; 195 196 // Get the mean motion vectors 197 byte Mx = blockHeader.param >> 8; 198 byte My = blockHeader.param & 0xFF; 199 200 int32 ends =_file->pos() + blockHeader.size; 201 int numblocks = (640 / 8) * (320 / 8); 202 for (int j = 0; j < numblocks && ends > _file->pos(); j++) { 203 printf("doing block %d/%d\n", j, numblocks); 204 uint16 codingType = _file->readUint16LE(); 205 for (int i = 0; i < 8; i++) { 206 switch (codingType >> 14) { 207 case 0: // MOT: Skip block 208 //printf("coding type 0\n"); 209 break; 210 case 1: { // FCC: Copy an existing block 211 //printf("coding type 1\n"); 212 byte argument = _file->readByte(); 213 byte Dx = Mx + (argument >> 4); 214 byte Dy = My + (argument & 0x0F); 215 // Dx = X + 8 - (argument >> 4) - Mx 216 // Dy = Y + 8 - (argument & 0x0F) - My 217 break; 218 } 219 case 2: { // SLD: Quad vector quantisation 220 //printf("coding type 2\n"); 221 byte argument = _file->readByte(); 222 if (argument > _num4blocks) { 223 //error("invalid 4x4 block %d of %d", argument, _num4blocks); 224 } 225 // Upsample the 4x4 pixel block 226 break; 227 } 228 case 3: // CCC: 229 //printf("coding type 3:\n"); 230 processBlockQuadVectorSub(blockHeader); 231 break; 232 } 233 codingType <<= 2; 234 } 235 } 236 printf("Should have ended at %d, and has ended at %d\n", ends, _file->pos()); 237 return true; 238 } 239 240 bool ROQPlayer::processBlockQuadVectorSub(ROQBlockHeader &blockHeader) { 241 debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::ROQ: Processing quad vector sub block"); 242 243 // Get the mean motion vectors 244 byte Mx = blockHeader.param >> 8; 245 byte My = blockHeader.param & 0xFF; 246 247 uint16 codingType = _file->readUint16LE(); 248 for (int i = 0; i < 4; i++) { 249 switch (codingType >> 14) { 250 case 0: // MOT: Skip block 251 //printf("coding type 0\n"); 252 break; 253 case 1: { // FCC: Copy an existing block 254 //printf("coding type 1\n"); 255 byte argument = _file->readByte(); 256 byte Dx = Mx + (argument >> 4); 257 byte Dy = My + (argument & 0x0F); 258 // Dx = X + 8 - (argument >> 4) - Mx 259 // Dy = Y + 8 - (argument & 0x0F) - My 260 break; 261 } 262 case 2: { // SLD: Quad vector quantisation 263 //printf("coding type 2\n"); 264 byte argument = _file->readByte(); 265 if (argument > _num2blocks) { 266 //error("invalid 2x2 block: %d of %d", argument, _num2blocks); 267 } 268 break; 269 } 270 case 3: 271 //printf("coding type 3\n"); 272 _file->readByte(); 273 _file->readByte(); 274 _file->readByte(); 275 _file->readByte(); 276 break; 277 } 278 codingType <<= 2; 279 } 280 return true; 281 } 282 283 bool ROQPlayer::processBlockStill(ROQBlockHeader &blockHeader) { 284 debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::ROQ: Processing still (JPEG) block"); 285 Common::ReadStream *jpegData = new Common::SubReadStream(_file, blockHeader.size); 286 JPEG jpegFrame; 287 jpegFrame.read(jpegData); 288 /* 289 Common::File save; 290 save.open("dump.jpg", Common::File::kFileWriteMode); 291 save.write(data, blockHeader.size); 292 save.close(); 293 */ 294 error("JPEG!"); 295 return true; 296 } 297 298 bool ROQPlayer::processBlockSoundMono(ROQBlockHeader &blockHeader) { 299 debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::ROQ: Processing mono sound block"); 300 301 // Verify the block header 302 if (blockHeader.type != 0x1020) { 303 return false; 304 } 305 306 // Initialize the audio stream if needed 307 if (!_audioStream) { 308 byte flags = Audio::Mixer::FLAG_16BITS | Audio::Mixer::FLAG_AUTOFREE; 309 #ifdef SCUMM_LITTLE_ENDIAN 310 flags |= Audio::Mixer::FLAG_LITTLE_ENDIAN; 311 #endif 312 _audioStream = Audio::makeAppendableAudioStream(22050, flags); 313 Audio::SoundHandle sound_handle; 314 ::g_engine->_mixer->playInputStream(Audio::Mixer::kPlainSoundType, &sound_handle, _audioStream); 315 } 316 317 // Create the audio buffer 318 int16 *buffer = new int16[blockHeader.size]; 319 320 // Initialize the prediction with the block parameter 321 int16 prediction = blockHeader.param ^ 0x8000; 322 323 // Process the data 324 for (uint16 i = 0; i < blockHeader.size; i++) { 325 int16 data = _file->readByte(); 326 if (data < 0x80) { 327 prediction += data * data; 328 } else { 329 data -= 0x80; 330 prediction -= data * data; 331 } 332 buffer[i] = prediction; 333 } 334 335 // Queue the read buffer 336 _audioStream->queueBuffer((byte *)buffer, blockHeader.size * 2); 337 338 return true; 339 } 340 341 bool ROQPlayer::processBlockSoundStereo(ROQBlockHeader &blockHeader) { 342 debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::ROQ: Processing stereo sound block"); 343 344 // Verify the block header 345 if (blockHeader.type != 0x1021) { 346 return false; 347 } 348 349 // Initialize the audio stream if needed 350 if (!_audioStream) { 351 byte flags = Audio::Mixer::FLAG_16BITS | Audio::Mixer::FLAG_AUTOFREE | Audio::Mixer::FLAG_STEREO; 352 #ifdef SCUMM_LITTLE_ENDIAN 353 flags |= Audio::Mixer::FLAG_LITTLE_ENDIAN; 354 #endif 355 _audioStream = Audio::makeAppendableAudioStream(22050, flags); 356 Audio::SoundHandle sound_handle; 357 ::g_engine->_mixer->playInputStream(Audio::Mixer::kPlainSoundType, &sound_handle, _audioStream); 358 } 359 360 // Create the audio buffer 361 int16 *buffer = new int16[blockHeader.size]; 362 363 // Initialize the prediction with the block parameter 364 int16 predictionLeft = (blockHeader.param & 0xFF00) ^ 0x8000; 365 int16 predictionRight = (blockHeader.param << 8) ^ 0x8000; 366 bool left = true; 367 368 // Process the data 369 for (uint16 i = 0; i < blockHeader.size; i++) { 370 int16 data = _file->readByte(); 371 if (left) { 372 if (data < 0x80) { 373 predictionLeft += data * data; 374 } else { 375 data -= 0x80; 376 predictionLeft -= data * data; 377 } 378 buffer[i] = predictionLeft; 379 } else { 380 if (data < 0x80) { 381 predictionRight += data * data; 382 } else { 383 data -= 0x80; 384 predictionRight -= data * data; 385 } 386 buffer[i] = predictionRight; 387 } 388 left = !left; 389 } 390 391 // Queue the read buffer 392 _audioStream->queueBuffer((byte *)buffer, blockHeader.size * 2); 393 394 return true; 395 } 396 397 bool ROQPlayer::processBlockAudioContainer(ROQBlockHeader &blockHeader) { 398 debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::ROQ: Processing audio container block: 0x%04X", blockHeader.param); 399 return true; 400 } 401 402 } // End of Groovie namespace -
engines/groovie/vdx.cpp
1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 * $URL$ 22 * $Id$ 23 * 24 */ 25 26 #include "groovie/groovie.h" 27 #include "groovie/lzss.h" 28 #include "groovie/vdx.h" 29 30 #include "sound/mixer.h" 31 32 #define TILE_SIZE 4 // Size of each tile on the image: only ever seen 4 so far 33 #define VDX_IDENT 0x9267 // 37479 34 35 namespace Groovie { 36 37 VDXPlayer::VDXPlayer(GroovieEngine *vm) : 38 VideoPlayer(vm), _origX(0), _origY(0), _flagOnePrev(false), 39 _fg(&_vm->_graphicsMan->_foreground), _bg(&_vm->_graphicsMan->_background) { 40 } 41 42 VDXPlayer::~VDXPlayer() { 43 //delete _audioStream; 44 } 45 46 void VDXPlayer::setOrigin(int16 x, int16 y) { 47 _origX = x; 48 _origY = y; 49 } 50 51 uint16 VDXPlayer::loadInternal() { 52 uint32 engine_level = kGroovieDebugVideo | kGroovieDebugAll; 53 if ((gDebugLevel == 11) || (Common::getEnabledSpecialDebugLevels() & engine_level)) { 54 int8 i; 55 debugN(1, "Groovie::VDX: New VDX: bitflags are "); 56 for (i = 11; i >= 0; i--) { 57 debugN(1, "%d", _flags & (1 << i)? 1 : 0); 58 if (i % 4 == 0) { 59 debugN(1, " "); 60 } 61 } 62 debug(1, " "); 63 } 64 // Flags: 65 // - 1 Puzzle piece? Skip palette, don't redraw full screen, draw still to b/ack buffer 66 // - 2 Transparent colour is 0xFF 67 // - 5 Skip still chunks 68 // - 7 69 // - 8 Just show the first frame 70 // - 9 Start a palette fade in 71 _flagZero = ((_flags & (1 << 0)) != 0); 72 _flagOne = ((_flags & (1 << 1)) != 0); 73 _flag2Byte = (_flags & (1 << 2)) ? 0xFF : 0x00; 74 _flagThree = ((_flags & (1 << 3)) != 0); 75 _flagFour = ((_flags & (1 << 4)) != 0); 76 _flagFive = ((_flags & (1 << 5)) != 0); 77 _flagSix = ((_flags & (1 << 6)) != 0); 78 _flagSeven = ((_flags & (1 << 7)) != 0); 79 _flagEight = ((_flags & (1 << 8)) != 0); 80 _flagNine = ((_flags & (1 << 9)) != 0); 81 82 if (_flagOnePrev && !_flagOne && !_flagEight) { 83 _flagSeven = true; 84 } 85 86 // Save _flagOne for the next video 87 _flagOnePrev = _flagOne; 88 89 //_flagTransparent = _flagOne; 90 _flagFirstFrame = _flagEight; 91 //_flagSkipPalette = _flagSeven; 92 _flagSkipPalette = false; 93 //_flagSkipStill = _flagFive || _flagSeven; 94 //_flagUpdateStill = _flagNine || _flagSix; 95 96 // Begin reading the file 97 debugC(1, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::VDX: Playing video"); 98 99 if (_file->readUint16LE() != VDX_IDENT) { 100 error("Groovie::VDX: This does not appear to be a 7th guest vxd file"); 101 return 0; 102 } else { 103 debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::VDX: VDX file identified correctly"); 104 } 105 106 uint16 tmp; 107 108 // Skip unknown data: 6 bytes, ref Martine 109 tmp = _file->readUint16LE(); 110 debugC(2, kGroovieDebugVideo | kGroovieDebugUnknown | kGroovieDebugAll, "Groovie::VDX: Martine1 = 0x%04X", tmp); 111 tmp = _file->readUint16LE(); 112 debugC(2, kGroovieDebugVideo | kGroovieDebugUnknown | kGroovieDebugAll, "Groovie::VDX: Martine2 = 0x%04X", tmp); 113 tmp = _file->readUint16LE(); 114 debugC(2, kGroovieDebugVideo | kGroovieDebugUnknown | kGroovieDebugAll, "Groovie::VDX: Martine3 (FPS?) = %d", tmp); 115 116 return tmp; 117 } 118 119 bool VDXPlayer::playFrameInternal() { 120 byte currRes = 0x80; 121 while (!_file->eos() && currRes == 0x80) { 122 currRes = _file->readByte(); 123 124 // Skip unknown data: 1 byte, ref Edward 125 byte tmp = _file->readByte(); 126 debugC(5, kGroovieDebugVideo | kGroovieDebugUnknown | kGroovieDebugAll, "Groovie::VDX: Edward = 0x%04X", tmp); 127 128 uint32 compSize = _file->readUint32LE(); 129 uint8 lengthmask = _file->readByte(); 130 uint8 lengthbits = _file->readByte(); 131 132 // Read the chunk data and decompress if needed 133 Common::ReadStream *vdxData = new Common::SubReadStream(_file, compSize); 134 if (lengthmask && lengthbits) { 135 Common::ReadStream *decompData = new LzssReadStream(vdxData, lengthmask, lengthbits); 136 delete vdxData; 137 vdxData = decompData; 138 } 139 140 // Use the current chunk 141 switch (currRes) { 142 case 0x00: 143 debugC(6, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::VDX: Replay frame"); 144 break; 145 case 0x20: 146 debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::VDX: Still frame"); 147 getStill(vdxData); 148 break; 149 case 0x25: 150 debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::VDX: Animation frame"); 151 getDelta(vdxData); 152 break; 153 case 0x80: 154 debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::VDX: Sound resource"); 155 chunkSound(vdxData); 156 break; 157 default: 158 error("Groovie::VDX: Invalid resource type: %d", currRes); 159 } 160 delete vdxData; 161 } 162 163 // Wait until the current frame can be shown 164 waitFrame(); 165 166 // TODO: Move it to a better place 167 // Update the screen 168 if (currRes == 0x25) { 169 //if (_flagSeven) { 170 //_vm->_graphicsMan->mergeFgAndBg(); 171 //} 172 _vm->_graphicsMan->updateScreen(_bg); 173 } 174 175 // Report the end of the video if we reached the end of the file or if we 176 // just wanted to play one frame. 177 return _file->eos() || _flagFirstFrame; 178 } 179 180 static const uint16 vdxBlockMapLookup[] = { 181 0xc800, 0xec80, 0xfec8, 0xffec, 0xfffe, 0x3100, 0x7310, 0xf731, 0xff73, 0xfff7, 0x6c80, 0x36c8, 0x136c, 0x6310, 0xc631, 0x8c63, 182 0xf000, 0xff00, 0xfff0, 0x1111, 0x3333, 0x7777, 0x6666, 0xcccc, 0x0ff0, 0x00ff, 0xffcc, 0x0076, 0xff33, 0x0ee6, 0xccff, 0x6770, 183 0x33ff, 0x6ee0, 0x4800, 0x2480, 0x1248, 0x0024, 0x0012, 0x2100, 0x4210, 0x8421, 0x0042, 0x0084, 0xf888, 0x0044, 0x0032, 0x111f, 184 0x22e0, 0x4c00, 0x888f, 0x4470, 0x2300, 0xf111, 0x0e22, 0x00c4, 0xf33f, 0xfccf, 0xff99, 0x99ff, 0x4444, 0x2222, 0xccee, 0x7733, 185 0x00f8, 0x00f1, 0x00bb, 0x0cdd, 0x0f0f, 0x0f88, 0x13f1, 0x19b3, 0x1f80, 0x226f, 0x27ec, 0x3077, 0x3267, 0x37e4, 0x38e3, 0x3f90, 186 0x44cf, 0x4cd9, 0x4c99, 0x5555, 0x603f, 0x6077, 0x6237, 0x64c9, 0x64cd, 0x6cd9, 0x70ef, 0x0f00, 0x00f0, 0x0000, 0x4444, 0x2222 187 }; 188 189 void VDXPlayer::getDelta(Common::ReadStream *in) { 190 uint16 j, k, l; 191 uint32 offset; 192 uint8 currOpCode, param1, param2, param3; 193 194 // Get the size of the local palette 195 j = in->readUint16LE(); 196 197 // Load the palette if it isn't empty 198 if (j) { 199 uint16 palBitField[16]; 200 int flag = 1, palIndex; 201 202 // Load the bit field 203 for (l = 0; l < 16; l++) { 204 palBitField[l] = in->readUint16LE(); 205 } 206 207 // Load the actual palette 208 for (l = 0; l < 16; l++) { 209 flag = 1 << 15; 210 for (j = 0; j < 16; j++) { 211 palIndex = (l * 16) + j; 212 213 if (flag & palBitField[l]) { 214 for (k = 0; k < 3; k++) { 215 _palBuf[(palIndex * 3) + k] = in->readByte(); 216 } 217 } 218 flag = flag >> 1; 219 } 220 } 221 222 // Apply the palette 223 if (!_flagSix && !_flagSeven) { 224 setPalette(_palBuf); 225 } 226 } 227 currOpCode = in->readByte(); 228 229 /* j now becomes the current block line we're dealing with */ 230 j = 0; 231 offset = 0; 232 while (!in->eos()) { 233 byte colours[16]; 234 if (currOpCode < 0x60) { 235 param1 = in->readByte(); 236 param2 = in->readByte(); 237 expandColourMap(colours, vdxBlockMapLookup[currOpCode], param1, param2); 238 decodeBlockDelta(offset, colours, 640); 239 offset += TILE_SIZE; 240 } else if (currOpCode > 0x7f) { 241 param1 = in->readByte(); 242 param2 = in->readByte(); 243 param3 = in->readByte(); 244 expandColourMap(colours, (param1 << 8) + currOpCode, param2, param3); 245 decodeBlockDelta(offset, colours, 640); 246 offset += TILE_SIZE; 247 } else switch (currOpCode) { 248 case 0x60: /* Fill tile with the 16 colours given as parameters */ 249 for (l = 0; l < 16; l++) { 250 colours[l] = in->readByte(); 251 } 252 decodeBlockDelta(offset, colours, 640); 253 offset += TILE_SIZE; 254 break; 255 case 0x61: /* Skip to the end of this line, next block is start of next */ 256 /* Note this is used at the end of EVERY line */ 257 j++; 258 offset = j * TILE_SIZE * 640; 259 break; 260 case 0x62: 261 case 0x63: 262 case 0x64: 263 case 0x65: 264 case 0x66: 265 case 0x67: 266 case 0x68: 267 case 0x69: 268 case 0x6a: 269 case 0x6b: /* Skip next param1 blocks (within line) */ 270 offset += (currOpCode - 0x62) * TILE_SIZE; 271 break; 272 case 0x6c: 273 case 0x6d: 274 case 0x6e: 275 case 0x6f: 276 case 0x70: 277 case 0x71: 278 case 0x72: 279 case 0x73: 280 case 0x74: 281 case 0x75: /* Next param1 blocks are filled with colour param2 */ 282 param1 = currOpCode - 0x6b; 283 param2 = in->readByte(); 284 for (l = 0; l < 16; l++) { 285 colours[l] = param2; 286 } 287 for (k = 0; k < param1; k++) { 288 decodeBlockDelta(offset, colours, 640); 289 offset += TILE_SIZE; 290 } 291 break; 292 case 0x76: 293 case 0x77: 294 case 0x78: 295 case 0x79: 296 case 0x7a: 297 case 0x7b: 298 case 0x7c: 299 case 0x7d: 300 case 0x7e: 301 case 0x7f: /* Next bytes contain colours to fill the next param1 blocks in the current line*/ 302 param1 = currOpCode - 0x75; 303 for (k = 0; k < param1; k++) { 304 param2 = in->readByte(); 305 for (l = 0; l < 16; l++) { 306 colours[l] = param2; 307 } 308 decodeBlockDelta(offset, colours, 640); 309 offset += TILE_SIZE; 310 } 311 break; 312 default: 313 error("Groovie::VDX: Broken somehow"); 314 } 315 currOpCode = in->readByte(); 316 } 317 } 318 319 void VDXPlayer::getStill(Common::ReadStream *in) { 320 uint16 numXTiles = in->readUint16LE(); 321 debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::VDX: numXTiles=%d", numXTiles); 322 uint16 numYTiles = in->readUint16LE(); 323 debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::VDX: numYTiles=%d", numYTiles); 324 325 // It's skipped in the original: 326 uint16 colourDepth = in->readUint16LE(); 327 debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::VDX: colourDepth=%d", colourDepth); 328 329 uint16 imageWidth = TILE_SIZE * numXTiles; 330 331 uint8 mask = 0; 332 byte *buf; 333 if (_flagOne) { 334 // Paint to the foreground 335 buf = (byte *)_fg->getBasePtr(0, 0); 336 if (_flag2Byte) { 337 mask = 0xff; 338 } else { 339 mask = 0; 340 } 341 342 // TODO: Verify this is the right procedure. Couldn't find it on the 343 // disassembly, but it's required to work properly 344 _flagFirstFrame = true; 345 } else { 346 // Paint to the background 347 buf = (byte *)_bg->getBasePtr(0, 0); 348 } 349 350 // Read the palette 351 in->read(_palBuf, 3 * 256); 352 353 if (_flagSeven) { 354 _flagFive = true; 355 } 356 357 // Skip the frame when flag 5 is set, unless flag 1 is set 358 if (!_flagFive || _flagOne) { 359 360 byte colours[16]; 361 for (uint16 j = 0; j < numYTiles; j++) { 362 for (uint16 i = 0; i < numXTiles; i++) { /* Tile number */ 363 uint8 colour1 = in->readByte(); 364 uint8 colour0 = in->readByte(); 365 uint16 colourMap = in->readUint16LE(); 366 expandColourMap(colours, colourMap, colour1, colour0); 367 decodeBlockStill(buf + j * TILE_SIZE * imageWidth + i * TILE_SIZE, colours, 640, mask); 368 } 369 } 370 371 // Apply the palette 372 if (_flagNine) { 373 // Flag 9 starts a fade in 374 fadeIn(_palBuf); 375 } else { 376 if (!_flagOne && !_flagSeven) { 377 // Actually apply the palette 378 setPalette(_palBuf); 379 } 380 } 381 382 if (!_flagOne) { 383 _vm->_graphicsMan->updateScreen(_bg); 384 } 385 /* 386 if (_flagSix) { 387 if (_flagOne) { 388 _vm->_graphicsMan->updateScreen(_fg); 389 } else { 390 _vm->_graphicsMan->updateScreen(_bg); 391 } 392 _flagSix = 0; 393 } 394 */ 395 } else { 396 // Skip the remaining data 397 debugC(10, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::VDX: Skipping still frame"); 398 while (!in->eos()) { 399 in->readByte(); 400 } 401 } 402 } 403 404 void VDXPlayer::expandColourMap(byte *out, uint16 colourMap, uint8 colour1, uint8 colour0) { 405 int flag = 1 << 15; 406 for (int i = 0; i < 16; i++) { 407 // Set the corresponding colour 408 out[i] = (colourMap & flag) ? colour1 : colour0; 409 410 // Update the flag to test the next colour 411 flag >>= 1; 412 } 413 } 414 415 void VDXPlayer::decodeBlockStill(byte *buf, byte *colours, uint16 imageWidth, uint8 mask) { 416 for (int y = 0; y < TILE_SIZE; y++) { 417 for (int x = 0; x < TILE_SIZE; x++) { 418 if (_flagOne) { 419 // 0xff pixels don't modify the buffer 420 if (*colours != 0xff) { 421 // Write the colour 422 *buf = *colours | mask; 423 // Note: if the mask is 0, it paints the image 424 // else, it paints the image's mask using 0xff 425 } 426 } else { 427 *buf = *colours; 428 } 429 430 // Point to the next colour 431 colours++; 432 433 // Point to the next pixel 434 buf++; 435 } 436 437 // Point to the start of the next line 438 buf += imageWidth - TILE_SIZE; 439 } 440 } 441 442 void VDXPlayer::decodeBlockDelta(uint32 offset, byte *colours, uint16 imageWidth) { 443 byte *fgBuf = (byte *)_fg->getBasePtr(0, 0) + offset; 444 //byte *bgBuf = (byte *)_bg->getBasePtr(0, 0) + offset; 445 446 byte *dest; 447 // TODO: Verify just the else block is required 448 //if (_flagOne) { 449 // Paint to the foreground 450 //dest = (byte *)_fg->getBasePtr(0, 0) + offset; 451 //} else { 452 dest = (byte *)_bg->getBasePtr(0, 0) + offset; 453 //} 454 455 int32 off = _origX + _origY * imageWidth; 456 for (int y = 0; y < TILE_SIZE; y++) { 457 for (int x = 0; x < TILE_SIZE; x++) { 458 if (_flagSeven) { 459 if (fgBuf[off] != 0xff) { 460 if (*colours == 0xff) { 461 dest[off] = fgBuf[off]; 462 } else { 463 dest[off] = *colours; 464 } 465 } 466 } else { 467 // Paint directly 468 dest[off] = *colours; 469 } 470 colours++; 471 off++; 472 } 473 474 // Prepare the offset of the next line 475 off += imageWidth - TILE_SIZE; 476 } 477 } 478 479 void VDXPlayer::chunkSound(Common::ReadStream *in) { 480 if (!_audioStream) { 481 _audioStream = Audio::makeAppendableAudioStream(22050, Audio::Mixer::FLAG_UNSIGNED | Audio::Mixer::FLAG_AUTOFREE); 482 Audio::SoundHandle sound_handle; 483 ::g_engine->_mixer->playInputStream(Audio::Mixer::kPlainSoundType, &sound_handle, _audioStream); 484 } 485 486 byte *data = new byte[60000]; 487 int chunksize = in->read(data, 60000); 488 _audioStream->queueBuffer(data, chunksize); 489 } 490 491 void VDXPlayer::fadeIn(uint8 *targetpal) { 492 // Don't do anything if we're asked to skip palette changes 493 if (_flagSkipPalette) 494 return; 495 496 // TODO: Is it required? If so, move to an appropiate place 497 // Copy the foreground to the background 498 memcpy((byte *)_vm->_graphicsMan->_foreground.getBasePtr(0, 0), (byte *)_vm->_graphicsMan->_background.getBasePtr(0, 0), 640 * 320); 499 500 // Start a fadein 501 _vm->_graphicsMan->fadeIn(targetpal); 502 503 // Show the background 504 _vm->_graphicsMan->updateScreen(_bg); 505 } 506 507 void VDXPlayer::setPalette(uint8 *palette) { 508 if (_flagSkipPalette) 509 return; 510 511 uint8 palBuf[4 * 256]; 512 debugC(7, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::VDX: Setting palette"); 513 for (int i = 0; i < 256; i++) { 514 palBuf[(i * 4) + 0] = palette[(i * 3) + 0]; 515 palBuf[(i * 4) + 1] = palette[(i * 3) + 1]; 516 palBuf[(i * 4) + 2] = palette[(i * 3) + 2]; 517 palBuf[(i * 4) + 3] = 0; 518 } 519 _syst->setPalette(palBuf, 0, 256); 520 } 521 522 } // End of Groovie namespace -
engines/groovie/player.h
1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 * $URL$ 22 * $Id$ 23 * 24 */ 25 26 #ifndef GROOVIE_PLAYER_H 27 #define GROOVIE_PLAYER_H 28 29 #include "common/system.h" 30 #include "sound/audiostream.h" 31 32 namespace Groovie { 33 34 class GroovieEngine; 35 36 class VideoPlayer { 37 public: 38 VideoPlayer(GroovieEngine *vm); 39 virtual ~VideoPlayer() {} 40 41 bool load(Common::SeekableReadStream *file, uint16 flags); 42 bool playFrame(); 43 virtual void setOrigin(int16 x, int16 y) {}; 44 45 protected: 46 // To be implemented by subclasses 47 virtual uint16 loadInternal() = 0; 48 virtual bool playFrameInternal() = 0; 49 50 GroovieEngine *_vm; 51 OSystem *_syst; 52 Common::SeekableReadStream *_file; 53 uint16 _flags; 54 Audio::AppendableAudioStream *_audioStream; 55 56 private: 57 // Synchronization stuff 58 bool _begunPlaying; 59 uint16 _millisBetweenFrames; 60 uint32 _lastFrameTime; 61 62 protected: 63 void waitFrame(); 64 }; 65 66 } // End of Groovie namespace 67 68 #endif // GROOVIE_PLAYER_H -
engines/groovie/script.cpp
1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 * $URL$ 22 * $Id$ 23 * 24 */ 25 26 #include "groovie/debug.h" 27 #include "groovie/music.h" 28 #include "groovie/script.h" 29 #include "groovie/groovie.h" 30 31 #include "common/config-manager.h" 32 #include "common/endian.h" 33 #include "common/events.h" 34 #include "common/savefile.h" 35 #include "sound/audiocd.h" 36 37 #define NUM_OPCODES 90 38 39 namespace Groovie { 40 41 void debugScript(int level, bool nl, const char *s, ...) { 42 char buf[STRINGBUFLEN]; 43 va_list va; 44 45 uint32 engine_level = kGroovieDebugScript | kGroovieDebugAll; 46 if (gDebugLevel != 11) 47 if (!(Common::getEnabledSpecialDebugLevels() & engine_level)) 48 return; 49 50 va_start(va, s); 51 vsnprintf(buf, STRINGBUFLEN, s, va); 52 va_end(va); 53 54 if (nl) 55 debug(level, buf); 56 else 57 debugN(level, buf); 58 } 59 60 Script::Script(GroovieEngine *vm) : 61 _code(NULL), _savedCode(NULL), _stacktop(0), 62 _debugger(NULL), _error(false), _vm(vm), 63 _videoFile(NULL), _videoRef(0), _font(NULL) { 64 // Initialize the random source 65 _vm->_system->getEventManager()->registerRandomSource(_random, "GroovieScripts"); 66 67 // Prepare the variables 68 _bitflags = 0; 69 for (int i = 0; i < 0x400; i++) { 70 _variables[i] = 0; 71 } 72 73 // Initialize the music type variable 74 int midiDriver = MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB | MDT_PREFER_MIDI); 75 if (midiDriver == MD_ADLIB) { 76 // MIDI through AdLib 77 _variables[0x100] = 0; 78 } else if ((midiDriver == MD_MT32) || ConfMan.getBool("native_mt32")) { 79 // MT-32 80 _variables[0x100] = 2; 81 } else { 82 // GM 83 _variables[0x100] = 1; 84 } 85 86 _hotspotTopAction = 0; 87 _hotspotBottomAction = 0; 88 _hotspotRightAction = 0; 89 _hotspotLeftAction = 0; 90 _hotspotCursorOldX = 1000; 91 _hotspotCursorOldY = 1000; 92 } 93 94 Script::~Script() { 95 delete[] _code; 96 delete[] _savedCode; 97 98 delete _font; 99 delete _videoFile; 100 } 101 102 void Script::setDebugger(Debugger *debugger) { 103 _debugger = debugger; 104 } 105 106 bool Script::loadScript(Common::String filename) { 107 // Try to open the script file 108 Common::File scriptfile; 109 if (!scriptfile.open(filename)) { 110 return false; 111 } 112 113 // Save the script filename 114 _scriptFile = filename; 115 116 // Load the code 117 _code = new byte[0x10000]; 118 scriptfile.read(_code, 0x10000); 119 scriptfile.close(); 120 121 // Initialize the script 122 _currentInstruction = 0; 123 124 return true; 125 } 126 127 void Script::directGameLoad(int slot) { 128 // Reject invalid slots 129 if (slot < 0 || slot > 9) { 130 return; 131 } 132 133 // TODO: Return to the main script, likely reusing most of o_returnscript() 134 135 // HACK: We set variable 0x19 to the slot to load, and set the current 136 // instruction to the one that actually loads the saved game specified 137 // in that variable. This will change in other versions of the game and 138 // in other games. 139 _variables[0x19] = slot; 140 _currentInstruction = 0x287; 141 142 // TODO: We'll probably need to start by running the beginning of the 143 // script to let it do the soundcard initialization and then do the 144 // actual loading. 145 } 146 147 void Script::step() { 148 // Reset the error status 149 _error = false; 150 151 // Prepare the base debug string 152 char debugstring[10]; 153 sprintf(debugstring, "@0x%04X: ", _currentInstruction); 154 _debugString = _scriptFile + debugstring; 155 156 // Get the current opcode 157 byte opcode = readScript8bits(); 158 _firstbit = ((opcode & 0x80) != 0); 159 opcode = opcode & 0x7F; 160 161 // Show the opcode debug string 162 sprintf(debugstring, "op 0x%02X: ", opcode); 163 _debugString += debugstring; 164 debugScript(1, false, _debugString.c_str()); 165 166 // Detect invalid opcodes 167 if (opcode >= NUM_OPCODES) { 168 o_invalid(); 169 return; 170 } 171 172 // Execute the current opcode 173 OpcodeFunc op = _opcodes[opcode]; 174 (this->*op)(); 175 } 176 177 void Script::setMouseClick() { 178 _eventMouseClicked = true; 179 } 180 181 void Script::setKbdChar(uint8 c) { 182 _eventKbdChar = c; 183 } 184 185 bool Script::haveError() { 186 return _error; 187 } 188 189 void Script::error(const char *msg) { 190 // Prepend the debugging info to the error 191 Common::String msg2 = _debugString + msg; 192 193 // Print the error message 194 printf("ERROR: %s\n", msg2.c_str()); 195 196 // Show it in the debugger 197 _debugger->attach(msg2.c_str()); 198 199 // Set the error state 200 _error = true; 201 } 202 203 uint8 Script::readScript8bits() { 204 uint8 data = _code[_currentInstruction]; 205 _currentInstruction++; 206 return data; 207 } 208 209 uint8 Script::readScriptVar() { 210 uint8 data = _variables[readScript8or16bits()]; 211 return data; 212 } 213 214 uint16 Script::readScript16bits() { 215 uint16 data = READ_LE_UINT16(_code + _currentInstruction); 216 _currentInstruction += 2; 217 return data; 218 } 219 220 uint32 Script::readScript32bits() { 221 uint32 data = READ_LE_UINT32(_code + _currentInstruction); 222 _currentInstruction += 4; 223 return data; 224 } 225 226 uint16 Script::readScript8or16bits() { 227 if (_firstbit) { 228 return readScript8bits(); 229 } else { 230 return readScript16bits(); 231 } 232 } 233 234 uint8 Script::readScriptChar(bool allow7C, bool limitVal, bool limitVar) { 235 uint8 result; 236 uint8 data = readScript8bits(); 237 if (limitVal) { 238 data &= 0x7F; 239 } 240 241 if (allow7C && (data == 0x7C)) { 242 // Index a bidimensional array 243 uint8 parta, partb; 244 parta = readScriptChar(false, false, false); 245 partb = readScriptChar(false, true, true); 246 result = _variables[0x0A * parta + partb + 0x19]; 247 } else if (data == 0x23) { 248 // Index an array 249 data = readScript8bits(); 250 if (limitVar) { 251 data &= 0x7F; 252 } 253 result = _variables[data - 0x61]; 254 } else { 255 // Immediate value 256 result = data - 0x30; 257 } 258 return result; 259 } 260 261 uint16 Script::getVideoRefString() { 262 Common::String str; 263 byte c; 264 while ((c = readScript8bits())) { 265 switch (c) { 266 case 0x23: 267 c = readScript8bits(); 268 c = _variables[c - 0x61] + 0x30; 269 if (c >= 0x41 && c <= 0x5A) { 270 c += 0x20; 271 } 272 break; 273 case 0x7C: 274 uint8 parta, partb; 275 parta = readScriptChar(false, false, false); 276 partb = readScriptChar(false, false, false); 277 c = _variables[0x0A * parta + partb + 0x19] + 0x30; 278 break; 279 default: 280 if (c >= 0x41 && c <= 0x5A) { 281 c += 0x20; 282 } 283 } 284 // Append the current character at the end of the string 285 str += c; 286 } 287 288 // Add a trailing dot 289 str += 0x2E; 290 291 debugScript(0, false, "%s", str.c_str()); 292 293 // Extract the script name. 294 Common::String scriptname(_scriptFile.c_str(), _scriptFile.size() - 4); 295 296 // Get the fileref of the resource 297 return _vm->_resMan->getRef(str, scriptname); 298 } 299 300 bool Script::hotspot(Common::Rect rect, uint16 address, uint8 cursor) { 301 // Test if the current mouse position is contained in the specified rectangle 302 Common::Point mousepos = _vm->_system->getEventManager()->getMousePos(); 303 bool contained = rect.contains(mousepos); 304 305 // Show hotspots when debugging 306 if (Common::getEnabledSpecialDebugLevels() & (kGroovieDebugHotspots | kGroovieDebugAll)) { 307 rect.translate(0, -80); 308 _vm->_graphicsMan->_foreground.frameRect(rect, 250); 309 _vm->_system->copyRectToScreen((byte*)_vm->_graphicsMan->_foreground.getBasePtr(0, 0), 640, 0, 80, 640, 320); 310 _vm->_system->updateScreen(); 311 } 312 313 // If there's an already planned action, do nothing 314 if (_inputAction != -1) { 315 return false; 316 } 317 318 if (contained) { 319 // Change the mouse cursor 320 if (_newCursorStyle == 5) { 321 _newCursorStyle = cursor; 322 } 323 324 // If clicked with the mouse, jump to the specified address 325 if (_mouseClicked) { 326 _inputAction = address; 327 } 328 } 329 330 return contained; 331 } 332 333 void Script::loadgame(uint slot) { 334 Common::String filename = ConfMan.getActiveDomainName() + ".00" + ('0' + slot); 335 Common::InSaveFile *file = _vm->_system->getSavefileManager()->openForLoading(filename.c_str()); 336 337 // Loading the variables. It is endian safe because they're byte variables 338 file->read(_variables, 0x400); 339 340 delete file; 341 } 342 343 void Script::savegame(uint slot) { 344 Common::String filename = ConfMan.getActiveDomainName() + ".00" + ('0' + slot); 345 Common::OutSaveFile *file = _vm->_system->getSavefileManager()->openForSaving(filename.c_str()); 346 347 // Saving the variables. It is endian safe because they're byte variables 348 file->write(_variables, 0x400); 349 350 delete file; 351 } 352 353 // OPCODES 354 355 void Script::o_invalid() { 356 error("Invalid opcode"); 357 } 358 359 void Script::o_nop() { 360 debugScript(1, true, "NOP"); 361 } 362 363 void Script::o_nop8() { 364 uint8 tmp = readScript8bits(); 365 debugScript(1, true, "NOP8: 0x%02X", tmp); 366 } 367 368 void Script::o_nop16() { 369 uint16 tmp = readScript16bits(); 370 debugScript(1, true, "NOP16: 0x%04X", tmp); 371 } 372 373 void Script::o_nop32() { 374 uint32 tmp = readScript32bits(); 375 debugScript(1, true, "NOP32: 0x%08X", tmp); 376 } 377 378 void Script::o_nop8or16() { 379 uint16 tmp = readScript8or16bits(); 380 debugScript(1, true, "NOP8OR16: 0x%04X", tmp); 381 } 382 383 void Script::o_playsong() { // 0x02 384 uint16 fileref = readScript16bits(); 385 debugScript(1, true, "PlaySong(0x%04X): Play xmidi file", fileref); 386 if (fileref == 0x4C17) { 387 warning("this song is special somehow"); 388 // don't save the reference? 389 } 390 _vm->_musicPlayer->playSong(fileref); 391 } 392 393 void Script::o_bf9on() { // 0x03 394 debugScript(1, true, "BF9ON: bitflag 9 turned on"); 395 _bitflags |= 1 << 9; 396 } 397 398 void Script::o_palfadeout() { 399 debugScript(1, true, "PALFADEOUT"); 400 _vm->_graphicsMan->fadeOut(); 401 } 402 403 void Script::o_bf8on() { // 0x05 404 debugScript(1, true, "BF8ON: bitflag 8 turned on"); 405 _bitflags |= 1 << 8; 406 } 407 408 void Script::o_bf6on() { // 0x06 409 debugScript(1, true, "BF6ON: bitflag 6 turned on"); 410 _bitflags |= 1 << 6; 411 } 412 413 void Script::o_bf7on() { // 0x07 414 debugScript(1, true, "BF7ON: bitflag 7 turned on"); 415 _bitflags |= 1 << 7; 416 } 417 418 void Script::o_setbackgroundsong() { // 0x08 419 uint16 fileref = readScript16bits(); 420 debugScript(1, true, "SetBackgroundSong(0x%04X)", fileref); 421 _vm->_musicPlayer->setBackgroundSong(fileref); 422 } 423 424 void Script::o_videofromref() { // 0x09 425 uint16 fileref = readScript16bits(); 426 427 // Show the debug information just when starting the playback 428 if (fileref != _videoRef) { 429 debugScript(1, false, "VIDEOFROMREF(0x%04X) (Not fully imp): Play video file from ref", fileref); 430 debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Playing video 0x%04X via 0x09", fileref); 431 } 432 switch (fileref) { 433 case 0x1C03: // Trilobyte logo 434 case 0x1C04: // Virgin logo 435 case 0x1C05: // Credits 436 if (fileref != _videoRef) { 437 debugScript(1, true, "Use external file if available"); 438 } 439 break; 440 441 case 0x400D: // floating objects in music room 442 case 0x5060: // a sound from gamwav? 443 case 0x5098: // a sound from gamwav? 444 case 0x2402: // House becomes book in intro? 445 case 0x1426: // Turn to face front in hall: played after intro 446 case 0x206D: // Cards on table puzzle (bedroom) 447 case 0x2001: // Coins on table puzzle (bedroom) 448 if (fileref != _videoRef) { 449 debugScript(1, false, " (This video is special somehow!)"); 450 warning("(This video is special somehow!)"); 451 printf("Special vid: 0x%04X\n", fileref); 452 } 453 } 454 if (fileref != _videoRef) { 455 debugScript(1, true, ""); 456 } 457 // Play the video 458 if (!playvideofromref(fileref)) { 459 // Move _currentInstruction back 460 _currentInstruction -= 3; 461 } 462 } 463 464 bool Script::playvideofromref(uint16 fileref) { 465 // It isn't the current video, open it 466 if (fileref != _videoRef) { 467 468 // Debug bitflags 469 debugScript(1, false, "Play video 0x%04X (bitflags:", fileref); 470 for (int i = 10; i >= 0; i--) { 471 debugScript(1, false, "%d", _bitflags & (1 << i)? 1 : 0); 472 } 473 debugScript(1, true, ")"); 474 475 // Close the previous video file 476 if (_videoFile) { 477 _videoRef = 0; 478 delete _videoFile; 479 } 480 481 // Try to open the new file 482 _videoFile = _vm->_resMan->open(fileref); 483 484 if (_videoFile) { 485 _videoRef = fileref; 486 _vm->_videoPlayer->load(_videoFile, _bitflags); 487 } else { 488 error("Couldn't open file"); 489 return true; 490 } 491 492 _bitflags = 0; 493 } 494 495 // Video available, play one frame 496 if (_videoFile) { 497 bool endVideo = _vm->_videoPlayer->playFrame(); 498 499 if (endVideo) { 500 // Close the file 501 delete _videoFile; 502 _videoFile = NULL; 503 _videoRef = 0; 504 505 // Clear the input events while playing the video 506 _eventMouseClicked = false; 507 _eventKbdChar = 0; 508 509 // Newline 510 debugScript(1, true, ""); 511 } 512 513 // Let the caller know if the video has ended 514 return endVideo; 515 } 516 517 // If the file is closed, finish the playback 518 return true; 519 } 520 521 void Script::o_bf5on() { // 0x0A 522 debugScript(1, true, "BF5ON: bitflag 5 turned on"); 523 _bitflags |= 1 << 5; 524 } 525 526 void Script::o_inputloopstart() { 527 debugScript(5, true, "Input loop start"); 528 529 // Reset the input action and the mouse cursor 530 _inputAction = -1; 531 _newCursorStyle = 5; 532 533 // Save the input loop address 534 _inputLoopAddress = _currentInstruction - 1; 535 536 // Save the current mouse state for the whole loop 537 _mouseClicked = _eventMouseClicked; 538 _eventMouseClicked = false; 539 540 // Save the current pressed character for the whole loop 541 _kbdChar = _eventKbdChar; 542 _eventKbdChar = 0; 543 } 544 545 void Script::o_keyboardaction() { 546 uint8 val = readScript8bits(); 547 uint16 address = readScript16bits(); 548 debugScript(5, true, "Test key == 0x%02X @0x%04X", val, address); 549 550 // If there's an already planned action, do nothing 551 if (_inputAction != -1) { 552 return; 553 } 554 555 // Check the typed key 556 if (_kbdChar == val) { 557 // Exit the input loop 558 _inputLoopAddress = 0; 559 560 // Save the action address 561 _inputAction = address; 562 } 563 } 564 565 void Script::o_hotspot_rect() { 566 uint16 left = readScript16bits(); 567 uint16 top = readScript16bits(); 568 uint16 right = readScript16bits(); 569 uint16 bottom = readScript16bits(); 570 uint16 address = readScript16bits(); 571 uint8 cursor = readScript8bits(); 572 debugScript(5, true, "HOTSPOT-RECT(%d,%d,%d,%d) @0x%04X cursor=%d", left, top, right, bottom, address, cursor); 573 574 // Mark the specified rectangle 575 Common::Rect rect(left, top, right, bottom); 576 hotspot(rect, address, cursor); 577 } 578 579 void Script::o_hotspot_left() { 580 uint16 address = readScript16bits(); 581 debugScript(5, true, "HOTSPOT-LEFT @0x%04X", address); 582 583 // Mark the leftmost 100 pixels of the game area 584 Common::Rect rect(0, 80, 100, 400); 585 hotspot(rect, address, 1); 586 } 587 588 void Script::o_hotspot_right() { 589 uint16 address = readScript16bits(); 590 debugScript(5, true, "HOTSPOT-RIGHT @0x%04X", address); 591 592 // Mark the rightmost 100 pixels of the game area 593 Common::Rect rect(540, 80, 640, 400); 594 hotspot(rect, address, 2); 595 } 596 597 void Script::o_hotspot_center() { 598 uint16 address = readScript16bits(); 599 debugScript(5, true, "HOTSPOT-CENTER @0x%04X", address); 600 601 // Mark the centremost 240 pixels of the game area 602 Common::Rect rect(200, 80, 440, 400); 603 hotspot(rect, address, 0); 604 } 605 606 void Script::o_hotspot_current() { 607 uint16 address = readScript16bits(); 608 debugScript(5, true, "HOTSPOT-CURRENT @0x%04X", address); 609 610 // The original interpreter doesn't check the position, so accept the 611 // whole screen 612 Common::Rect rect(0, 0, 640, 480); 613 hotspot(rect, address, 0); 614 } 615 616 void Script::o_inputloopend() { 617 debugScript(5, true, "Input loop end"); 618 619 // Handle the predefined hotspots 620 if (_hotspotTopAction) { 621 Common::Rect rect(0, 0, 640, 80); 622 hotspot(rect, _hotspotTopAction, _hotspotTopCursor); 623 } 624 if (_hotspotBottomAction) { 625 Common::Rect rect(0, 400, 640, 480); 626 hotspot(rect, _hotspotBottomAction, _hotspotBottomCursor); 627 } 628 if (_hotspotRightAction) { 629 Common::Rect rect(560, 0, 640, 480); 630 hotspot(rect, _hotspotRightAction, 2); 631 } 632 if (_hotspotLeftAction) { 633 Common::Rect rect(0, 0, 80, 480); 634 hotspot(rect, _hotspotLeftAction, 1); 635 } 636 637 // Actually execute the planned action 638 if (_inputAction != -1) { 639 // Jump to the planned address 640 _currentInstruction = _inputAction; 641 642 // Exit the input loop 643 _inputLoopAddress = 0; 644 _vm->_system->showMouse(false); 645 } 646 647 // Nothing to do 648 if (_inputLoopAddress) { 649 if (_newCursorStyle != _vm->_cursorMan->getStyle()) { 650 _vm->_cursorMan->setStyle(_newCursorStyle); 651 } 652 _vm->_system->showMouse(true); 653 654 // Go back to the begining of the loop 655 _currentInstruction = _inputLoopAddress; 656 657 // There's nothing to do until we get some input 658 _vm->waitForInput(); 659 } 660 } 661 662 void Script::o_random() { 663 uint16 varnum = readScript8or16bits(); 664 uint8 maxnum = readScript8bits(); 665 debugScript(1, true, "RANDOM: var[0x%04X] = rand(%d)", varnum, maxnum); 666 667 _variables[varnum] = _random.getRandomNumber(maxnum); 668 } 669 670 void Script::o_jmp() { 671 uint16 address = readScript16bits(); 672 debugScript(1, true, "JMP @0x%04X", address); 673 674 // Set the current address 675 _currentInstruction = address; 676 } 677 678 void Script::o_loadstring() { 679 uint16 varnum = readScript8or16bits(); 680 debugScript(1, false, "LOADSTRING var[0x%04X..] =", varnum); 681 do { 682 _variables[varnum++] = readScriptChar(true, true, true); 683 debugScript(1, false, " 0x%02X", _variables[varnum - 1]); 684 } while (!(_code[_currentInstruction - 1] & 0x80)); 685 debugScript(1, true, ""); 686 } 687 688 void Script::o_ret() { 689 uint8 val = readScript8bits(); 690 debugScript(1, true, "RET %d", val); 691 692 // Set the return value 693 _variables[0x102] = val; 694 695 // Get the return address 696 if (_stacktop > 0) { 697 _stacktop--; 698 _currentInstruction = _stack[_stacktop]; 699 } else { 700 error("Return: Stack is empty"); 701 } 702 } 703 704 void Script::o_call() { 705 uint16 address = readScript16bits(); 706 debugScript(1, true, "CALL @0x%04X", address); 707 708 // Save return address in the call stack 709 _stack[_stacktop] = _currentInstruction; 710 _stacktop++; 711 712 // Change the current instruction 713 _currentInstruction = address; 714 } 715 716 void Script::o_sleep() { 717 uint16 time = readScript16bits(); 718 debugScript(1, true, "SLEEP 0x%04X", time); 719 720 _vm->_system->delayMillis(time * 3); 721 } 722 723 void Script::o_strcmpnejmp() { // 0x1A 724 uint16 varnum = readScript8or16bits(); 725 debugScript(1, false, "STRCMP-NEJMP: var[0x%04X..],", varnum); 726 uint8 val; 727 uint8 result = 1; 728 do { 729 val = readScriptChar(true, true, true); 730 731 if (_variables[varnum] != val) { 732 result = 0; 733 } 734 varnum++; 735 debugScript(1, false, " 0x%02X", val); 736 737 } while (!(_code[_currentInstruction - 1] & 0x80)); 738 739 uint16 address = readScript16bits(); 740 if (!result) { 741 debugScript(1, true, " jumping to @0x%04X", address); 742 _currentInstruction = address; 743 } else { 744 debugScript(1, true, " not jumping"); 745 } 746 } 747 748 void Script::o_xor_obfuscate() { 749 uint16 varnum = readScript8or16bits(); 750 debugScript(1, false, "XOR OBFUSCATE: var[0x%04X..] = ", varnum); 751 do { 752 uint8 val = readScript8bits(); 753 _firstbit = ((val & 0x80) != 0); 754 val &= 0x4F; 755 756 _variables[varnum] ^= val; 757 debugScript(1, false, "%c", _variables[varnum]); 758 759 varnum++; 760 } while (!_firstbit); 761 debugScript(1, true, ""); 762 } 763 764 void Script::o_vdxtransition() { // 0x1C 765 uint16 fileref = readScript16bits(); 766 767 // Show the debug information just when starting the playback 768 if (fileref != _videoRef) { 769 debugScript(1, true, "VDX transition fileref = 0x%04X", fileref); 770 debugC(1, kGroovieDebugVideo | kGroovieDebugAll, "Playing video 0x%04X with transition", fileref); 771 } 772 773 // Set bit 1 774 _bitflags |= 1 << 1; 775 776 // Clear bit 7 777 _bitflags &= ~(1 << 7); 778 779 // Set bit 2 if _firstbit 780 if (_firstbit) { 781 _bitflags |= 1 << 2; 782 } 783 784 // Play the video 785 if (!playvideofromref(fileref)) { 786 // Move _currentInstruction back 787 _currentInstruction -= 3; 788 } 789 } 790 791 void Script::o_swap() { 792 uint16 varnum1 = readScript8or16bits(); 793 uint16 varnum2 = readScript16bits(); 794 debugScript(1, true, "SWAP var[0x%04X] <-> var[0x%04X]", varnum1, varnum2); 795 796 uint8 tmp = _variables[varnum1]; 797 _variables[varnum1] = _variables[varnum2]; 798 _variables[varnum2] = tmp; 799 } 800 801 void Script::o_inc() { 802 uint16 varnum = readScript8or16bits(); 803 debugScript(1, true, "INC var[0x%04X]", varnum); 804 805 _variables[varnum]++; 806 } 807 808 void Script::o_dec() { 809 uint16 varnum = readScript8or16bits(); 810 debugScript(1, true, "DEC var[0x%04X]", varnum); 811 812 _variables[varnum]--; 813 } 814 815 void Script::o_strcmpnejmp_var() { // 0x21 816 uint16 data = readScriptVar(); 817 if (data > 9) { 818 data -= 7; 819 } 820 data = _variables[data + 0x19]; 821 bool stringsmatch = 1; 822 do { 823 if (_variables[data++] != readScriptChar(true, true, true)) { 824 stringsmatch = 0; 825 } 826 } while (!(_code[_currentInstruction - 1] & 0x80)); 827 828 uint16 offset = readScript16bits(); 829 if (!stringsmatch) { 830 _currentInstruction = offset; 831 } 832 } 833 834 void Script::o_copybgtofg() { // 0x22 835 debugScript(1, true, "COPY_BG_TO_FG"); 836 memcpy(_vm->_graphicsMan->_foreground.getBasePtr(0, 0), _vm->_graphicsMan->_background.getBasePtr(0, 0), 640 * 320); 837 } 838 839 void Script::o_strcmpeqjmp() { // 0x23 840 uint16 varnum = readScript8or16bits(); 841 debugScript(1, false, "STRCMP-EQJMP: var[0x%04X..],", varnum); 842 uint8 val; 843 uint8 result = 1; 844 do { 845 val = readScriptChar(true, true, true); 846 847 if (_variables[varnum] != val) { 848 result = 0; 849 } 850 varnum++; 851 debugScript(1, false, " 0x%02X", val); 852 853 } while (!(_code[_currentInstruction - 1] & 0x80)); 854 855 uint16 address = readScript16bits(); 856 if (result) { 857 debugScript(1, true, " jumping to @0x%04X", address); 858 _currentInstruction = address; 859 } else { 860 debugScript(1, true, " not jumping"); 861 } 862 } 863 864 void Script::o_mov() { 865 uint16 varnum1 = readScript8or16bits(); 866 uint16 varnum2 = readScript16bits(); 867 debugScript(1, true, "MOV var[0x%04X] = var[0x%04X]", varnum1, varnum2); 868 869 _variables[varnum1] = _variables[varnum2]; 870 } 871 872 void Script::o_add() { 873 uint16 varnum1 = readScript8or16bits(); 874 uint16 varnum2 = readScript16bits(); 875 debugScript(1, true, "ADD var[0x%04X] += var[0x%04X]", varnum1, varnum2); 876 877 _variables[varnum1] += _variables[varnum2]; 878 } 879 880 void Script::o_videofromstring1() { 881 uint16 instStart = _currentInstruction; 882 uint16 fileref = getVideoRefString(); 883 884 // Show the debug information just when starting the playback 885 if (fileref != _videoRef) { 886 debugScript(0, true, "VIDEOFROMSTRING1 0x%04X", fileref); 887 } 888 889 // Play the video 890 if (!playvideofromref(fileref)) { 891 // Move _currentInstruction back 892 _currentInstruction = instStart - 1; 893 } 894 } 895 896 void Script::o_videofromstring2() { 897 uint16 instStart = _currentInstruction; 898 uint16 fileref = getVideoRefString(); 899 900 // Show the debug information just when starting the playback 901 if (fileref != _videoRef) { 902 debugScript(0, true, "VIDEOFROMSTRING2 0x%04X", fileref); 903 } 904 905 // Set bit 1 906 _bitflags |= 1 << 1; 907 908 // Set bit 2 if _firstbit 909 if (_firstbit) { 910 _bitflags |= 1 << 2; 911 } 912 913 // Play the video 914 if (!playvideofromref(fileref)) { 915 // Move _currentInstruction back 916 _currentInstruction = instStart - 1; 917 } 918 } 919 920 void Script::o_stopmidi() { 921 debugScript(1, true, "STOPMIDI (TODO)"); 922 } 923 924 void Script::o_endscript() { 925 debugScript(1, true, "END OF SCRIPT"); 926 _error = true; 927 } 928 929 void Script::o_sethotspottop() { 930 uint16 address = readScript16bits(); 931 uint8 cursor = readScript8bits(); 932 debugScript(5, true, "SETHOTSPOTTOP @0x%04X cursor=%d", address, cursor); 933 934 _hotspotTopAction = address; 935 _hotspotTopCursor = cursor; 936 } 937 938 void Script::o_sethotspotbottom() { 939 uint16 address = readScript16bits(); 940 uint8 cursor = readScript8bits(); 941 debugScript(5, true, "SETHOTSPOTBOTTOM @0x%04X cursor=%d", address, cursor); 942 943 _hotspotBottomAction = address; 944 _hotspotBottomCursor = cursor; 945 } 946 947 void Script::o_loadgame() { 948 uint16 varnum = readScript8or16bits(); 949 uint8 slot = _variables[varnum]; 950 debugScript(1, true, "LOADGAME var[0x%04X] -> slot=%d (TODO)", varnum, slot); 951 952 loadgame(slot); 953 _vm->_system->clearScreen(); 954 } 955 956 void Script::o_savegame() { 957 uint16 varnum = readScript8or16bits(); 958 uint8 slot = _variables[varnum]; 959 debugScript(1, true, "SAVEGAME var[0x%04X] -> slot=%d (TODO)", varnum, slot); 960 961 savegame(slot); 962 } 963 964 void Script::o_hotspotbottom_4() { //0x30 965 uint16 address = readScript16bits(); 966 debugScript(5, true, "HOTSPOT-BOTTOM @0x%04X", address); 967 968 // Mark the 80 pixels under the game area 969 Common::Rect rect(0, 400, 640, 480); 970 hotspot(rect, address, 4); 971 } 972 973 void Script::o_midivolume() { 974 uint16 arg1 = readScript16bits(); 975 uint16 arg2 = readScript16bits(); 976 debugScript(1, true, "MIDI volume: %d %d", arg1, arg2); 977 _vm->_musicPlayer->setGameVolume(arg1, arg2); 978 } 979 980 void Script::o_jne() { 981 int16 varnum1 = readScript8or16bits(); 982 uint16 varnum2 = readScript16bits(); 983 uint16 address = readScript16bits(); 984 debugScript(1, false, "JNE: var[var[0x%04X] - 0x31] != var[0x%04X] @0x%04X", varnum1, varnum2, address); 985 986 if (_variables[_variables[varnum1] - 0x31] != _variables[varnum2]) { 987 _currentInstruction = address; 988 debugScript(1, true, " jumping to @0x%04X", address); 989 } else { 990 debugScript(1, true, " not jumping"); 991 } 992 } 993 994 void Script::o_loadstringvar() { 995 uint16 varnum = readScript8or16bits(); 996 varnum = _variables[varnum] - 0x31; 997 debugScript(1, false, "LOADSTRINGVAR var[0x%04X..] =", varnum); 998 do { 999 _variables[varnum++] = readScriptChar(true, true, true); 1000 debugScript(1, false, " 0x%02X", _variables[varnum - 1]); 1001 } while (!(_code[_currentInstruction - 1] & 0x80)); 1002 debugScript(1, true, ""); 1003 } 1004 1005 void Script::o_chargreatjmp() { 1006 uint16 varnum = readScript8or16bits(); 1007 debugScript(1, false, "CHARGREAT-JMP: var[0x%04X..],", varnum); 1008 uint8 val; 1009 uint8 result = 0; 1010 do { 1011 val = readScriptChar(true, true, true); 1012 1013 if (val < _variables[varnum]) { 1014 result = 1; 1015 } 1016 varnum++; 1017 debugScript(1, false, " 0x%02X", val); 1018 } while (!(_code[_currentInstruction - 1] & 0x80)); 1019 1020 uint16 address = readScript16bits(); 1021 if (result) { 1022 debugScript(1, true, " jumping to @0x%04X", address); 1023 _currentInstruction = address; 1024 } else { 1025 debugScript(1, true, " not jumping"); 1026 } 1027 } 1028 1029 void Script::o_bf7off() { 1030 debugScript(1, true, "BF7OFF: bitflag 7 turned off"); 1031 _bitflags &= ~(1 << 7); 1032 } 1033 1034 void Script::o_charlessjmp() { 1035 uint16 varnum = readScript8or16bits(); 1036 debugScript(1, false, "CHARLESS-JMP: var[0x%04X..],", varnum); 1037 uint8 val; 1038 uint8 result = 0; 1039 do { 1040 val = readScriptChar(true, true, true); 1041 1042 if (val > _variables[varnum]) { 1043 result = 1; 1044 } 1045 varnum++; 1046 debugScript(1, false, " 0x%02X", val); 1047 } while (!(_code[_currentInstruction - 1] & 0x80)); 1048 1049 uint16 address = readScript16bits(); 1050 if (result) { 1051 debugScript(1, true, " jumping to @0x%04X", address); 1052 _currentInstruction = address; 1053 } else { 1054 debugScript(1, true, " not jumping"); 1055 } 1056 } 1057 1058 void Script::o_copyrecttobg() { // 0x37 1059 uint16 left = readScript16bits(); 1060 uint16 top = readScript16bits(); 1061 uint16 right = readScript16bits(); 1062 uint16 bottom = readScript16bits(); 1063 debugScript(1, true, "COPYRECT((%d,%d)->(%d,%d))", left, top, right, bottom); 1064 1065 uint16 i, width = right - left, height = bottom - top; 1066 uint32 offset = 0; 1067 byte *fg, *bg; 1068 fg = (byte *)_vm->_graphicsMan->_foreground.getBasePtr(left, top - 80); 1069 bg = (byte *)_vm->_graphicsMan->_background.getBasePtr(left, top - 80); 1070 for (i = 0; i < height; i++) { 1071 memcpy(bg + offset, fg + offset, width); 1072 offset += 640; 1073 } 1074 _vm->_system->copyRectToScreen((byte *)_vm->_graphicsMan->_background.getBasePtr(left, top - 80), 640, left, top, width, height); 1075 _vm->_graphicsMan->change(); 1076 } 1077 1078 void Script::o_restorestkpnt() { 1079 debugScript(1, true, "Restore stack pointer from saved (TODO)"); 1080 } 1081 1082 void Script::o_obscureswap() { 1083 debugScript(1, true, "OBSCSWAP"); 1084 uint16 var1, var2, tmp; 1085 1086 // Read the first variable 1087 var1 = readScriptChar(false, true, true) * 10; 1088 var1 += readScriptChar(false, true, true) + 0x19; 1089 1090 // Read the second variable 1091 var2 = readScriptChar(false, true, true) * 10; 1092 var2 += readScriptChar(false, true, true) + 0x19; 1093 1094 // Swap the values 1095 tmp = _variables[var1]; 1096 _variables[var1] = _variables[var2]; 1097 _variables[var2] = tmp; 1098 } 1099 1100 void Script::o_printstring() { 1101 char stringstorage[15], newchar; 1102 uint8 counter = 0; 1103 memset(stringstorage, 0, 15); 1104 do { 1105 newchar = readScriptChar(true, true, true) + 0x30; 1106 if (newchar < 0x30 || newchar > 0x39) { // If character is invalid, chuck a space in 1107 if (newchar < 0x41 || newchar > 0x7A) { 1108 newchar = 0x20; 1109 } 1110 } 1111 1112 stringstorage[counter] = newchar; 1113 counter++; 1114 } while (!(_code[_currentInstruction - 1] & 0x80)); 1115 1116 stringstorage[counter] = 0; 1117 1118 // Load the font if required 1119 if (!_font) { 1120 _font = new Font(_vm->_system); 1121 } 1122 _font->printstring(stringstorage); 1123 } 1124 1125 void Script::o_hotspot_slot() { 1126 uint16 slot = readScript8bits(); 1127 uint16 left = readScript16bits(); 1128 uint16 top = readScript16bits(); 1129 uint16 right = readScript16bits(); 1130 uint16 bottom = readScript16bits(); 1131 uint16 address = readScript16bits(); 1132 uint16 cursor = readScript8bits(); 1133 debugScript(1, true, "HOTSPOT-SLOT %d (%d,%d,%d,%d) @0x%04X cursor=%d (TODO)", slot, left, top, right, bottom, address, cursor); 1134 1135 Common::Rect rect(left, top, right, bottom); 1136 if (hotspot(rect, address, cursor)) { 1137 char savename[15]; 1138 1139 Common::String filename = ConfMan.getActiveDomainName() + ".00" + ('0' + slot); 1140 Common::StringList files = _vm->_system->getSavefileManager()->listSavefiles(filename.c_str()); 1141 if (!files.empty()) { 1142 Common::InSaveFile *file = _vm->_system->getSavefileManager()->openForLoading(filename.c_str()); 1143 if (file) { 1144 uint8 i; 1145 char temp; 1146 1147 for (i = 0; i < 15; i++) { 1148 file->read(&temp, 1); 1149 savename[i] = temp + 0x30; 1150 } 1151 1152 delete file; 1153 } else { 1154 strcpy(savename, "ERROR"); 1155 } 1156 } else { 1157 strcpy(savename, "E M P T Y"); 1158 } 1159 1160 // Load the font if required 1161 if (!_font) { 1162 _font = new Font(_vm->_system); 1163 } 1164 _font->printstring(savename); 1165 } else { 1166 Common::Point mousepos = _vm->_system->getEventManager()->getMousePos(); 1167 if (_hotspotCursorOldX != mousepos.x || _hotspotCursorOldY != mousepos.y ) { 1168 Common::Rect topbar(640, 80); 1169 1170 Graphics::Surface *gamescreen; 1171 gamescreen = _vm->_system->lockScreen(); 1172 1173 gamescreen->fillRect(topbar, 0); 1174 1175 _vm->_system->unlockScreen(); 1176 _hotspotCursorOldX = mousepos.x; 1177 _hotspotCursorOldY = mousepos.y; 1178 } 1179 } 1180 } 1181 1182 void Script::o_checkvalidsaves() { 1183 debugScript(1, true, "CHECKVALIDSAVES"); 1184 1185 // Reset the array of valid saves 1186 for (int i = 0; i < 10; i++) { 1187 _variables[i] = 0; 1188 } 1189 1190 // Get the list of savefiles 1191 Common::String pattern = ConfMan.getActiveDomainName() + ".00?"; 1192 Common::StringList savefiles = _vm->_system->getSavefileManager()->listSavefiles(pattern.c_str()); 1193 1194 // Mark the existing savefiles as valid 1195 uint count = 0; 1196 Common::StringList::iterator it = savefiles.begin(); 1197 while (it != savefiles.end()) { 1198 int8 n = it->lastChar() - '0'; 1199 if (n >= 0 && n <= 9) { 1200 // TODO: Check the contents of the file? 1201 debugScript(2, true, " Found valid savegame: %s", it->c_str()); 1202 _variables[n] = 1; 1203 count++; 1204 } 1205 it++; 1206 } 1207 1208 // Save the number of valid saves 1209 _variables[0x104] = count; 1210 debugScript(1, true, " Found %d valid savegames", count); 1211 } 1212 1213 void Script::o_resetvars() { 1214 debugScript(1, true, "RESETVARS"); 1215 for (int i = 0; i < 0x100; i++) { 1216 _variables[i] = 0; 1217 } 1218 } 1219 1220 void Script::o_mod() { 1221 uint16 varnum = readScript8or16bits(); 1222 uint8 val = readScript8bits(); 1223 debugScript(1, true, "MOD var[0x%04X] %%= %d", varnum, val); 1224 1225 _variables[varnum] %= val; 1226 } 1227 1228 void Script::o_loadscript() { 1229 Common::String filename; 1230 char c; 1231 while ((c = readScript8bits())) { 1232 filename += c; 1233 } 1234 debugScript(1, true, "LOADSCRIPT %s", filename.c_str()); 1235 1236 // Just 1 level of sub-scripts are allowed 1237 if (_savedCode) { 1238 error("Tried to load a level 2 sub-script"); 1239 } 1240 1241 // Save the current code 1242 _savedCode = _code; 1243 _savedInstruction = _currentInstruction; 1244 1245 // Save the filename of the current script 1246 _savedScriptFile = _scriptFile; 1247 1248 // Load the sub-script 1249 if (!loadScript(filename)) { 1250 error("Couldn't load sub-script"); 1251 } 1252 1253 // Save the current stack top 1254 _savedStacktop = _stacktop; 1255 1256 // Save the variables 1257 memcpy(_savedVariables, _variables + 0x107, 0x180); 1258 } 1259 1260 void Script::o_setvideoorigin() { 1261 // Set bitflag 7 1262 _bitflags |= 1 << 7; 1263 1264 // Read the two offset arguments 1265 int16 origX = readScript16bits(); 1266 int16 origY = readScript16bits(); 1267 1268 debugScript(1, true, "SetVideoOrigin(0x%04X,0x%04X) (%d, %d)", origX, origY, origX, origY); 1269 _vm->_videoPlayer->setOrigin(origX, origY); 1270 } 1271 1272 void Script::o_sub() { 1273 uint16 varnum1 = readScript8or16bits(); 1274 uint16 varnum2 = readScript16bits(); 1275 debugScript(1, true, "SUB var[0x%04X] -= var[0x%04X]", varnum1, varnum2); 1276 1277 _variables[varnum1] -= _variables[varnum2]; 1278 } 1279 1280 void Script::o_othello() { 1281 uint16 arg = readScript8bits(); 1282 debugScript(1, true, "OTHELLO var[0x%02X]", arg); 1283 1284 // Arguments used by the original implementation: (2, arg, scriptBoard) 1285 byte *scriptBoard = &_variables[0x19]; 1286 byte board[7][7]; 1287 for (int y = 0; y < 7; y++) { 1288 for (int x = 0; x < 7; x++) { 1289 board[x][y] = 0; 1290 if (*scriptBoard == 0x32) board[x][y] = 1; 1291 if (*scriptBoard == 0x42) board[x][y] = 2; 1292 scriptBoard++; 1293 printf("%d", board[x][y]); 1294 } 1295 printf("\n"); 1296 } 1297 1298 // Set the movement origin 1299 _variables[0] = 6; // y 1300 _variables[1] = 0; // x 1301 // Set the movement destination 1302 _variables[2] = 6; 1303 _variables[3] = 1; 1304 } 1305 1306 void Script::o_returnscript() { 1307 uint8 val = readScript8bits(); 1308 debugScript(1, true, "RETURNSCRIPT @0x%02X", val); 1309 1310 // Are we returning from a sub-script? 1311 if (!_savedCode) { 1312 error("Tried to return from the main script"); 1313 } 1314 1315 // Set the return value 1316 _variables[0x102] = val; 1317 1318 // Restore the code 1319 delete[] _code; 1320 _code = _savedCode; 1321 _savedCode = NULL; 1322 _currentInstruction = _savedInstruction; 1323 1324 // Restore the stack 1325 _stacktop = _savedStacktop; 1326 1327 // Restore the variables 1328 memcpy(_variables + 0x107, _savedVariables, 0x180); 1329 1330 // Restore the filename of the script 1331 _scriptFile = _savedScriptFile; 1332 1333 //TODO: reset script flags and previous video's flag1? 1334 _vm->_videoPlayer->setOrigin(0, 0); 1335 } 1336 1337 void Script::o_sethotspotright() { 1338 uint16 address = readScript16bits(); 1339 debugScript(1, true, "SETHOTSPOTRIGHT @0x%04X", address); 1340 1341 _hotspotRightAction = address; 1342 } 1343 1344 void Script::o_sethotspotleft() { 1345 uint16 address = readScript16bits(); 1346 debugScript(1, true, "SETHOTSPOTLEFT @0x%04X", address); 1347 1348 _hotspotLeftAction = address; 1349 } 1350 1351 void Script::o_getcd() { 1352 debugScript(1, true, "GETCD"); 1353 1354 // By default set it to no CD available 1355 int8 cd = -1; 1356 1357 // Try to open one file from each CD 1358 Common::File cdfile; 1359 if (cdfile.open("b.gjd")) { 1360 cdfile.close(); 1361 cd = 1; 1362 } 1363 if (cdfile.open("at.gjd")) { 1364 cdfile.close(); 1365 if (cd == 1) { 1366 // Both CDs are available 1367 cd = 0; 1368 } else { 1369 cd = 2; 1370 } 1371 } 1372 1373 _variables[0x106] = cd; 1374 } 1375 1376 void Script::o_opcode4D() { 1377 // TODO: play alternative vie logo, then playcd 1378 uint8 val = readScript8bits(); 1379 debugScript(1, true, "PLAYCD? %d", val); 1380 1381 if (val == 2) { 1382 AudioCD.play(1, 1, 0, 0); 1383 } 1384 1385 } 1386 1387 void Script::o_hotspot_outrect() { 1388 uint16 left = readScript16bits(); 1389 uint16 top = readScript16bits(); 1390 uint16 right = readScript16bits(); 1391 uint16 bottom = readScript16bits(); 1392 uint16 address = readScript16bits(); 1393 debugScript(1, true, "HOTSPOT-OUTRECT(%d,%d,%d,%d) @0x%04X (TODO)", left, top, right, bottom, address); 1394 1395 // Test if the current mouse position is outside the specified rectangle 1396 Common::Rect rect(left, top, right, bottom); 1397 Common::Point mousepos = _vm->_system->getEventManager()->getMousePos(); 1398 bool contained = rect.contains(mousepos); 1399 1400 if (!contained) { 1401 error("hotspot-outrect unimplemented!"); 1402 // TODO: what to do with address? 1403 } 1404 } 1405 1406 void Script::o_stub56() { 1407 uint32 val1 = readScript32bits(); 1408 uint8 val2 = readScript8bits(); 1409 uint8 val3 = readScript8bits(); 1410 debugScript(1, true, "STUB56: 0x%08X 0x%02X 0x%02X", val1, val2, val3); 1411 } 1412 1413 void Script::o_stub59() { 1414 uint16 val1 = readScript8or16bits(); 1415 uint8 val2 = readScript8bits(); 1416 debugScript(1, true, "STUB59: 0x%04X 0x%02X", val1, val2); 1417 } 1418 1419 Script::OpcodeFunc Script::_opcodes[NUM_OPCODES] = { 1420 &Script::o_nop, // 0x00 1421 &Script::o_nop, 1422 &Script::o_playsong, 1423 &Script::o_bf9on, 1424 &Script::o_palfadeout, // 0x04 1425 &Script::o_bf8on, 1426 &Script::o_bf6on, 1427 &Script::o_bf7on, 1428 &Script::o_setbackgroundsong, // 0x08 1429 &Script::o_videofromref, 1430 &Script::o_bf5on, 1431 &Script::o_inputloopstart, 1432 &Script::o_keyboardaction, // 0x0C 1433 &Script::o_hotspot_rect, 1434 &Script::o_hotspot_left, 1435 &Script::o_hotspot_right, 1436 &Script::o_hotspot_center, // 0x10 1437 &Script::o_hotspot_center, 1438 &Script::o_hotspot_current, 1439 &Script::o_inputloopend, 1440 &Script::o_random, // 0x14 1441 &Script::o_jmp, 1442 &Script::o_loadstring, 1443 &Script::o_ret, 1444 &Script::o_call, // 0x18 1445 &Script::o_sleep, 1446 &Script::o_strcmpnejmp, 1447 &Script::o_xor_obfuscate, 1448 &Script::o_vdxtransition, // 0x1C 1449 &Script::o_swap, 1450 &Script::o_nop8, 1451 &Script::o_inc, 1452 &Script::o_dec, // 0x20 1453 &Script::o_strcmpnejmp_var, 1454 &Script::o_copybgtofg, 1455 &Script::o_strcmpeqjmp, 1456 &Script::o_mov, // 0x24 1457 &Script::o_add, 1458 &Script::o_videofromstring1, // Reads a string and then does stuff: used by book in library 1459 &Script::o_videofromstring2, // play vdx file from string, after setting 1 (and 2 if firstbit) 1460 &Script::o_nop16, // 0x28 1461 &Script::o_stopmidi, 1462 &Script::o_endscript, 1463 &Script::o_nop, 1464 &Script::o_sethotspottop, // 0x2C 1465 &Script::o_sethotspotbottom, 1466 &Script::o_loadgame, 1467 &Script::o_savegame, 1468 &Script::o_hotspotbottom_4, // 0x30 1469 &Script::o_midivolume, 1470 &Script::o_jne, 1471 &Script::o_loadstringvar, 1472 &Script::o_chargreatjmp, // 0x34 1473 &Script::o_bf7off, 1474 &Script::o_charlessjmp, 1475 &Script::o_copyrecttobg, 1476 &Script::o_restorestkpnt, // 0x38 1477 &Script::o_obscureswap, 1478 &Script::o_printstring, 1479 &Script::o_hotspot_slot, 1480 &Script::o_checkvalidsaves, // 0x3C 1481 &Script::o_resetvars, 1482 &Script::o_mod, 1483 &Script::o_loadscript, 1484 &Script::o_setvideoorigin, // 0x40 1485 &Script::o_sub, 1486 &Script::o_othello, 1487 &Script::o_returnscript, 1488 &Script::o_sethotspotright, // 0x44 1489 &Script::o_sethotspotleft, 1490 &Script::o_nop, 1491 &Script::o_nop, 1492 &Script::o_nop8, // 0x48 1493 &Script::o_nop, 1494 &Script::o_nop16, 1495 &Script::o_nop8, 1496 &Script::o_getcd, // 0x4C 1497 &Script::o_opcode4D, 1498 &Script::o_nop16, 1499 &Script::o_nop16, 1500 &Script::o_nop16, // 0x50 1501 &Script::o_nop16, 1502 //&Script::o_nop8, 1503 &Script::o_invalid, // Do loads with game area, maybe draw dirty areas? 1504 &Script::o_hotspot_outrect, 1505 &Script::o_nop, // 0x54 1506 &Script::o_nop16, 1507 &Script::o_stub56, 1508 //&Script::o_nop32, 1509 &Script::o_invalid, // completely unimplemented, plays vdx in some way 1510 //&Script::o_nop, // 0x58 1511 &Script::o_invalid, // 0x58 // like above, but plays from string not ref 1512 &Script::o_stub59 1513 }; 1514 1515 } // End of Groovie namespace -
engines/groovie/graphics.h
1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 * $URL$ 22 * $Id$ 23 * 24 */ 25 26 #ifndef GROOVIE_GRAPHICS_H 27 #define GROOVIE_GRAPHICS_H 28 29 namespace Groovie { 30 31 class GroovieEngine; 32 33 class GraphicsMan { 34 public: 35 GraphicsMan(GroovieEngine *vm); 36 ~GraphicsMan(); 37 38 // Buffers 39 void update(); 40 void change(); 41 void mergeFgAndBg(); 42 void updateScreen(Graphics::Surface *source); 43 Graphics::Surface _foreground; // The main surface that most things are drawn to 44 Graphics::Surface _background; // Used occasionally, mostly (only?) in puzzles 45 46 // Palette fading 47 bool isFading(); 48 void fadeIn(byte *pal); 49 void fadeOut(); 50 51 private: 52 GroovieEngine *_vm; 53 54 bool _changed; 55 56 // Palette fading 57 void applyFading(int step); 58 int _fading; 59 byte _paletteFull[256 * 4]; 60 uint32 _fadeStartTime; 61 }; 62 63 } // End of Groovie namespace 64 65 #endif // GROOVIE_GRAPHICS_H -
engines/groovie/roq.h
1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 * $URL$ 22 * $Id$ 23 * 24 */ 25 26 #ifndef GROOVIE_ROQ_H 27 #define GROOVIE_ROQ_H 28 29 #include "groovie/player.h" 30 31 namespace Groovie { 32 33 class GroovieEngine; 34 35 struct ROQBlockHeader { 36 uint16 type; 37 uint32 size; 38 uint16 param; 39 }; 40 41 class ROQPlayer : public VideoPlayer { 42 public: 43 ROQPlayer(GroovieEngine *vm); 44 ~ROQPlayer(); 45 46 protected: 47 uint16 loadInternal(); 48 bool playFrameInternal(); 49 50 private: 51 bool readBlockHeader(ROQBlockHeader &blockHeader); 52 53 bool processBlock(); 54 bool processBlockInfo(ROQBlockHeader &blockHeader); 55 bool processBlockQuadCodebook(ROQBlockHeader &blockHeader); 56 bool processBlockQuadVector(ROQBlockHeader &blockHeader); 57 bool processBlockQuadVectorSub(ROQBlockHeader &blockHeader); 58 bool processBlockStill(ROQBlockHeader &blockHeader); 59 bool processBlockSoundMono(ROQBlockHeader &blockHeader); 60 bool processBlockSoundStereo(ROQBlockHeader &blockHeader); 61 bool processBlockAudioContainer(ROQBlockHeader &blockHeader); 62 63 uint16 _num2blocks; 64 uint16 _num4blocks; 65 }; 66 67 } // End of Groovie namespace 68 69 #endif // GROOVIE_ROQ_H -
engines/groovie/font.cpp
1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 * $URL$ 22 * $Id$ 23 * 24 */ 25 26 #include "common/file.h" 27 #include "graphics/surface.h" 28 29 #include "groovie/font.h" 30 31 namespace Groovie { 32 33 Font::Font(OSystem *syst) : 34 _syst(syst), _sphinxfnt(NULL) { 35 36 Common::File fontfile; 37 if (!fontfile.open("sphinx.fnt")) { 38 error("Groovie::Font: Couldn't open sphinx.fnt"); 39 } 40 uint16 fontfilesize = fontfile.size(); 41 _sphinxfnt = fontfile.readStream(fontfilesize); 42 fontfile.close(); 43 } 44 45 Font::~Font() { 46 delete _sphinxfnt; 47 } 48 49 void Font::printstring(char *messagein) { 50 uint16 totalwidth = 0, currxoffset, i; 51 52 char message[15]; 53 memset(message, 0, 15); 54 55 // Clear the top bar 56 Common::Rect topbar(640, 80); 57 Graphics::Surface *gamescreen; 58 gamescreen = _syst->lockScreen(); 59 gamescreen->fillRect(topbar, 0); 60 _syst->unlockScreen(); 61 62 for (i = 0; i < 14; i++) { 63 char chartocopy = messagein[i]; 64 if (chartocopy <= 0x00 || chartocopy == 0x24) { 65 break; 66 } 67 message[i] = chartocopy; 68 } 69 Common::rtrim(message); 70 for (i = 0; i < strlen(message); i++) { 71 totalwidth += letterwidth(message[i]); 72 } 73 currxoffset = (640 - totalwidth) / 2; 74 char *currpos = message; 75 while (*(currpos) != 0) { 76 currxoffset += printletter(*(currpos++), currxoffset); 77 } 78 } 79 80 uint16 Font::letteroffset(char letter) { 81 uint16 offset; 82 offset = letter; 83 _sphinxfnt->seek(offset); 84 offset = _sphinxfnt->readByte() * 2 + 128; 85 _sphinxfnt->seek(offset); 86 offset = _sphinxfnt->readUint16LE(); 87 return offset; 88 } 89 90 uint8 Font::letterwidth(char letter) { 91 uint16 offset = letteroffset(letter); 92 _sphinxfnt->seek(offset); 93 return _sphinxfnt->readByte(); 94 } 95 96 uint8 Font::letterheight(char letter) { 97 uint16 offset, width, julia, data, counter = 0; 98 offset = letteroffset(letter); 99 _sphinxfnt->seek(offset); 100 width = _sphinxfnt->readByte(); 101 julia = _sphinxfnt->readByte(); 102 data = _sphinxfnt->readByte(); 103 while (data != 0xFF) { 104 data = _sphinxfnt->readByte(); 105 counter++; 106 } 107 if (counter % width != 0) assert("font file corrupt"); 108 return counter / width; 109 } 110 111 112 uint8 Font::printletter(char letter, uint16 xoffset) { 113 uint16 offset, width, height, julia; 114 //printf("%c (%d), ", letter, letter); 115 offset = letteroffset(letter); 116 height = letterheight(letter); 117 _sphinxfnt->seek(offset); 118 width = _sphinxfnt->readByte(); 119 julia = _sphinxfnt->readByte(); 120 121 byte *data = new byte[width * height]; 122 _sphinxfnt->read(data, width * height); 123 _syst->copyRectToScreen(data, width, xoffset, 16, width, height); 124 delete data; 125 126 return width; 127 } 128 129 } // End of Groovie namespace -
engines/groovie/vdx.h
1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 * $URL$ 22 * $Id$ 23 * 24 */ 25 26 #ifndef GROOVIE_VDX_H 27 #define GROOVIE_VDX_H 28 29 #include "groovie/player.h" 30 31 namespace Groovie { 32 33 class VDXPlayer : public VideoPlayer { 34 public: 35 VDXPlayer(GroovieEngine *vm); 36 ~VDXPlayer(); 37 void setOrigin(int16 x, int16 y); 38 39 protected: 40 uint16 loadInternal(); 41 bool playFrameInternal(); 42 43 private: 44 Graphics::Surface *_fg, *_bg; 45 uint8 _palBuf[3 * 256]; 46 47 // Origin 48 int16 _origX, _origY; 49 50 // Video flags 51 bool _flagZero; 52 bool _flagOne; 53 bool _flagOnePrev; 54 byte _flag2Byte; 55 bool _flagThree; 56 bool _flagFour; 57 bool _flagFive; 58 bool _flagSix; 59 bool _flagSeven; 60 bool _flagEight; 61 bool _flagNine; 62 63 bool _flagSkipStill; 64 bool _flagSkipPalette; 65 bool _flagFirstFrame; 66 bool _flagTransparent; 67 bool _flagUpdateStill; 68 69 void getStill(Common::ReadStream *in); 70 void getDelta(Common::ReadStream *in); 71 void expandColourMap(byte *out, uint16 colourMap, uint8 colour1, uint8 colour0); 72 void decodeBlockStill(byte *buf, byte *colours, uint16 imageWidth, uint8 mask); 73 void decodeBlockDelta(uint32 offset, byte *colours, uint16 imageWidth); 74 void chunkSound(Common::ReadStream *in); 75 void setPalette(uint8 *palette); 76 void fadeIn(uint8 *palette); 77 }; 78 79 } // End of Groovie namespace 80 81 #endif // GROOVIE_VDX_H -
engines/groovie/script.h
1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 * $URL$ 22 * $Id$ 23 * 24 */ 25 26 #ifndef GROOVIE_SCRIPT_H 27 #define GROOVIE_SCRIPT_H 28 29 #include "common/file.h" 30 #include "common/rect.h" 31 32 #include "groovie/font.h" 33 34 namespace Groovie { 35 36 class GroovieEngine; 37 38 class Script { 39 friend class Debugger; 40 41 public: 42 Script(GroovieEngine *vm); 43 ~Script(); 44 45 void setDebugger(Debugger *debugger); 46 47 bool loadScript(Common::String scriptfile); 48 void directGameLoad(int slot); 49 void step(); 50 51 void setMouseClick(); 52 void setKbdChar(uint8 c); 53 54 bool haveError(); 55 56 private: 57 GroovieEngine *_vm; 58 59 Common::RandomSource _random; 60 61 bool _firstbit; 62 63 // Script filename (for debugging purposes) 64 Common::String _scriptFile; 65 Common::String _savedScriptFile; 66 67 // Code 68 byte *_code; 69 uint16 _currentInstruction; 70 byte *_savedCode; 71 uint16 _savedInstruction; 72 73 // Variables 74 byte _variables[0x400]; 75 byte _savedVariables[0x180]; 76 77 // Stack 78 uint16 _stack[0x20]; 79 uint8 _stacktop; 80 uint8 _savedStacktop; 81 82 // Input 83 bool _mouseClicked; 84 bool _eventMouseClicked; 85 uint8 _kbdChar; 86 uint8 _eventKbdChar; 87 uint16 _inputLoopAddress; 88 int16 _inputAction; 89 uint8 _newCursorStyle; 90 uint16 _hotspotTopAction; 91 uint16 _hotspotTopCursor; 92 uint16 _hotspotBottomAction; 93 uint16 _hotspotBottomCursor; 94 uint16 _hotspotRightAction; 95 uint16 _hotspotLeftAction; 96 uint16 _hotspotCursorOldX; 97 uint16 _hotspotCursorOldY; 98 99 // Video 100 Font *_font; 101 Common::SeekableReadStream *_videoFile; 102 uint16 _videoRef; 103 uint16 _bitflags; 104 105 // Debugging 106 Debugger *_debugger; 107 Common::String _debugString; 108 void error(const char *msg); 109 bool _error; 110 111 // Helper functions 112 uint8 readScript8bits(); 113 uint16 readScript16bits(); 114 uint32 readScript32bits(); 115 uint16 readScript8or16bits(); 116 uint8 readScriptChar(bool allow7C, bool limitVal, bool limitVar); 117 uint8 readScriptVar(); 118 uint16 getVideoRefString(); 119 120 bool hotspot(Common::Rect rect, uint16 addr, uint8 cursor); 121 122 void loadgame(uint slot); 123 void savegame(uint slot); 124 bool playvideofromref(uint16 fileref); 125 126 // Opcodes 127 typedef void (Script::*OpcodeFunc)(); 128 static OpcodeFunc _opcodes[]; 129 130 void o_invalid(); 131 132 void o_nop(); 133 void o_nop8(); 134 void o_nop16(); 135 void o_nop32(); 136 void o_nop8or16(); 137 138 void o_playsong(); 139 void o_bf9on(); 140 void o_palfadeout(); 141 void o_bf8on(); 142 void o_bf6on(); 143 void o_bf7on(); 144 void o_setbackgroundsong(); 145 void o_videofromref(); 146 void o_bf5on(); 147 void o_inputloopstart(); 148 void o_keyboardaction(); 149 void o_hotspot_rect(); 150 void o_hotspot_left(); 151 void o_hotspot_right(); 152 void o_hotspot_center(); 153 void o_hotspot_current(); 154 void o_inputloopend(); 155 void o_random(); 156 void o_jmp(); 157 void o_loadstring(); 158 void o_ret(); 159 void o_call(); 160 void o_sleep(); 161 void o_strcmpnejmp_var(); 162 void o_copybgtofg(); 163 void o_strcmpnejmp(); 164 void o_xor_obfuscate(); 165 void o_vdxtransition(); 166 void o_swap(); 167 void o_inc(); 168 void o_dec(); 169 void o_strcmpeqjmp(); 170 void o_mov(); 171 void o_add(); 172 void o_videofromstring1(); 173 void o_videofromstring2(); 174 void o_stopmidi(); 175 void o_endscript(); 176 void o_sethotspottop(); 177 void o_sethotspotbottom(); 178 void o_loadgame(); 179 void o_savegame(); 180 void o_hotspotbottom_4(); 181 void o_midivolume(); 182 void o_jne(); 183 void o_loadstringvar(); 184 void o_chargreatjmp(); 185 void o_bf7off(); 186 void o_charlessjmp(); 187 void o_copyrecttobg(); 188 void o_restorestkpnt(); 189 void o_obscureswap(); 190 void o_printstring(); 191 void o_hotspot_slot(); 192 void o_checkvalidsaves(); 193 void o_resetvars(); 194 void o_mod(); 195 void o_loadscript(); 196 void o_setvideoorigin(); 197 void o_sub(); 198 void o_othello(); 199 void o_returnscript(); 200 void o_sethotspotright(); 201 void o_sethotspotleft(); 202 void o_getcd(); 203 void o_opcode4D(); 204 void o_hotspot_outrect(); 205 void o_stub56(); 206 void o_stub59(); 207 }; 208 209 } // End of Groovie namespace 210 211 #endif // GROOVIE_SCRIPT_H -
engines/groovie/groovie.cpp
1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 * $URL$ 22 * $Id$ 23 * 24 */ 25 26 #include "common/config-manager.h" 27 #include "common/events.h" 28 #include "sound/mixer.h" 29 30 #include "groovie/groovie.h" 31 #include "groovie/music.h" 32 #include "groovie/roq.h" 33 #include "groovie/vdx.h" 34 35 namespace Groovie { 36 37 GroovieEngine::GroovieEngine(OSystem *syst, GroovieGameDescription *gd) : 38 Engine(syst), _gameDescription(gd), _debugger(NULL), _script(this), 39 _resMan(NULL), _cursorMan(NULL), _videoPlayer(NULL), _musicPlayer(NULL), 40 _graphicsMan(NULL), _waitingForInput(false) { 41 42 // Adding the default directories 43 Common::File::addDefaultDirectory(_gameDataDir.getChild("groovie")); 44 Common::File::addDefaultDirectory(_gameDataDir.getChild("media")); 45 Common::File::addDefaultDirectory(_gameDataDir.getChild("system")); 46 47 // Initialize the custom debug levels 48 Common::addSpecialDebugLevel(kGroovieDebugAll, "All", "Debug everything"); 49 Common::addSpecialDebugLevel(kGroovieDebugVideo, "Video", "Debug video and audio playback"); 50 Common::addSpecialDebugLevel(kGroovieDebugResource, "Resource", "Debug resouce management"); 51 Common::addSpecialDebugLevel(kGroovieDebugScript, "Script", "Debug the scripts"); 52 Common::addSpecialDebugLevel(kGroovieDebugUnknown, "Unknown", "Report values of unknown data in files"); 53 Common::addSpecialDebugLevel(kGroovieDebugHotspots, "Hotspots", "Show the hotspots"); 54 Common::addSpecialDebugLevel(kGroovieDebugCursor, "Cursor", "Debug cursor decompression / switching"); 55 } 56 57 GroovieEngine::~GroovieEngine() { 58 // Delete the remaining objects 59 delete _debugger; 60 delete _resMan; 61 delete _cursorMan; 62 delete _videoPlayer; 63 delete _musicPlayer; 64 delete _graphicsMan; 65 } 66 67 Common::Error GroovieEngine::init() { 68 // Initialize the graphics 69 _system->beginGFXTransaction(); 70 initCommonGFX(true); 71 _system->initSize(640, 480); 72 _system->endGFXTransaction(); 73 74 // Create debugger. It requires GFX to be initialized 75 _debugger = new Debugger(this); 76 _script.setDebugger(_debugger); 77 78 // Create the graphics manager 79 _graphicsMan = new GraphicsMan(this); 80 81 // Create the resource and cursor managers and the video player 82 switch (_gameDescription->version) { 83 case kGroovieT7G: 84 _resMan = new ResMan_t7g(); 85 _cursorMan = new CursorMan_t7g(_system); 86 _videoPlayer = new VDXPlayer(this); 87 break; 88 case kGroovieV2: 89 _resMan = new ResMan_v2(); 90 _cursorMan = new CursorMan_v2(_system); 91 _videoPlayer = new ROQPlayer(this); 92 break; 93 } 94 95 // Create the music player 96 _musicPlayer = new MusicPlayer(this); 97 98 // Load volume levels 99 syncSoundSettings(); 100 101 // Get the name of the main script 102 Common::String filename = _gameDescription->desc.filesDescriptions[0].fileName; 103 if (_gameDescription->version == kGroovieT7G) { 104 // Run The 7th Guest's demo if requested 105 if (ConfMan.hasKey("demo_mode") && ConfMan.getBool("demo_mode")) { 106 filename = Common::String("demo.grv"); 107 } 108 } else if (_gameDescription->version == kGroovieV2) { 109 // Open the disk index 110 Common::File disk; 111 if (!disk.open(filename)) { 112 error("Couldn't open %s", filename.c_str()); 113 return Common::kNoGameDataFoundError; 114 } 115 116 // Search the entry 117 bool found = false; 118 int index = 0; 119 while (!found && !disk.eos()) { 120 Common::String line = disk.readLine(); 121 if (line.hasPrefix("title: ")) { 122 // A new entry 123 index++; 124 } else if (line.hasPrefix("boot: ") && index == _gameDescription->indexEntry) { 125 // It's the boot of the entry were looking for, 126 // get the script filename 127 filename = line.c_str() + 6; 128 found = true; 129 } 130 } 131 132 // Couldn't find the entry 133 if (!found) { 134 error("Couldn't find entry %d in %s", _gameDescription->indexEntry, filename.c_str()); 135 return Common::kUnknownError; 136 } 137 } 138 139 // Check the script file extension 140 if (!filename.hasSuffix(".grv")) { 141 error("%s isn't a valid script filename", filename.c_str()); 142 return Common::kUnknownError; 143 } 144 145 // Load the script 146 if (!_script.loadScript(filename)) { 147 error("Couldn't load the script file %s", filename.c_str()); 148 return Common::kUnknownError; 149 } 150 151 // Should I load a saved game? 152 if (ConfMan.hasKey("save_slot")) { 153 // Get the requested slot 154 int slot = ConfMan.getInt("save_slot"); 155 _script.directGameLoad(slot); 156 } 157 158 return Common::kNoError; 159 } 160 161 Common::Error GroovieEngine::go() { 162 // Check that the game files and the audio tracks aren't together run from 163 // the same cd 164 165 checkCD(); 166 167 // Initialize the CD 168 int cd_num = ConfMan.getInt("cdrom"); 169 if (cd_num >= 0) 170 _system->openCD(cd_num); 171 172 while (!shouldQuit()) { 173 // Show the debugger if required 174 if (_debugger->isAttached()) { 175 _debugger->onFrame(); 176 } 177 178 // If there's still a script error after debugging, end the execution 179 if (_script.haveError()) { 180 quitGame(); 181 break; 182 } 183 184 // Handle input 185 Common::Event ev; 186 while (_eventMan->pollEvent(ev)) { 187 switch (ev.type) { 188 case Common::EVENT_KEYDOWN: 189 // CTRL-D: Attach the debugger 190 if ((ev.kbd.flags & Common::KBD_CTRL) && ev.kbd.keycode == Common::KEYCODE_d) 191 _debugger->attach(); 192 193 // Send the event to the scripts 194 _script.setKbdChar(ev.kbd.ascii); 195 196 // Continue the script execution to handle the key 197 _waitingForInput = false; 198 break; 199 200 case Common::EVENT_MOUSEMOVE: 201 // Continue the script execution, the mouse 202 // pointer may fall inside a hotspot now 203 _waitingForInput = false; 204 break; 205 206 case Common::EVENT_LBUTTONDOWN: 207 // Send the event to the scripts 208 _script.setMouseClick(); 209 210 // Continue the script execution to handle 211 // the click 212 _waitingForInput = false; 213 break; 214 215 case Common::EVENT_QUIT: 216 quitGame(); 217 break; 218 219 default: 220 break; 221 } 222 } 223 224 if (_waitingForInput) { 225 // Still waiting for input, just update the mouse and wait a bit more 226 _cursorMan->animate(); 227 _system->updateScreen(); 228 _system->delayMillis(50); 229 } else if (_graphicsMan->isFading()) { 230 // We're waiting for a fading to end, let the CPU rest 231 // for a while and continue 232 _system->delayMillis(30); 233 } else { 234 // Everything's fine, execute another script step 235 _script.step(); 236 } 237 238 // Update the screen if required 239 _graphicsMan->update(); 240 } 241 242 return Common::kNoError; 243 } 244 245 bool GroovieEngine::hasFeature(EngineFeature f) const { 246 return 247 (f == kSupportsRTL) || 248 (f == kSupportsLoadingDuringRuntime); 249 } 250 251 void GroovieEngine::syncSoundSettings() { 252 _musicPlayer->setUserVolume(ConfMan.getInt("music_volume")); 253 _mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, ConfMan.getInt("speech_volume")); 254 } 255 256 bool GroovieEngine::canLoadGameStateCurrently() { 257 // TODO: verify the engine has been initialized 258 return true; 259 } 260 261 Common::Error GroovieEngine::loadGameState(int slot) { 262 _script.directGameLoad(slot); 263 264 // TODO: Use specific error codes 265 return Common::kNoError; 266 } 267 268 void GroovieEngine::waitForInput() { 269 _waitingForInput = true; 270 } 271 272 } // End of namespace Groovie -
engines/groovie/module.mk
1 MODULE := engines/groovie 2 3 MODULE_OBJS := \ 4 cursor.o \ 5 debug.o \ 6 detection.o \ 7 font.o \ 8 graphics.o \ 9 groovie.o \ 10 jpeg.o \ 11 lzss.o \ 12 music.o \ 13 player.o \ 14 resource.o \ 15 roq.o \ 16 script.o \ 17 vdx.o 18 19 # This module can be built as a plugin 20 ifeq ($(ENABLE_GROOVIE), DYNAMIC_PLUGIN) 21 PLUGIN := 1 22 endif 23 24 # Include common rules 25 include $(srcdir)/rules.mk -
engines/groovie/font.h
1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 * $URL$ 22 * $Id$ 23 * 24 */ 25 26 #ifndef GROOVIE_FONT_H 27 #define GROOVIE_FONT_H 28 29 #include "common/stream.h" 30 #include "common/system.h" 31 32 namespace Groovie { 33 34 class Font { 35 public: 36 Font(OSystem *syst); 37 ~Font(); 38 void printstring(char *messagein); 39 40 private: 41 OSystem *_syst; 42 Common::MemoryReadStream *_sphinxfnt; 43 44 uint16 letteroffset(char letter); 45 uint8 letterwidth(char letter); 46 uint8 letterheight(char letter); 47 uint8 printletter(char letter, uint16 xoffset); 48 }; 49 50 } // End of Groovie namespace 51 52 #endif // GROOVIE_FONT_H -
engines/groovie/cursor.cpp
1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 * $URL$ 22 * $Id$ 23 * 24 */ 25 26 #include "groovie/cursor.h" 27 #include "groovie/groovie.h" 28 29 namespace Groovie { 30 31 // Cursor Manager 32 33 CursorMan::CursorMan(OSystem *system) : 34 _syst(system), _lastTime(0), _cursor(NULL) { 35 } 36 37 CursorMan::~CursorMan() { 38 // Delete the cursors 39 for (uint cursor = 0; cursor < _cursors.size(); cursor++) { 40 delete _cursors[cursor]; 41 } 42 } 43 44 uint8 CursorMan::getStyle() { 45 return _current; 46 } 47 48 void CursorMan::setStyle(uint8 newStyle) { 49 // Reset the animation 50 _lastFrame = 254; 51 _lastTime = 1; 52 53 // Save the new cursor 54 _current = newStyle; 55 _cursor = _cursors[newStyle]; 56 57 // Show the first frame 58 _cursor->enable(); 59 animate(); 60 } 61 62 void CursorMan::animate() { 63 if (_lastTime) { 64 int newTime = _syst->getMillis(); 65 if (_lastTime - newTime >= 75) { 66 _lastFrame++; 67 _lastFrame %= _cursor->getFrames(); 68 _cursor->showFrame(_lastFrame); 69 _lastTime = _syst->getMillis(); 70 } 71 } 72 } 73 74 75 // t7g Cursor 76 77 class Cursor_t7g : public Cursor { 78 public: 79 Cursor_t7g(OSystem *system, uint8 *img, uint8 *pal); 80 81 void enable(); 82 void showFrame(uint16 frame); 83 84 private: 85 OSystem *_syst; 86 byte *_img; 87 byte *_pal; 88 }; 89 90 Cursor_t7g::Cursor_t7g(OSystem *system, uint8 *img, uint8 *pal) : 91 _syst(system), _pal(pal) { 92 93 _width = img[0]; 94 _height = img[1]; 95 _numFrames = img[2]; 96 uint8 elinor1 = img[3]; 97 uint8 elinor2 = img[4]; 98 99 _img = img + 5; 100 101 debugC(1, kGroovieDebugCursor | kGroovieDebugAll, "Groovie::Cursor: width: %d, height: %d, frames:%d", _width, _height, _numFrames); 102 debugC(1, kGroovieDebugCursor | kGroovieDebugUnknown | kGroovieDebugAll, "Groovie::Cursor: elinor: 0x%02X (%d), 0x%02X (%d)", elinor1, elinor1, elinor2, elinor2); 103 } 104 105 void Cursor_t7g::enable() { 106 // Apply the palette 107 _syst->setCursorPalette(_pal, 0, 32); 108 } 109 110 void Cursor_t7g::showFrame(uint16 frame) { 111 // Set the mouse cursor 112 int offset = _width * _height * frame; 113 _syst->setMouseCursor((const byte *)_img + offset, _width, _height, _width >> 1, _height >> 1, 0); 114 } 115 116 117 // t7g Cursor Manager 118 119 #define NUM_IMGS 9 120 static const uint16 cursorDataOffsets[NUM_IMGS] = { 121 0x0000, 0x182f, 0x3b6d, 0x50cc, 0x6e79, 0x825d, 0x96d7, 0xa455, 0xa776 122 }; 123 124 #define NUM_PALS 7 125 //Pals: 0xb794, 0xb7f4, 0xb854, 0xb8b4, 0xb914, 0xb974, 0xb9d4 126 127 #define NUM_STYLES 11 128 // pyramid is cursor 8, eyes are 9 & 10 129 const uint CursorMan_t7g::_cursorImg[NUM_STYLES] = {3, 5, 4, 3, 1, 0, 2, 6, 7, 8, 8}; 130 const uint CursorMan_t7g::_cursorPal[NUM_STYLES] = {0, 0, 0, 0, 2, 0, 1, 3, 5, 4, 6}; 131 132 CursorMan_t7g::CursorMan_t7g(OSystem *system) : 133 CursorMan(system) { 134 135 // Open the cursors file 136 Common::File robgjd; 137 if (!robgjd.open("rob.gjd")) { 138 error("Groovie::Cursor: Couldn't open rob.gjd"); 139 return; 140 } 141 142 // Load the images 143 for (uint imgnum = 0; imgnum < NUM_IMGS; imgnum++) { 144 robgjd.seek(cursorDataOffsets[imgnum]); 145 _images.push_back(loadImage(robgjd)); 146 } 147 148 // Load the palettes 149 robgjd.seek(-0x60 * NUM_PALS, SEEK_END); 150 for (uint palnum = 0; palnum < NUM_PALS; palnum++) { 151 _palettes.push_back(loadPalette(robgjd)); 152 } 153 154 // Build the cursors 155 for (uint cursor = 0; cursor < NUM_STYLES; cursor++) { 156 Cursor *s = new Cursor_t7g(_syst, _images[_cursorImg[cursor]], _palettes[_cursorPal[cursor]]); 157 _cursors.push_back(s); 158 } 159 160 robgjd.close(); 161 } 162 163 CursorMan_t7g::~CursorMan_t7g() { 164 // Delete the images 165 for (uint img = 0; img < _images.size(); img++) { 166 delete[] _images[img]; 167 } 168 169 // Delete the palettes 170 for (uint pal = 0; pal < _palettes.size(); pal++) { 171 delete[] _palettes[pal]; 172 } 173 } 174 175 byte *CursorMan_t7g::loadImage(Common::File &file) { 176 uint16 decompbytes = 0, offset, i, length; 177 uint8 flagbyte, lengthmask = 0x0F, offsetlen, var_8; 178 byte *cursorStorage = new byte[65536]; 179 uint8 *runningcursor = cursorStorage; 180 181 bool finished = false; 182 while (!(finished || file.eos())) { 183 flagbyte = file.readByte(); 184 for (i = 1; i <= 8; i++) { 185 if (!file.eos()) { 186 if (flagbyte & 1) { 187 *(runningcursor++) = file.readByte(); 188 decompbytes++; 189 } else { 190 var_8 = file.readByte(); 191 offsetlen = file.readByte(); 192 if (var_8 == 0 && offsetlen == 0) { 193 finished = true; 194 break; 195 } 196 length = (offsetlen & lengthmask) + 3; 197 offsetlen >>= 4; 198 offset = (offsetlen << 8) + var_8; 199 decompbytes += length; 200 201 for (; length > 0; length--, runningcursor++) { 202 *(runningcursor) = *(runningcursor - offset); 203 } 204 } 205 flagbyte = flagbyte >> 1; 206 } 207 } 208 } 209 210 return cursorStorage; 211 } 212 213 byte *CursorMan_t7g::loadPalette(Common::File &file) { 214 byte *palette = new byte[4 * 32]; 215 for (uint8 colournum = 0; colournum < 32; colournum++) { 216 palette[colournum * 4 + 0] = file.readByte(); 217 palette[colournum * 4 + 1] = file.readByte(); 218 palette[colournum * 4 + 2] = file.readByte(); 219 palette[colournum * 4 + 3] = 0; 220 } 221 return palette; 222 } 223 224 225 // v2 Cursor 226 227 class Cursor_v2 : public Cursor { 228 public: 229 Cursor_v2(Common::File &file); 230 231 void enable(); 232 void showFrame(uint16 frame); 233 234 private: 235 //byte *_data; 236 }; 237 238 Cursor_v2::Cursor_v2(Common::File &file) { 239 _numFrames = file.readUint16LE(); 240 _width = file.readUint16LE(); 241 _height = file.readUint16LE(); 242 243 debugC(1, kGroovieDebugCursor | kGroovieDebugAll, "Groovie::Cursor: width: %d, height: %d, frames:%d", _width, _height, _numFrames); 244 245 uint16 tmp16 = file.readUint16LE(); 246 printf("hotspot x?: %d\n", tmp16); 247 tmp16 = file.readUint16LE(); 248 printf("hotspot y?: %d\n", tmp16); 249 int loop2count = file.readUint16LE(); 250 printf("loop2count?: %d\n", loop2count); 251 for (int l = 0; l < loop2count; l++) { 252 tmp16 = file.readUint16LE(); 253 printf("loop2a: %d\n", tmp16); 254 tmp16 = file.readUint16LE(); 255 printf("loop2b: %d\n", tmp16); 256 } 257 258 file.seek(0x20 * 3, SEEK_CUR); 259 260 for (int f = 0; f < _numFrames; f++) { 261 uint32 tmp32 = file.readUint32LE(); 262 printf("loop3: %d\n", tmp32); 263 264 //file.seek(tmp32, SEEK_CUR); 265 byte *data = new byte[tmp32]; 266 file.read(data, tmp32); 267 //Common::hexdump(data, tmp32); 268 delete[] data; 269 } 270 } 271 272 void Cursor_v2::enable() { 273 } 274 275 void Cursor_v2::showFrame(uint16 frame) { 276 } 277 278 279 // v2 Cursor Manager 280 281 CursorMan_v2::CursorMan_v2(OSystem *system) : 282 CursorMan(system) { 283 284 // Open the icons file 285 Common::File iconsFile; 286 if (!iconsFile.open("icons.ph")) { 287 error("Groovie::Cursor: Couldn't open icons.ph"); 288 return; 289 } 290 291 // Verify the signature 292 uint32 tmp32 = iconsFile.readUint32LE(); 293 uint16 tmp16 = iconsFile.readUint16LE(); 294 if (tmp32 != 0x6e6f6369 || tmp16 != 1) { 295 error("Groovie::Cursor: icons.ph signature failed: %04X %d", tmp32, tmp16); 296 return; 297 } 298 299 // Read the number of icons 300 uint16 nicons = iconsFile.readUint16LE(); 301 302 // Read the icons 303 for (int i = 0; i < nicons; i++) { 304 Cursor *s = new Cursor_v2(iconsFile); 305 _cursors.push_back(s); 306 } 307 308 iconsFile.close(); 309 } 310 311 CursorMan_v2::~CursorMan_v2() { 312 } 313 314 } // End of Groovie namespace -
engines/groovie/detection.cpp
1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/engines/groovie/detection.cpp $ 22 * $Id: detection.cpp 28132 2007-07-17 22:29:09Z aquadran $ 23 * 24 */ 25 26 #include "common/savefile.h" 27 28 #include "groovie/groovie.h" 29 30 namespace Groovie { 31 32 //#define GROOVIE_EXPERIMENTAL 33 34 static const PlainGameDescriptor groovieGames[] = { 35 // Games 36 {"t7g", "The 7th Guest"}, 37 38 #ifdef GROOVIE_EXPERIMENTAL 39 {"11h", "The 11th Hour: The sequel to The 7th Guest"}, 40 {"clandestiny", "Clandestiny"}, 41 {"unclehenry", "Uncle Henry's Playhouse"}, 42 {"tlc", "Tender Loving Care"}, 43 44 // Extras 45 {"making11h", "The Making of The 11th Hour"}, 46 {"clantrailer", "Clandestiny Trailer"}, 47 #endif 48 49 // Unknown 50 {"groovie", "Groovie engine game"}, 51 {0, 0} 52 }; 53 54 static const GroovieGameDescription gameDescriptions[] = { 55 56 // The 7th Guest DOS English 57 { 58 { 59 "t7g", "", 60 AD_ENTRY1s("script.grv", "d1b8033b40aa67c076039881eccce90d", 16659), 61 Common::EN_ANY, Common::kPlatformPC, Common::ADGF_NO_FLAGS 62 }, 63 kGroovieT7G, 0 64 }, 65 66 // The 7th Guest Mac English 67 { 68 { 69 "t7g", "", 70 AD_ENTRY1s("script.grv", "6e30b54b1f3bc2262cdcf7961db2ae67", 17191), 71 Common::EN_ANY, Common::kPlatformMacintosh, Common::ADGF_NO_FLAGS 72 }, 73 kGroovieT7G, 0 74 }, 75 76 #ifdef GROOVIE_EXPERIMENTAL 77 // The 11th Hour DOS English 78 { 79 { 80 "11h", "", 81 AD_ENTRY1s("disk.1", "5c0428cd3659fc7bbcd0aa16485ed5da", 227), 82 Common::EN_ANY, Common::kPlatformPC, Common::ADGF_NO_FLAGS 83 }, 84 kGroovieV2, 1 85 }, 86 87 // The Making of The 11th Hour DOS English 88 { 89 { 90 "making11h", "", 91 AD_ENTRY1s("disk.1", "5c0428cd3659fc7bbcd0aa16485ed5da", 227), 92 Common::EN_ANY, Common::kPlatformPC, Common::ADGF_NO_FLAGS 93 }, 94 kGroovieV2, 2 95 }, 96 97 // Clandestiny Trailer DOS English 98 { 99 { 100 "clantrailer", "", 101 AD_ENTRY1s("disk.1", "5c0428cd3659fc7bbcd0aa16485ed5da", 227), 102 Common::EN_ANY, Common::kPlatformPC, Common::ADGF_NO_FLAGS 103 }, 104 kGroovieV2, 3 105 }, 106 107 // Clandestiny DOS English 108 { 109 { 110 "clandestiny", "", 111 AD_ENTRY1s("disk.1", "f79fc1515174540fef6a34132efc4c53", 76), 112 Common::EN_ANY, Common::kPlatformPC, Common::ADGF_NO_FLAGS 113 }, 114 kGroovieV2, 1 115 }, 116 117 // Uncle Henry's Playhouse PC English 118 { 119 { 120 "unclehenry", "", 121 AD_ENTRY1s("disk.1", "0e1b1d3cecc4fc7efa62a968844d1f7a", 72), 122 Common::EN_ANY, Common::kPlatformPC, Common::ADGF_NO_FLAGS 123 }, 124 kGroovieV2, 1 125 }, 126 127 // Tender Loving Care PC English 128 { 129 { 130 "tlc", "", 131 AD_ENTRY1s("disk.1", "32a1afa68478f1f9d2b25eeea427f2e3", 84), 132 Common::EN_ANY, Common::kPlatformPC, Common::ADGF_NO_FLAGS 133 }, 134 kGroovieV2, 1 135 }, 136 #endif 137 138 {AD_TABLE_END_MARKER, kGroovieT7G, 0} 139 }; 140 141 static const Common::ADParams detectionParams = { 142 // Pointer to ADGameDescription or its superset structure 143 (const byte *)gameDescriptions, 144 // Size of that superset structure 145 sizeof(GroovieGameDescription), 146 // Number of bytes to compute MD5 sum for 147 5000, 148 // List of all engine targets 149 groovieGames, 150 // Structure for autoupgrading obsolete targets 151 0, 152 // Name of single gameid (optional) 153 0, 154 // List of files for file-based fallback detection (optional) 155 0, 156 // Flags 157 0 158 }; 159 160 161 class GroovieMetaEngine : public Common::AdvancedMetaEngine { 162 public: 163 GroovieMetaEngine() : Common::AdvancedMetaEngine(detectionParams) {} 164 165 const char *getName() const { 166 return "Groovie Engine"; 167 } 168 169 const char *getCopyright() const { 170 return "Groovie Engine (C) 1990-1996 Trilobyte"; 171 } 172 173 bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *gd) const; 174 175 bool hasFeature(MetaEngineFeature f) const; 176 SaveStateList listSaves(const char *target) const; 177 void removeSaveState(const char *target, int slot) const; 178 }; 179 180 bool GroovieMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *gd) const { 181 if (gd) { 182 *engine = new GroovieEngine(syst, (GroovieGameDescription *)gd); 183 } 184 return gd != 0; 185 } 186 187 bool GroovieMetaEngine::hasFeature(MetaEngineFeature f) const { 188 return 189 (f == kSupportsListSaves) || 190 (f == kSupportsLoadingDuringStartup) || 191 (f == kSupportsDeleteSave); 192 //(f == kSavesSupportCreationDate) 193 } 194 195 SaveStateList GroovieMetaEngine::listSaves(const char *target) const { 196 Common::SaveFileManager *sfm = g_system->getSavefileManager(); 197 SaveStateList list; 198 199 // Get the list of savefiles 200 Common::String pattern = Common::String(target) + ".00?"; 201 Common::StringList savefiles = sfm->listSavefiles(pattern.c_str()); 202 203 // Sort the list of filenames 204 sort(savefiles.begin(), savefiles.end()); 205 206 // Fill the information for the existing savegames 207 Common::StringList::iterator it = savefiles.begin(); 208 while (it != savefiles.end()) { 209 int slot = it->lastChar() - '0'; 210 if (slot >= 0 && slot <= 9) { 211 Common::InSaveFile *file = sfm->openForLoading(it->c_str()); 212 213 // Read the savegame description 214 Common::String description; 215 unsigned char c = 1; 216 for (int i = 0; (c != 0) && (i < 15); i++) { 217 c = file->readByte(); 218 switch (c) { 219 case 0: 220 break; 221 case 16: // @ 222 c = ' '; 223 break; 224 case 244: // $ 225 c = 0; 226 break; 227 default: 228 c += 0x30; 229 } 230 if (c != 0) { 231 description += c; 232 } 233 } 234 delete file; 235 236 list.push_back(SaveStateDescriptor(slot, description)); 237 } 238 it++; 239 } 240 241 return list; 242 } 243 244 void GroovieMetaEngine::removeSaveState(const char *target, int slot) const { 245 if (slot < 0 || slot > 9) { 246 // Invalid slot, do nothing 247 return; 248 } 249 250 char extension[6]; 251 snprintf(extension, sizeof(extension), ".00%01d", slot); 252 253 Common::String filename = target; 254 filename += extension; 255 256 g_system->getSavefileManager()->removeSavefile(filename.c_str()); 257 } 258 259 } // End of namespace Groovie 260 261 #if PLUGIN_ENABLED_DYNAMIC(GROOVIE) 262 REGISTER_PLUGIN_DYNAMIC(GROOVIE, PLUGIN_TYPE_ENGINE, Groovie::GroovieMetaEngine); 263 #else 264 REGISTER_PLUGIN_STATIC(GROOVIE, PLUGIN_TYPE_ENGINE, Groovie::GroovieMetaEngine); 265 #endif -
engines/groovie/groovie.h
1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 * $URL$ 22 * $Id$ 23 * 24 */ 25 26 #ifndef GROOVIE_H 27 #define GROOVIE_H 28 29 #include "common/advancedDetector.h" 30 #include "engines/engine.h" 31 #include "graphics/surface.h" 32 33 #include "groovie/cursor.h" 34 #include "groovie/debug.h" 35 #include "groovie/graphics.h" 36 #include "groovie/player.h" 37 #include "groovie/resource.h" 38 #include "groovie/script.h" 39 40 namespace Groovie { 41 42 class MusicPlayer; 43 44 enum kDebugLevels { 45 kGroovieDebugAll = 1 << 0, 46 kGroovieDebugVideo = 1 << 1, 47 kGroovieDebugResource = 1 << 2, 48 kGroovieDebugScript = 1 << 3, 49 kGroovieDebugUnknown = 1 << 4, 50 kGroovieDebugHotspots = 1 << 5, 51 kGroovieDebugCursor = 1 << 6 52 // the current limitation is 32 debug levels (1 << 31 is the last one) 53 }; 54 55 enum kEngineVersion { 56 kGroovieT7G, 57 kGroovieV2 58 }; 59 60 struct GroovieGameDescription { 61 Common::ADGameDescription desc; 62 63 kEngineVersion version; // Version of the engine 64 int indexEntry; // The index of the entry in disk.1 for V2 games 65 }; 66 67 class GroovieEngine : public Engine { 68 public: 69 GroovieEngine(OSystem *syst, GroovieGameDescription *gd); 70 ~GroovieEngine(); 71 72 protected: 73 Common::Error init(); 74 Common::Error go(); 75 76 public: 77 bool hasFeature(EngineFeature f) const; 78 79 bool canLoadGameStateCurrently(); 80 Common::Error loadGameState(int slot); 81 void syncSoundSettings(); 82 83 Debugger *getDebugger() { return _debugger; } 84 85 void waitForInput(); 86 87 Script _script; 88 ResMan *_resMan; 89 CursorMan *_cursorMan; 90 VideoPlayer *_videoPlayer; 91 MusicPlayer *_musicPlayer; 92 GraphicsMan *_graphicsMan; 93 94 private: 95 GroovieGameDescription *_gameDescription; 96 Debugger *_debugger; 97 bool _waitingForInput; 98 }; 99 100 } // End of namespace Groovie 101 102 #endif // GROOVIE_H -
engines/groovie/music.cpp
1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 * $URL$ 22 * $Id$ 23 * 24 */ 25 26 #include "groovie/music.h" 27 #include "groovie/resource.h" 28 29 namespace Groovie { 30 31 MusicPlayer::MusicPlayer(GroovieEngine *vm) : 32 _vm(vm), _midiParser(NULL), _data(NULL), _driver(NULL), 33 _backgroundFileRef(0) { 34 // Create the parser 35 _midiParser = MidiParser::createParser_XMIDI(); 36 37 // Create the driver 38 int driver = detectMusicDriver(MDT_MIDI | MDT_ADLIB | MDT_PREFER_MIDI); 39 _driver = createMidi(driver); 40 _driver->open(); 41 42 // Initialize the channel volumes 43 for (int i = 0; i < 0x10; i++) { 44 _chanVolumes[i] = 0x7F; 45 } 46 47 // Set the parser's driver 48 _midiParser->setMidiDriver(this); 49 50 // Set the timer rate 51 _midiParser->setTimerRate(_driver->getBaseTempo()); 52 } 53 54 MusicPlayer::~MusicPlayer() { 55 // Unload the parser 56 unload(); 57 delete _midiParser; 58 59 // Unload the MIDI Driver 60 _driver->close(); 61 delete _driver; 62 } 63 64 void MusicPlayer::playSong(uint16 fileref) { 65 // Play the referenced file once 66 play(fileref, false); 67 } 68 69 void MusicPlayer::setBackgroundSong(uint16 fileref) { 70 _backgroundFileRef = fileref; 71 } 72 73 void MusicPlayer::setUserVolume(uint16 volume) { 74 // Save the new user volume 75 _userVolume = volume; 76 if (_userVolume > 0x100) _userVolume = 0x100; 77 78 // Apply it to all the channels 79 for (int i = 0; i < 0x10; i++) { 80 updateChanVolume(i); 81 } 82 //FIXME: AdlibPercussionChannel::controlChange() is empty 83 //(can't set the volume for the percusion channel) 84 } 85 86 void MusicPlayer::setGameVolume(uint16 volume, uint16 time) { 87 //TODO: Implement volume fading 88 printf("setting game volume: %d, %d\n", volume, time); 89 90 // Save the new game volume 91 _gameVolume = volume; 92 if (_gameVolume > 100) _gameVolume = 100; 93 94 // Apply it to all the channels 95 for (int i = 0; i < 0x10; i++) { 96 updateChanVolume(i); 97 } 98 } 99 100 void MusicPlayer::updateChanVolume(byte channel) { 101 // Generate a MIDI Control change message for the volume 102 uint32 b = 0x7B0; 103 104 // Specify the channel 105 b |= (channel & 0xF); 106 107 // Scale by the user and game volumes 108 uint32 val = (_chanVolumes[channel] * _userVolume * _gameVolume) / 0x100 / 100; 109 val &= 0x7F; 110 111 // Send it to the driver 112 _driver->send(b | (val << 16)); 113 } 114 115 bool MusicPlayer::play(uint16 fileref, bool loop) { 116 // Unload the previous song 117 unload(); 118 119 // Set the looping option 120 _midiParser->property(MidiParser::mpAutoLoop, loop); 121 122 // Load the new file 123 return load(fileref); 124 } 125 126 bool MusicPlayer::load(uint16 fileref) { 127 // Open the song resource 128 Common::SeekableReadStream *xmidiFile = _vm->_resMan->open(fileref); 129 if (!xmidiFile) { 130 error("Groovie::Music: Couldn't resource 0x%04X", fileref); 131 return false; 132 } 133 134 // Read the whole file to memory 135 int length = xmidiFile->size(); 136 _data = new byte[length]; 137 xmidiFile->read(_data, length); 138 delete xmidiFile; 139 140 // Start parsing the data 141 if (!_midiParser->loadMusic(_data, length)) { 142 error("Groovie::Music: Invalid XMI file"); 143 return false; 144 } 145 146 // Activate the timer source 147 _driver->setTimerCallback(_midiParser, MidiParser::timerCallback); 148 149 return true; 150 } 151 152 void MusicPlayer::unload() { 153 // Unload the parser 154 _midiParser->unloadMusic(); 155 156 // Unload the xmi file 157 delete[] _data; 158 _data = NULL; 159 } 160 161 int MusicPlayer::open() { 162 return 0; 163 } 164 165 void MusicPlayer::close() {} 166 167 void MusicPlayer::send(uint32 b) { 168 if ((b & 0xFFF0) == 0x07B0) { // Volume change 169 // Save the specific channel volume 170 byte chan = b & 0xF; 171 _chanVolumes[chan] = (b >> 16) & 0x7F; 172 173 // Send the updated value 174 updateChanVolume(chan); 175 176 return; 177 } 178 _driver->send(b); 179 } 180 181 void MusicPlayer::metaEvent(byte type, byte *data, uint16 length) { 182 switch (type) { 183 case 0x2F: 184 // End of Track, play the background song 185 if (_backgroundFileRef) { 186 play(_backgroundFileRef, true); 187 } 188 break; 189 default: 190 _driver->metaEvent(type, data, length); 191 break; 192 } 193 } 194 195 void MusicPlayer::setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc) { 196 _driver->setTimerCallback(timer_param, timer_proc); 197 } 198 199 uint32 MusicPlayer::getBaseTempo(void) { 200 return _driver->getBaseTempo(); 201 } 202 203 MidiChannel *MusicPlayer::allocateChannel() { 204 return _driver->allocateChannel(); 205 } 206 207 MidiChannel *MusicPlayer::getPercussionChannel() { 208 return _driver->getPercussionChannel(); 209 } 210 211 } // End of Groovie namespace -
engines/groovie/cursor.h
1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 * $URL$ 22 * $Id$ 23 * 24 */ 25 26 #ifndef GROOVIE_CURSOR_H 27 #define GROOVIE_CURSOR_H 28 29 #include "common/system.h" 30 #include "common/file.h" 31 32 namespace Groovie { 33 34 class Cursor { 35 public: 36 virtual ~Cursor() {} 37 uint16 getFrames() { return _numFrames; } 38 virtual void enable() = 0; 39 virtual void showFrame(uint16 frame) = 0; 40 41 protected: 42 uint16 _width; 43 uint16 _height; 44 uint16 _numFrames; 45 }; 46 47 class CursorMan { 48 public: 49 CursorMan(OSystem *system); 50 virtual ~CursorMan(); 51 52 virtual void animate(); 53 virtual void setStyle(uint8 newStyle); 54 virtual uint8 getStyle(); 55 56 protected: 57 OSystem *_syst; 58 59 // Animation variables 60 uint8 _lastFrame; 61 uint32 _lastTime; 62 63 // Styles 64 Common::Array<Cursor *> _cursors; 65 uint8 _current; 66 Cursor *_cursor; 67 }; 68 69 class CursorMan_t7g : public CursorMan { 70 public: 71 CursorMan_t7g(OSystem *system); 72 ~CursorMan_t7g(); 73 74 private: 75 // Styles data 76 static const uint _cursorImg[]; 77 static const uint _cursorPal[]; 78 79 // Cursors data 80 Common::Array<byte *> _images; 81 Common::Array<byte *> _palettes; 82 83 // Loading functions 84 byte *loadImage(Common::File &file); 85 byte *loadPalette(Common::File &file); 86 }; 87 88 class CursorMan_v2 : public CursorMan { 89 public: 90 CursorMan_v2(OSystem *system); 91 ~CursorMan_v2(); 92 }; 93 94 } // End of Groovie namespace 95 96 #endif // GROOVIE_CURSOR_H -
engines/groovie/music.h
1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 * $URL$ 22 * $Id$ 23 * 24 */ 25 26 #ifndef GROOVIE_MUSIC_H 27 #define GROOVIE_MUSIC_H 28 29 #include "groovie/groovie.h" 30 31 #include "sound/mididrv.h" 32 #include "sound/midiparser.h" 33 34 namespace Groovie { 35 36 class MusicPlayer : public MidiDriver { 37 public: 38 MusicPlayer(GroovieEngine *vm); 39 ~MusicPlayer(); 40 void playSong(uint16 fileref); 41 void setBackgroundSong(uint16 fileref); 42 43 // Volume 44 void setUserVolume(uint16 volume); 45 void setGameVolume(uint16 volume, uint16 time); 46 private: 47 uint16 _userVolume; 48 uint16 _gameVolume; 49 byte _chanVolumes[0x10]; 50 void updateChanVolume(byte channel); 51 52 public: 53 // MidiDriver interface 54 int open(); 55 void close(); 56 void send(uint32 b); 57 void metaEvent(byte type, byte *data, uint16 length); 58 void setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc); 59 uint32 getBaseTempo(void); 60 MidiChannel *allocateChannel(); 61 MidiChannel *getPercussionChannel(); 62 63 private: 64 GroovieEngine *_vm; 65 byte *_data; 66 MidiParser *_midiParser; 67 MidiDriver *_driver; 68 69 uint16 _backgroundFileRef; 70 71 bool play(uint16 fileref, bool loop); 72 bool load(uint16 fileref); 73 void unload(); 74 }; 75 76 } // End of Groovie namespace 77 78 #endif // GROOVIE_MUSIC_H -
engines/groovie/jpeg.cpp
1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 * $URL$ 22 * $Id$ 23 * 24 */ 25 26 #include "groovie/groovie.h" 27 #include "groovie/jpeg.h" 28 29 #include "common/util.h" 30 31 namespace Groovie { 32 33 // Order used to traverse the quantization tables 34 uint8 JPEG::_zigZagOrder[64] = { 35 0, 1, 8, 16, 9, 2, 3, 10, 36 17, 24, 32, 25, 18, 11, 4, 5, 37 12, 19, 26, 33, 40, 48, 41, 34, 38 27, 20, 13, 6, 7, 14, 21, 28, 39 35, 42, 49, 56, 57, 50, 43, 36, 40 29, 22, 15, 23, 30, 37, 44, 51, 41 58, 59, 52, 45, 38, 31, 39, 46, 42 53, 60, 61, 54, 47, 55, 62, 63 43 }; 44 45 JPEG::JPEG() : 46 _str(NULL), _w(0), _h(0), _numComp(0), _components(NULL), _numScanComp(0), 47 _scanComp(NULL), _currentComp(NULL) { 48 49 // Initialize the quantization tables 50 for (int i = 0; i < JPEG_MAX_QUANT_TABLES; i++) { 51 _quant[i] = NULL; 52 } 53 54 // Initialize the Huffman tables 55 for (int i = 0; i < 2 * JPEG_MAX_HUFF_TABLES; i++) { 56 _huff[i].count = 0; 57 _huff[i].values = NULL; 58 _huff[i].sizes = NULL; 59 _huff[i].codes = NULL; 60 } 61 } 62 63 JPEG::~JPEG() { 64 reset(); 65 } 66 67 void JPEG::reset() { 68 // Reset member variables 69 _str = NULL; 70 _w = _h = 0; 71 72 // Free the components 73 if (_components) { 74 delete[] _components; 75 _components = NULL; 76 } 77 _numComp = 0; 78 79 // Free the scan components 80 if (_scanComp) { 81 delete[] _scanComp; 82 _scanComp = NULL; 83 } 84 _numScanComp = 0; 85 _currentComp = NULL; 86 87 // Free the quantization tables 88 for (int i = 0; i < JPEG_MAX_QUANT_TABLES; i++) { 89 if (_quant[i]) { 90 delete[] _quant[i]; 91 _quant[i] = NULL; 92 } 93 } 94 95 // Free the Huffman tables 96 for (int i = 0; i < 2 * JPEG_MAX_HUFF_TABLES; i++) { 97 _huff[i].count = 0; 98 if (_huff[i].values) { 99 delete[] _huff[i].values; 100 _huff[i].values = NULL; 101 } 102 if (_huff[i].sizes) { 103 delete[] _huff[i].sizes; 104 _huff[i].sizes = NULL; 105 } 106 if (_huff[i].codes) { 107 delete[] _huff[i].codes; 108 _huff[i].codes = NULL; 109 } 110 } 111 } 112 113 bool JPEG::read(Common::ReadStream *str) { 114 // Reset member variables and tables from previous reads 115 reset(); 116 117 // Save the input stream 118 _str = str; 119 120 bool ok = true; 121 while (!_str->eos() && ok) { 122 // Read the marker 123 uint16 marker = _str->readByte(); 124 if (marker != 0xFF) { 125 error("Groovie::JPEG: Invalid marker[0]: 0x%02X", marker); 126 ok = false; 127 break; 128 } 129 while (marker == 0xFF) { 130 marker = _str->readByte(); 131 } 132 133 // Process the marker data 134 switch (marker) { 135 case 0xC0: // Start Of Frame 136 ok = readSOF0(); 137 break; 138 case 0xC4: // Define Huffman Tables 139 ok = readDHT(); 140 break; 141 case 0xD8: // Start Of Image 142 case 0xD9: // End Of Image 143 break; 144 case 0xDA: // Start Of Scan 145 ok = readSOS(); 146 break; 147 case 0xDB: // Define Quantization Tables 148 ok = readDQT(); 149 break; 150 default: { // Unknown marker 151 uint16 size = _str->readUint16BE(); 152 warning("Groovie::JPEG: Unknown marker %02X, skipping %d bytes", marker, size); 153 for (int i = 2; i < size; i++) { 154 _str->readByte(); 155 } 156 } 157 } 158 } 159 return ok; 160 } 161 162 // Marker 0xC0 (Start Of Frame, Baseline DCT) 163 bool JPEG::readSOF0() { 164 debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::JPEG: readSOF0"); 165 uint16 size = _str->readUint16BE(); 166 167 // Read the sample precision 168 uint8 precision = _str->readByte(); 169 if (precision != 8) { 170 warning("Groovie::JPEG: Just 8 bit precision supported at the moment"); 171 return false; 172 } 173 174 // Image size 175 _h = _str->readUint16BE(); 176 _w = _str->readUint16BE(); 177 178 // Number of components 179 _numComp = _str->readByte(); 180 if (size != 8 + 3 * _numComp) { 181 warning("Groovie::JPEG: Invalid number of components"); 182 return false; 183 } 184 185 // Allocate the new components 186 if (_components) { 187 delete[] _components; 188 } 189 _components = new Component[_numComp]; 190 191 // Read the components details 192 for (int c = 0; c < _numComp; c++) { 193 _components[c].id = _str->readByte(); 194 _components[c].factorH = _str->readByte(); 195 _components[c].factorV = _components[c].factorH & 0xF; 196 _components[c].factorH >>= 4; 197 _components[c].quantTableSelector = _str->readByte(); 198 } 199 200 return true; 201 } 202 203 // Marker 0xC4 (Define Huffman Tables) 204 bool JPEG::readDHT() { 205 debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::JPEG: readDHT"); 206 uint16 size = _str->readUint16BE(); 207 208 // Read the table type and id 209 uint8 tableId = _str->readByte(); 210 uint8 tableType = tableId >> 4; // type 0: DC, 1: AC 211 tableId &= 0xF; 212 uint8 tableNum = (tableId << 1) + tableType; 213 214 // Free the Huffman table 215 if (_huff[tableNum].values) { 216 delete[] _huff[tableNum].values; 217 _huff[tableNum].values = NULL; 218 } 219 if (_huff[tableNum].sizes) { 220 delete[] _huff[tableNum].sizes; 221 _huff[tableNum].sizes = NULL; 222 } 223 if (_huff[tableNum].codes) { 224 delete[] _huff[tableNum].codes; 225 _huff[tableNum].codes = NULL; 226 } 227 228 // Read the number of values for each length 229 uint8 numValues[16]; 230 _huff[tableNum].count = 0; 231 for (int len = 0; len < 16; len++) { 232 numValues[len] = _str->readByte(); 233 _huff[tableNum].count += numValues[len]; 234 } 235 236 // Verify the number of bytes to read 237 if (size != _huff[tableNum].count + 19) { 238 warning("Groovie::JPEG: Invalid number of values in the Huffman table"); 239 return false; 240 } 241 242 // Allocate memory for the current table 243 _huff[tableNum].values = new uint8[_huff[tableNum].count]; 244 _huff[tableNum].sizes = new uint8[_huff[tableNum].count]; 245 _huff[tableNum].codes = new uint16[_huff[tableNum].count]; 246 247 // Read the table contents 248 int cur = 0; 249 for (int len = 0; len < 16; len++) { 250 for (int i = 0; i < numValues[len]; i++) { 251 _huff[tableNum].values[cur] = _str->readByte(); 252 _huff[tableNum].sizes[cur] = len + 1; 253 cur++; 254 } 255 } 256 257 // Fill the table of Huffman codes 258 cur = 0; 259 uint16 curCode = 0; 260 uint8 curCodeSize = _huff[tableNum].sizes[0]; 261 while (cur < _huff[tableNum].count) { 262 // Increase the code size to fit the request 263 while (_huff[tableNum].sizes[cur] != curCodeSize) { 264 curCode <<= 1; 265 curCodeSize++; 266 } 267 268 // Assign the current code 269 _huff[tableNum].codes[cur] = curCode; 270 curCode++; 271 cur++; 272 } 273 274 return true; 275 } 276 277 // Marker 0xDA (Start Of Scan) 278 bool JPEG::readSOS() { 279 debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::JPEG: readSOS"); 280 uint16 size = _str->readUint16BE(); 281 282 // Number of scan components 283 _numScanComp = _str->readByte(); 284 if (size != 6 + 2 * _numScanComp) { 285 warning("Groovie::JPEG: Invalid number of components"); 286 return false; 287 } 288 289 // Allocate the new scan components 290 if (_scanComp) { 291 delete[] _scanComp; 292 } 293 _scanComp = new Component *[_numScanComp]; 294 295 // Reset the maximum sampling factors 296 _maxFactorV = 0; 297 _maxFactorH = 0; 298 299 // Component-specification parameters 300 for (int c = 0; c < _numScanComp; c++) { 301 // Read the desired component id 302 uint8 id = _str->readByte(); 303 304 // Search the component with the specified id 305 bool found = false; 306 for (int i = 0; !found && i < _numComp; i++) { 307 if (_components[i].id == id) { 308 // We found the desired component 309 found = true; 310 311 // Assign the found component to the c'th scan component 312 _scanComp[c] = &_components[i]; 313 } 314 } 315 if (!found) { 316 warning("Groovie::JPEG: Invalid component"); 317 return false; 318 } 319 320 // Read the entropy table selectors 321 _scanComp[c]->DCentropyTableSelector = _str->readByte(); 322 _scanComp[c]->ACentropyTableSelector = _scanComp[c]->DCentropyTableSelector & 0xF; 323 _scanComp[c]->DCentropyTableSelector >>= 4; 324 325 // Calculate the maximum sampling factors 326 if (_scanComp[c]->factorV > _maxFactorV) { 327 _maxFactorV = _scanComp[c]->factorV; 328 } 329 if (_scanComp[c]->factorH > _maxFactorH) { 330 _maxFactorH = _scanComp[c]->factorH; 331 } 332 333 // Initialize the DC predictor 334 _scanComp[c]->DCpredictor = 0; 335 } 336 337 // Start of spectral selection 338 if (_str->readByte() != 0) { 339 warning("Groovie::JPEG: Progressive scanning not supported"); 340 return false; 341 } 342 343 // End of spectral selection 344 if (_str->readByte() != 63) { 345 warning("Groovie::JPEG: Progressive scanning not supported"); 346 return false; 347 } 348 349 // Successive approximation parameters 350 if (_str->readByte() != 0) { 351 warning("Groovie::JPEG: Progressive scanning not supported"); 352 return false; 353 } 354 355 // Entropy coded sequence starts, initialize Huffman decoder 356 _bitsNumber = 0; 357 358 // Read all the scan MCUs 359 uint16 xMCU = _w / (_maxFactorH * 8); 360 uint16 yMCU = _h / (_maxFactorV * 8); 361 bool ok = true; 362 for (int y = 0; ok && (y < yMCU); y++) { 363 for (int x = 0; ok && (x < xMCU); x++) { 364 ok = readMCU(x, y); 365 } 366 } 367 368 return ok; 369 } 370 371 // Marker 0xDB (Define Quantization Tables) 372 bool JPEG::readDQT() { 373 debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::JPEG: readDQT"); 374 uint16 size = _str->readUint16BE(); 375 if (size - 3 != 64) { 376 warning("Groovie::JPEG: (TODO) Trying to define several quantization tables on the same block"); 377 return false; 378 } 379 380 // Read the table precision and id 381 uint8 tableId = _str->readByte(); 382 if (tableId & 0xF0) { 383 // Precision = 1 -> 16 bits per element 384 warning("Groovie::JPEG: Just 8 bit precision supported at the moment"); 385 return false; 386 } 387 388 // Validate the table id 389 tableId &= 0xF; 390 if (tableId > JPEG_MAX_QUANT_TABLES) { 391 warning("Groovie::JPEG: Invalid number of components"); 392 return false; 393 } 394 395 // Create the new table if necessary 396 if (!_quant[tableId]) { 397 _quant[tableId] = new uint8[64]; 398 } 399 400 // Read the table in Zig-Zag order 401 for (int i = 0; i < 64; i++) { 402 _quant[tableId][_zigZagOrder[i]] = _str->readByte(); 403 } 404 405 return true; 406 } 407 408 bool JPEG::readMCU(uint16 xMCU, uint16 yMCU) { 409 bool ok = true; 410 for (int c = 0; ok && (c < _numComp); c++) { 411 // Set the current component 412 _currentComp = _scanComp[c]; 413 414 // Read the data units of the current component 415 for (int y = 0; ok && (y < _scanComp[c]->factorV); y++) { 416 for (int x = 0; ok && (x < _scanComp[c]->factorH); x++) { 417 ok = readDataUnit(xMCU * _scanComp[c]->factorH + x, yMCU * _scanComp[c]->factorV + y); 418 } 419 } 420 } 421 //printf("MCU(%d,%d) ", xMCU, yMCU); 422 423 return ok; 424 } 425 426 bool JPEG::readDataUnit(uint16 x, uint16 y) { 427 // Prepare an empty data array 428 int8 readData[64]; 429 for (int i = 1; i < 64; i++) { 430 readData[i] = 0; 431 } 432 433 // Read the DC component 434 readData[0] = _currentComp->DCpredictor + readDC(); 435 _currentComp->DCpredictor = readData[0]; 436 437 // Read the AC components 438 readAC(readData); 439 440 // Calculate the DCT coefficients from the input sequence 441 uint16 _DCT[64]; 442 for (int i = 0; i < 64; i++) { 443 // Dequantize 444 int16 val = readData[i]; 445 int16 quant = _quant[_currentComp->quantTableSelector][i]; 446 val *= quant; 447 448 // Store the normalized coefficients in the Zig-Zag order 449 _DCT[_zigZagOrder[i]] = val; 450 } 451 452 // TODO: apply the IDCT PAG31 453 454 // Level shift to make the values unsigned 455 for (int i = 0; i < 64; i++) { 456 _DCT[i] += 128; 457 } 458 459 if (_currentComp->id == 1) { 460 // HACK: show the DC luminance! 461 for (int j = 0; j < 8 * _maxFactorV / _currentComp->factorV; j++) { 462 for (int i = 0; i < 8 * _maxFactorH / _currentComp->factorH; i++) { 463 // TODO 464 // paint (x + i, y + j) 465 } 466 } 467 } 468 469 return true; 470 } 471 472 int8 JPEG::readDC() { 473 // DC is type 0 474 uint8 tableNum = _currentComp->DCentropyTableSelector << 1; 475 476 // Get the number of bits to read 477 uint8 numBits = readHuff(tableNum); 478 479 // Read the requested bits 480 return readSignedBits(numBits); 481 } 482 483 void JPEG::readAC(int8 *out) { 484 // AC is type 1 485 uint8 tableNum = (_currentComp->ACentropyTableSelector << 1) + 1; 486 487 // Start reading AC element 1 488 uint8 cur = 1; 489 while (cur < 64) { 490 uint8 s = readHuff(tableNum); 491 uint8 r = s >> 4; 492 s &= 0xF; 493 494 if (s == 0) { 495 if (r == 15) { 496 // Skip 16 values 497 cur += 16; 498 } else { 499 // EOB: end of block 500 cur = 64; 501 } 502 } else { 503 // Skip r values 504 cur += r; 505 506 // Read the next value 507 out[cur] = readSignedBits(s); 508 cur++; 509 } 510 } 511 } 512 513 int16 JPEG::readSignedBits(uint8 numBits) { 514 uint16 ret = 0; 515 if (numBits > 8) error("requested %d bits", numBits); //XXX 516 517 //MSB=0 for negatives, 1 for positives 518 for (int i = 0; i < numBits; i++) { 519 ret = (ret << 1) + readBit(); 520 } 521 522 // TODO: extend sign bits: PAG109 523 524 return ret; 525 } 526 527 // TODO: optimize? 528 uint8 JPEG::readHuff(uint8 table) { 529 bool foundCode = false; 530 uint8 val = 0; 531 532 uint8 cur = 0; 533 uint8 codeSize = 1; 534 uint16 code = readBit(); 535 while (!foundCode) { 536 // Prepare a code of the current size 537 while (codeSize < _huff[table].sizes[cur]) { 538 code = (code << 1) + readBit(); 539 codeSize++; 540 } 541 542 // Compare the codes of the current size 543 while (!foundCode && (codeSize == _huff[table].sizes[cur])) { 544 if (code == _huff[table].codes[cur]) { 545 // Found the code 546 val = _huff[table].values[cur]; 547 foundCode = true; 548 } else { 549 // Continue reading 550 cur++; 551 } 552 } 553 } 554 555 return val; 556 } 557 558 uint8 JPEG::readBit() { 559 // Read a whole byte if necessary 560 if (_bitsNumber == 0) { 561 _bitsData = _str->readByte(); 562 _bitsNumber = 8; 563 564 // Detect markers 565 if (_bitsData == 0xFF) { 566 uint8 byte2 = _str->readByte(); 567 568 // A stuffed 0 validates the previous byte 569 if (byte2 != 0) { 570 if (byte2 == 0xDC) { 571 // DNL marker: Define Number of Lines 572 // TODO: terminate scan 573 printf("DNL marker detected: terminate scan\n"); 574 } else { 575 printf("Error: marker 0x%02X read in entropy data\n", byte2); 576 } 577 } 578 } 579 } 580 _bitsNumber--; 581 582 return (_bitsData & (1 << _bitsNumber)) ? 1 : 0; 583 } 584 585 } // End of Groovie namespace -
engines/groovie/debug.cpp
1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 * $URL$ 22 * $Id$ 23 * 24 */ 25 26 #include "groovie/debug.h" 27 #include "groovie/script.h" 28 #include "groovie/groovie.h" 29 30 namespace Groovie { 31 32 Debugger::Debugger(GroovieEngine *vm) : 33 _vm (vm), _script(&_vm->_script), _syst(_vm->_system) { 34 35 // Register the debugger comands 36 DCmd_Register("step", WRAP_METHOD(Debugger, cmd_step)); 37 DCmd_Register("go", WRAP_METHOD(Debugger, cmd_go)); 38 DCmd_Register("pc", WRAP_METHOD(Debugger, cmd_pc)); 39 DCmd_Register("fg", WRAP_METHOD(Debugger, cmd_fg)); 40 DCmd_Register("bg", WRAP_METHOD(Debugger, cmd_bg)); 41 DCmd_Register("mem", WRAP_METHOD(Debugger, cmd_mem)); 42 DCmd_Register("load", WRAP_METHOD(Debugger, cmd_loadgame)); 43 DCmd_Register("save", WRAP_METHOD(Debugger, cmd_savegame)); 44 DCmd_Register("playref", WRAP_METHOD(Debugger, cmd_playref)); 45 DCmd_Register("dumppal", WRAP_METHOD(Debugger, cmd_dumppal)); 46 } 47 48 Debugger::~Debugger() { 49 Common::clearAllSpecialDebugLevels(); 50 } 51 52 int Debugger::getNumber(const char *arg) { 53 return strtol(arg, (char **)NULL, 0); 54 } 55 56 bool Debugger::cmd_step(int argc, const char **argv) { 57 _script->step(); 58 return true; 59 } 60 61 bool Debugger::cmd_go(int argc, const char **argv) { 62 _script->step(); 63 return false; 64 } 65 66 bool Debugger::cmd_fg(int argc, const char **argv) { 67 _vm->_graphicsMan->updateScreen(&_vm->_graphicsMan->_foreground); 68 return false; 69 } 70 71 bool Debugger::cmd_bg(int argc, const char **argv) { 72 _vm->_graphicsMan->updateScreen(&_vm->_graphicsMan->_background); 73 return false; 74 } 75 76 bool Debugger::cmd_pc(int argc, const char **argv) { 77 if (argc == 2) { 78 int val = getNumber(argv[1]); 79 _script->_currentInstruction = val; 80 } 81 DebugPrintf("pc = 0x%04X\n", _script->_currentInstruction); 82 return true; 83 } 84 85 bool Debugger::cmd_mem(int argc, const char **argv) { 86 if (argc >= 2) { 87 int pos = getNumber(argv[1]); 88 uint8 val; 89 if (argc >= 3) { 90 // Set 91 val = getNumber(argv[2]); 92 _script->_variables[pos] = val; 93 } else { 94 // Get 95 val = _script->_variables[pos]; 96 } 97 DebugPrintf("mem[0x%04X] = 0x%02X\n", pos, val); 98 } else { 99 DebugPrintf("Syntax: mem <addr> [<val>]\n"); 100 } 101 return true; 102 } 103 104 bool Debugger::cmd_loadgame(int argc, const char **argv) { 105 if (argc == 2) { 106 int slot = getNumber(argv[1]); 107 _script->loadgame(slot); 108 } else { 109 DebugPrintf("Syntax: load <slot>\n"); 110 } 111 return true; 112 } 113 114 bool Debugger::cmd_savegame(int argc, const char **argv) { 115 if (argc == 2) { 116 int slot = getNumber(argv[1]); 117 _script->savegame(slot); 118 } else { 119 DebugPrintf("Syntax: save <slot>\n"); 120 } 121 return true; 122 } 123 124 bool Debugger::cmd_playref(int argc, const char **argv) { 125 if (argc == 2) { 126 int ref = getNumber(argv[1]); 127 _script->playvideofromref(ref); 128 } else { 129 DebugPrintf("Syntax: playref <videorefnum>\n"); 130 } 131 return true; 132 } 133 134 bool Debugger::cmd_dumppal(int argc, const char **argv) { 135 uint16 i; 136 byte palettedump[256 * 4]; 137 _syst->grabPalette(palettedump, 0, 256); 138 139 for (i = 0; i < 256; i++) { 140 printf("%3d: %3d,%3d,%3d,%3d\n", i, palettedump[(i * 4)], palettedump[(i * 4) + 1], palettedump[(i * 4) + 2], palettedump[(i * 4) + 3]); 141 DebugPrintf("%3d: %3d,%3d,%3d,%3d\n", i, palettedump[(i * 4)], palettedump[(i * 4) + 1], palettedump[(i * 4) + 2], palettedump[(i * 4) + 3]); 142 } 143 return true; 144 } 145 146 } // End of Groovie namespace -
engines/groovie/resource.cpp
1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 * $URL$ 22 * $Id$ 23 * 24 */ 25 26 #include "groovie/groovie.h" 27 #include "groovie/resource.h" 28 29 namespace Groovie { 30 31 // ResMan 32 33 Common::SeekableReadStream *ResMan::open(uint16 fileRef) { 34 // Get the information about the resource 35 ResInfo resInfo; 36 if (!getResInfo(fileRef, resInfo)) { 37 return NULL; 38 } 39 40 // Do we know the name of the required GJD? 41 if (resInfo.gjd >= _gjds.size()) { 42 error("Groovie::Resource: Unknown GJD %d", resInfo.gjd); 43 return NULL; 44 } 45 46 debugC(1, kGroovieDebugResource | kGroovieDebugAll, "Groovie::Resource: Opening resource 0x%04X (%s, %d, %d)", fileRef, _gjds[resInfo.gjd].c_str(), resInfo.offset, resInfo.size); 47 48 // Does it exist? 49 if (!Common::File::exists(_gjds[resInfo.gjd])) { 50 error("Groovie::Resource: %s not found", _gjds[resInfo.gjd].c_str()); 51 return NULL; 52 } 53 54 // Open the pack file 55 Common::File *gjdFile = new Common::File(); 56 if (!gjdFile->open(_gjds[resInfo.gjd].c_str())) { 57 delete gjdFile; 58 error("Groovie::Resource: Couldn't open %s", _gjds[resInfo.gjd].c_str()); 59 return NULL; 60 } 61 62 // Save the used gjd file (except xmi and gamwav) 63 if (resInfo.gjd < 19) { 64 _lastGjd = resInfo.gjd; 65 } 66 67 // Returning the resource substream 68 return new Common::SeekableSubReadStream(gjdFile, resInfo.offset, resInfo.offset + resInfo.size, true); 69 } 70 71 72 // ResMan_t7g 73 74 static const char t7g_gjds[][0x15] = {"at", "b", "ch", "d", "dr", "fh", "ga", "hdisk", "htbd", "intro", "jhek", "k", "la", "li", "mb", "mc", "mu", "n", "p", "xmi", "gamwav"}; 75 76 ResMan_t7g::ResMan_t7g() { 77 for (int i = 0; i < 0x15; i++) { 78 // Prepare the filename 79 Common::String filename = t7g_gjds[i]; 80 filename += ".gjd"; 81 82 // Append it to the list of GJD files 83 _gjds.push_back(filename); 84 } 85 } 86 87 uint16 ResMan_t7g::getRef(Common::String name, Common::String scriptname) { 88 // Get the name of the RL file 89 Common::String rlFileName(t7g_gjds[_lastGjd]); 90 rlFileName += ".rl"; 91 92 // Open the RL file 93 Common::File rlFile; 94 if (!rlFile.open(rlFileName)) { 95 error("Groovie::Resource: Couldn't open %s", rlFileName.c_str()); 96 return false; 97 } 98 99 uint16 resNum; 100 bool found = false; 101 for (resNum = 0; !found && !rlFile.ioFailed(); resNum++) { 102 // Read the resource name 103 char readname[12]; 104 rlFile.read(readname, 12); 105 106 // Test whether it's the resource we're searching 107 Common::String resname(readname, 12); 108 if (resname.hasPrefix(name.c_str())) { 109 debugC(2, kGroovieDebugResource | kGroovieDebugAll, "Groovie::Resource: Resource %12s matches %s", readname, name.c_str()); 110 found = true; 111 } 112 113 // Skip the rest of resource information 114 rlFile.read(readname, 8); 115 } 116 117 // Close the RL file 118 rlFile.close(); 119 120 // Verify we really found the resource 121 if (!found) { 122 error("Groovie::Resource: Couldn't find resource %s in %s", name.c_str(), rlFileName.c_str()); 123 return (uint16)-1; 124 } 125 126 return (_lastGjd << 10) | (resNum - 1); 127 } 128 129 bool ResMan_t7g::getResInfo(uint16 fileRef, ResInfo &resInfo) { 130 // Calculate the GJD and the resource number 131 resInfo.gjd = fileRef >> 10; 132 uint16 resNum = fileRef & 0x3FF; 133 134 // Get the name of the RL file 135 Common::String rlFileName(t7g_gjds[resInfo.gjd]); 136 rlFileName += ".rl"; 137 138 // Open the RL file 139 Common::File rlFile; 140 if (!rlFile.open(rlFileName)) { 141 error("Groovie::Resource: Couldn't open %s", rlFileName.c_str()); 142 return false; 143 } 144 145 // Seek to the position of the desired resource 146 rlFile.seek(resNum * 20); 147 if (rlFile.eos()) { 148 rlFile.close(); 149 error("Groovie::Resource: Invalid resource number: 0x%04X (%s)", resNum, rlFileName.c_str()); 150 return false; 151 } 152 153 // Read the resource name (just for debugging purposes) 154 char resname[12]; 155 rlFile.read(resname, 12); 156 debugC(2, kGroovieDebugResource | kGroovieDebugAll, "Groovie::Resource: Resource name: %12s", resname); 157 158 // Read the resource information 159 resInfo.offset = rlFile.readUint32LE(); 160 resInfo.size = rlFile.readUint32LE(); 161 162 // Close the resource RL file 163 rlFile.close(); 164 165 return true; 166 } 167 168 169 // ResMan_v2 170 171 ResMan_v2::ResMan_v2() { 172 Common::File indexfile; 173 174 // Open the GJD index file 175 if (!indexfile.open("gjd.gjd")) { 176 error("Groovie::Resource: Couldn't open gjd.gjd"); 177 return; 178 } 179 180 Common::String line = indexfile.readLine(); 181 while (!indexfile.eos() && !line.empty()) { 182 // Get the name before the space 183 Common::String filename; 184 for (const char *cur = line.c_str(); *cur != ' '; cur++) { 185 filename += *cur; 186 } 187 188 // Append it to the list of GJD files 189 if (!filename.empty()) { 190 _gjds.push_back(filename); 191 } 192 193 // Read the next line 194 line = indexfile.readLine(); 195 } 196 197 // Close the GJD index file 198 indexfile.close(); 199 } 200 201 uint16 ResMan_v2::getRef(Common::String name, Common::String scriptname) { 202 return 0; 203 } 204 205 bool ResMan_v2::getResInfo(uint16 fileRef, ResInfo &resInfo) { 206 // Open the RL file 207 Common::File rlFile; 208 if (!rlFile.open("dir.rl")) { 209 error("Groovie::Resource: Couldn't open dir.rl"); 210 return false; 211 } 212 213 // Seek to the position of the desired resource 214 rlFile.seek(fileRef * 32); 215 if (rlFile.eos()) { 216 rlFile.close(); 217 error("Groovie::Resource: Invalid resource number: 0x%04X", fileRef); 218 return false; 219 } 220 221 // Read the resource information 222 rlFile.readUint32LE(); // Unknown 223 resInfo.offset = rlFile.readUint32LE(); 224 resInfo.size = rlFile.readUint32LE(); 225 resInfo.gjd = rlFile.readUint16LE(); 226 227 // Read the resource name (just for debugging purposes) 228 char resname[12]; 229 rlFile.read(resname, 12); 230 debugC(2, kGroovieDebugResource | kGroovieDebugAll, "Groovie::Resource: Resource name: %12s", resname); 231 232 // 6 padding bytes? (it looks like they're always 0) 233 234 // Close the resource RL file 235 rlFile.close(); 236 237 return true; 238 } 239 240 } // End of Groovie namespace -
engines/groovie/jpeg.h
1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 * $URL$ 22 * $Id$ 23 * 24 */ 25 26 #ifndef GROOVIE_JPEG_H 27 #define GROOVIE_JPEG_H 28 29 #include "common/stream.h" 30 31 namespace Groovie { 32 33 #define JPEG_MAX_QUANT_TABLES 4 34 #define JPEG_MAX_HUFF_TABLES 2 35 36 class JPEG { 37 public: 38 JPEG(); 39 ~JPEG(); 40 41 bool read(Common::ReadStream *str); 42 43 private: 44 void reset(); 45 46 Common::ReadStream *_str; 47 uint16 _w, _h; 48 49 // Image components 50 uint8 _numComp; 51 struct Component { 52 // Global values 53 uint8 id; 54 uint8 factorH; 55 uint8 factorV; 56 uint8 quantTableSelector; 57 58 // Scan specific values 59 uint8 DCentropyTableSelector; 60 uint8 ACentropyTableSelector; 61 int8 DCpredictor; 62 }; 63 Component *_components; 64 65 // Scan components 66 uint8 _numScanComp; 67 Component **_scanComp; 68 Component *_currentComp; 69 70 // Maximum sampling factors, used to calculate the interleaving of the MCU 71 uint8 _maxFactorV; 72 uint8 _maxFactorH; 73 74 // Zig-Zag order 75 static uint8 _zigZagOrder[64]; 76 77 // Quantization tables 78 uint8 *_quant[JPEG_MAX_QUANT_TABLES]; 79 80 // Huffman tables 81 struct HuffmanTable { 82 uint8 count; 83 uint8 *values; 84 uint8 *sizes; 85 uint16 *codes; 86 }; 87 HuffmanTable _huff[2 * JPEG_MAX_HUFF_TABLES]; 88 89 // Marker read functions 90 bool readSOF0(); 91 bool readDHT(); 92 bool readSOS(); 93 bool readDQT(); 94 95 // Helper functions 96 bool readMCU(uint16 xMCU, uint16 yMCU); 97 bool readDataUnit(uint16 x, uint16 y); 98 int8 readDC(); 99 void readAC(int8 *out); 100 int16 readSignedBits(uint8 numBits); 101 102 // Huffman decoding 103 uint8 readHuff(uint8 table); 104 uint8 readBit(); 105 uint8 _bitsData; 106 uint8 _bitsNumber; 107 }; 108 109 } // End of Groovie namespace 110 111 #endif // GROOVIE_JPEG_H -
engines/groovie/debug.h
1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 * $URL$ 22 * $Id$ 23 * 24 */ 25 26 #ifndef GROOVIE_DEBUG_H 27 #define GROOVIE_DEBUG_H 28 29 #include "gui/debugger.h" 30 #include "engines/engine.h" 31 32 namespace Groovie { 33 34 class Script; 35 class GroovieEngine; 36 37 class Debugger : public GUI::Debugger { 38 public: 39 Debugger(GroovieEngine *vm); 40 ~Debugger(); 41 42 private: 43 GroovieEngine *_vm; 44 Script *_script; 45 OSystem *_syst; 46 47 int getNumber(const char *arg); 48 49 bool cmd_step(int argc, const char **argv); 50 bool cmd_go(int argc, const char **argv); 51 bool cmd_pc(int argc, const char **argv); 52 bool cmd_bg(int argc, const char **argv); 53 bool cmd_fg(int argc, const char **argv); 54 bool cmd_mem(int argc, const char **argv); 55 bool cmd_loadgame(int argc, const char **argv); 56 bool cmd_savegame(int argc, const char **argv); 57 bool cmd_playref(int argc, const char **argv); 58 bool cmd_dumppal(int argc, const char **argv); 59 }; 60 61 } // End of Groovie namespace 62 63 #endif // GROOVIE_DEBUG_H -
engines/groovie/lzss.cpp
1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 * $URL$ 22 * $Id$ 23 * 24 */ 25 26 #include "groovie/lzss.h" 27 28 #define OUT_BUFF_SIZE 131072 29 #define COMP_THRESH 3 // Compression not attempted if string to be compressed is less than 3 long 30 31 LzssReadStream::LzssReadStream(Common::ReadStream *indata, uint8 lengthmask, uint8 lengthbits) { 32 /* 33 TODO: Nasty hack. Make a buffer bigger than I'll ever need... probably. 34 What should *really* happen is I should define a whole new type of stream 35 that gets lzss decompressed on the fly 36 */ 37 _outLzssBufData = (uint8 *)malloc(OUT_BUFF_SIZE); 38 _size = decodeLZSS(indata, lengthmask, lengthbits); 39 _pos = 0; 40 } 41 42 LzssReadStream::~LzssReadStream() { 43 free(_outLzssBufData); 44 } 45 46 uint32 LzssReadStream::decodeLZSS(Common::ReadStream *in, uint8 lengthmask, uint8 lengthbits) { 47 uint32 N = 1 << (16 - lengthbits); /* History buffer size */ 48 byte *histbuff = new byte[N]; /* History buffer */ 49 memset(histbuff, 0, N); 50 uint32 outstreampos = 0; 51 uint32 bufpos = 0; 52 53 while (!in->eos()) { 54 byte flagbyte = in->readByte(); 55 for (uint32 i = 1; i <= 8; i++) { 56 if (!in->eos()) { 57 if ((flagbyte & 1) == 0) { 58 uint32 offsetlen = in->readUint16LE(); 59 if (offsetlen == 0) { 60 break; 61 } 62 uint32 length = (offsetlen & lengthmask) + COMP_THRESH; 63 uint32 offset = (bufpos - (offsetlen >> lengthbits)) & (N - 1); 64 for (uint32 j = 0; j < length; j++) { 65 byte tempa = histbuff[(offset + j) & (N - 1)]; 66 _outLzssBufData[outstreampos++] = tempa; 67 histbuff[bufpos] = tempa; 68 bufpos = (bufpos + 1) & (N - 1); 69 } 70 } else { 71 byte tempa = in->readByte(); 72 if (in->eos()) { 73 break; 74 } 75 _outLzssBufData[outstreampos++] = tempa; 76 histbuff[bufpos] = tempa; 77 bufpos = (bufpos + 1) & (N - 1); 78 } 79 flagbyte = flagbyte >> 1; 80 } 81 } 82 } 83 delete[] histbuff; 84 return outstreampos; 85 } 86 87 bool LzssReadStream::eos() const { 88 return _pos >= _size; 89 } 90 91 uint32 LzssReadStream::read(void *buf, uint32 size) { 92 if (size > _size - _pos) 93 size = _size - _pos; 94 95 memcpy(buf, &_outLzssBufData[_pos], size); 96 _pos += size; 97 98 return size; 99 } -
engines/groovie/player.cpp
1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 * $URL$ 22 * $Id$ 23 * 24 */ 25 26 #include "groovie/groovie.h" 27 #include "groovie/player.h" 28 29 namespace Groovie { 30 31 VideoPlayer::VideoPlayer(GroovieEngine *vm) : 32 _vm(vm), _syst(vm->_system), _file(NULL), _audioStream(NULL) { 33 } 34 35 bool VideoPlayer::load(Common::SeekableReadStream *file, uint16 flags) { 36 _file = file; 37 _flags = flags; 38 _audioStream = NULL; 39 40 uint16 fps = loadInternal(); 41 42 if (fps != 0) { 43 _millisBetweenFrames = 1000 / fps; 44 _begunPlaying = false; 45 return true; 46 } else { 47 _file = NULL; 48 return false; 49 } 50 } 51 52 bool VideoPlayer::playFrame() { 53 bool end = true; 54 55 // Process the next frame while the file is open 56 if (_file) { 57 end = playFrameInternal(); 58 } 59 60 // The file has been completely processed 61 if (end) { 62 _file = NULL; 63 64 // Wait for pending audio 65 if (_audioStream) { 66 if (_audioStream->endOfData()) { 67 // Mark the audio stream as finished (no more data will be appended) 68 _audioStream->finish(); 69 } else { 70 // Don't end if there's still audio playing 71 end = false; 72 } 73 } 74 } 75 76 return end; 77 } 78 79 void VideoPlayer::waitFrame() { 80 uint32 currTime = _syst->getMillis(); 81 if (!_begunPlaying) { 82 _begunPlaying = true; 83 _lastFrameTime = currTime; 84 } else { 85 uint32 millisDiff = currTime - _lastFrameTime; 86 if (millisDiff < _millisBetweenFrames) { 87 debugC(7, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::Player: Delaying %d (currTime=%d, _lastFrameTime=%d, millisDiff=%d, _millisBetweenFrame=%d)", 88 _millisBetweenFrames - millisDiff, currTime, _lastFrameTime, millisDiff, _millisBetweenFrames); 89 _syst->delayMillis(_millisBetweenFrames - millisDiff); 90 currTime = _syst->getMillis(); 91 debugC(7, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::Player: Finished delay at %d", currTime); 92 } 93 debugC(6, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::Player: Frame displayed at %d (%f FPS)", currTime, 1000.0 / (currTime - _lastFrameTime)); 94 _lastFrameTime = currTime; 95 } 96 } 97 98 } // End of Groovie namespace -
engines/groovie/resource.h
1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 * $URL$ 22 * $Id$ 23 * 24 */ 25 26 #ifndef GROOVIE_RESOURCE_H 27 #define GROOVIE_RESOURCE_H 28 29 namespace Groovie { 30 31 struct ResInfo { 32 uint16 gjd; 33 uint32 offset; 34 uint32 size; 35 }; 36 37 class ResMan { 38 public: 39 virtual ~ResMan() {}; 40 41 Common::SeekableReadStream *open(uint16 fileRef); 42 virtual uint16 getRef(Common::String name, Common::String scriptname = "") = 0; 43 44 protected: 45 Common::Array<Common::String> _gjds; 46 virtual bool getResInfo(uint16 fileRef, ResInfo &resInfo) = 0; 47 48 uint16 _lastGjd; 49 }; 50 51 class ResMan_t7g : public ResMan { 52 public: 53 ResMan_t7g(); 54 ~ResMan_t7g() {}; 55 56 uint16 getRef(Common::String name, Common::String scriptname); 57 bool getResInfo(uint16 fileRef, ResInfo &resInfo); 58 }; 59 60 class ResMan_v2 : public ResMan { 61 public: 62 ResMan_v2(); 63 ~ResMan_v2() {}; 64 65 uint16 getRef(Common::String name, Common::String scriptname); 66 bool getResInfo(uint16 fileRef, ResInfo &resInfo); 67 }; 68 69 } // End of Groovie namespace 70 71 #endif // GROOVIE_RESOURCE_H -
base/plugins.cpp
108 108 #if PLUGIN_ENABLED_STATIC(GOB) 109 109 LINK_PLUGIN(GOB) 110 110 #endif 111 #if PLUGIN_ENABLED_STATIC(GROOVIE) 112 LINK_PLUGIN(GROOVIE) 113 #endif 111 114 #if PLUGIN_ENABLED_STATIC(IGOR) 112 115 LINK_PLUGIN(IGOR) 113 116 #endif