FLARM::FrameHeader FLARM::PrepareFrameHeader(unsigned sequence_number, MessageType message_type, const void *data, size_t length) { assert((data != NULL && length > 0) || (data == NULL && length == 0)); FrameHeader header; header.SetLength(8 + length); header.version = 0; header.SetSequenceNumber(sequence_number++); header.type = (uint8_t)message_type; header.SetCRC(CalculateCRC(header, data, length)); return header; }
void FontRenderer::copyChar(byte *charPtr, byte *spritePtr, uint16 spriteWidth, uint8 pen) { FrameHeader frame; frame.read(charPtr); byte *source = charPtr + FrameHeader::size(); byte *rowPtr = spritePtr; for (uint i = 0; i < frame.height; i++) { byte *dest = rowPtr; if (pen) { // Use the specified colors for (uint j = 0; j < frame.width; j++) { switch (*source++) { case 0: // Do nothing if source pixel is zero, // ie. transparent break; case LETTER_COL_PSX1: // Values for colored zone case LETTER_COL_PSX2: case LETTER_COL: *dest = pen; break; case BORDER_COL: default: // Don't do a border pixel if there's // already a bit of another character // underneath (for overlapping!) if (!*dest) *dest = _borderPen; break; } dest++; } } else { // Pen is zero, so just copy character sprites // directly into text sprite without remapping colors. // Apparently overlapping is never considered here? memcpy(dest, source, frame.width); source += frame.width; } rowPtr += spriteWidth; } }
void MoviePlayer::openTextObject(uint32 index) { MovieText *text = &_movieTexts[index]; // Pull out the text line to get the official text number (for WAV id) uint32 res = text->_textNumber / SIZE; uint32 localText = text->_textNumber & 0xffff; // Open text resource and get the line byte *textData = _vm->fetchTextLine(_vm->_resman->openResource(res), localText); text->_speechId = READ_LE_UINT16(textData); // Is it speech or subtitles, or both? // If we want subtitles, or there was no sound if (_vm->getSubtitles() || !text->_speechId) { text->_textMem = _vm->_fontRenderer->makeTextSprite(textData + 2, 600, 255, _vm->_speechFontId, 1); } _vm->_resman->closeResource(res); if (text->_textMem) { FrameHeader frame; frame.read(text->_textMem); text->_textSprite.x = 320 - frame.width / 2; text->_textSprite.y = 440 - frame.height; text->_textSprite.w = frame.width; text->_textSprite.h = frame.height; text->_textSprite.type = RDSPR_DISPLAYALIGN | RDSPR_NOCOMPRESSION; text->_textSprite.data = text->_textMem + FrameHeader::size(); text->_textSprite.isText = true; _vm->_screen->createSurface(&text->_textSprite, &_textSurface); _textX = 320 - text->_textSprite.w / 2; _textY = 420 - text->_textSprite.h; } }
bool readFrameHeader(FrameHeader &h,PxFileBuffer &fph) { bool ret = false; h.init(); h.mItemCount = fph.readDword(); h.mItemSize = fph.readDword(); h.mSeekLocation = fph.tellRead(); if ( h.mItemCount > 0 && h.mItemSize > 0 ) { fph.seekRead(h.mSeekLocation+h.mItemSize); ret = true; } return ret; }
byte *FontRenderer::findChar(byte ch, byte *charSet) { // PSX version doesn't use an animation table to keep all letters, // instead a big sprite (char atlas) is used, and the single char // must be extracted from that. if (Sword2Engine::isPsx()) { byte *buffer; PSXFontEntry header; FrameHeader bogusHeader; charSet += ResHeader::size() + 2; if (ch < FIRST_CHAR) ch = DUD; // Read font entry of the corresponding char. header.read(charSet + PSXFontEntry::size() * (ch - 32)); // We have no such character, generate an empty one // on the fly, size 6x12. if (header.charWidth == 0) { // Prepare a "bogus" FrameHeader to be returned with // "empty" character data. bogusHeader.compSize = 0; bogusHeader.width = 6; bogusHeader.height = 12; buffer = (byte *)malloc(24 * 3 + FrameHeader::size()); memset(buffer, 0, 24 * 3 + FrameHeader::size()); bogusHeader.write(buffer); return buffer; } buffer = (byte *)malloc(FrameHeader::size() + header.charWidth * header.charHeight * 4); byte *tempchar = (byte *)malloc(header.charWidth * header.charHeight); // Prepare the "bogus" header to be returned with character bogusHeader.compSize = 0; bogusHeader.width = header.charWidth * 2; bogusHeader.height = header.charHeight; // Go to the beginning of char atlas charSet += 2062; memset(buffer, 0, FrameHeader::size() + header.charWidth * header.charHeight * 4); bogusHeader.write(buffer); // Copy and stretch the char into destination buffer for (int idx = 0; idx < header.charHeight; idx++) { memcpy(tempchar + header.charWidth * idx, charSet + header.offset + 128 * (header.skipLines + idx), header.charWidth); } for (int line = 0; line < header.charHeight; line++) { for (int col = 0; col < header.charWidth; col++) { *(buffer + FrameHeader::size() + line * bogusHeader.width + col * 2) = *(tempchar + line * header.charWidth + col); *(buffer + FrameHeader::size() + line * bogusHeader.width + col * 2 + 1) = *(tempchar + line * header.charWidth + col); } } free(tempchar); return buffer; } else { if (ch < FIRST_CHAR) ch = DUD; return _vm->fetchFrameHeader(charSet, ch - FIRST_CHAR); } }
void Screen::rollCredits() { uint32 loopingMusicId = _vm->_sound->getLoopingMusicId(); // Prepare for the credits by fading down, stoping the music, etc. _vm->_mouse->setMouse(0); _vm->_sound->muteFx(true); _vm->_sound->muteSpeech(true); waitForFade(); fadeDown(); waitForFade(); _vm->_mouse->closeMenuImmediately(); // There are three files which I believe are involved in showing the // credits: // // credits.bmp - The "Smacker" logo, stored as follows: // // width 2 bytes, little endian // height 2 bytes, little endian // palette 3 * 256 bytes // data width * height bytes // // Note that the maximum colour component in the palette is 0x3F. // This is the same resolution as the _paletteMatch table. I doubt // that this is a coincidence, but let's use the image palette // directly anyway, just to be safe. // // credits.clu - The credits text (credits.txt in PSX version) // // This is simply a text file with CRLF line endings. // '^' is not shown, but used to mark the center of the line. // '@' is used as a placeholder for the "Smacker" logo. At least // when it appears alone. // Remaining lines are centered. // The German version also contains character code 9 for no // apparent reason. We ignore them. // // fonts.clu - The credits font? // // FIXME: At this time I don't know how to interpret fonts.clu. For // now, let's just the standard speech font instead. SpriteInfo spriteInfo; Common::File f; int i; spriteInfo.isText = false; // Read the "Smacker" logo uint16 logoWidth = 0; uint16 logoHeight = 0; byte *logoData = NULL; byte palette[256 * 3]; if (f.open("credits.bmp")) { logoWidth = f.readUint16LE(); logoHeight = f.readUint16LE(); for (i = 0; i < 256; i++) { palette[i * 3 + 0] = f.readByte() << 2; palette[i * 3 + 1] = f.readByte() << 2; palette[i * 3 + 2] = f.readByte() << 2; } logoData = (byte *)malloc(logoWidth * logoHeight); f.read(logoData, logoWidth * logoHeight); f.close(); } else { warning("Can't find credits.bmp"); memset(palette, 0, sizeof(palette)); palette[14 * 3 + 0] = 252; palette[14 * 3 + 1] = 252; palette[14 * 3 + 2] = 252; } setPalette(0, 256, palette, RDPAL_INSTANT); // Read the credits text Common::Array<CreditsLine *> creditsLines; int lineCount = 0; int lineTop = 400; int paragraphStart = 0; bool hasCenterMark = false; if (Sword2Engine::isPsx()) { if (!f.open("credits.txt")) { warning("Can't find credits.txt"); free(logoData); return; } } else { if (!f.open("credits.clu")) { warning("Can't find credits.clu"); free(logoData); return; } } while (1) { char buffer[80]; char *line = f.readLine(buffer, sizeof(buffer)); if (line) { // Replace invalid character codes prevent the 'dud' // symbol from showing up in the credits. for (byte *ptr = (byte *)line; *ptr; ptr++) { switch (*ptr) { case 9: // The German credits contain these. // Convert them to spaces. *ptr = 32; break; case 10: // LF is treated as end of line. *ptr = 0; break; case 170: // The Spanish credits contain these. // Convert them to periods. *ptr = '.'; default: break; } } } if (!line || *line == 0) { if (!hasCenterMark) { for (i = paragraphStart; i < lineCount; i++) creditsLines[i]->type = LINE_CENTER; } paragraphStart = lineCount; hasCenterMark = false; if (paragraphStart == lineCount) lineTop += CREDITS_LINE_SPACING; if (!line) break; continue; } char *center_mark = strchr(line, '^'); if (center_mark) { // The current paragraph has at least one center mark. hasCenterMark = true; if (center_mark != line) { creditsLines.push_back(new CreditsLine); // The center mark is somewhere inside the // line. Split it into left and right side. *center_mark = 0; creditsLines[lineCount]->top = lineTop; creditsLines[lineCount]->height = CREDITS_FONT_HEIGHT; creditsLines[lineCount]->type = LINE_LEFT; creditsLines[lineCount]->str = strdup(line); lineCount++; *center_mark = '^'; } line = center_mark; } creditsLines.push_back(new CreditsLine); creditsLines[lineCount]->top = lineTop; if (*line == '^') { creditsLines[lineCount]->type = LINE_RIGHT; line++; } else creditsLines[lineCount]->type = LINE_LEFT; if (strcmp(line, "@") == 0) { creditsLines[lineCount]->height = logoHeight; lineTop += logoHeight; } else { creditsLines[lineCount]->height = CREDITS_FONT_HEIGHT; lineTop += CREDITS_LINE_SPACING; } creditsLines[lineCount]->str = strdup(line); lineCount++; } f.close(); // We could easily add some ScummVM stuff to the credits, if we wanted // to. On the other hand, anyone with the attention span to actually // read all the credits probably already knows. :-) // Start the music and roll the credits // The credits music (which can also be heard briefly in the "carib" // cutscene) is played once. _vm->_sound->streamCompMusic(309, false); clearScene(); fadeUp(0); spriteInfo.scale = 0; spriteInfo.scaledWidth = 0; spriteInfo.scaledHeight = 0; spriteInfo.type = RDSPR_DISPLAYALIGN | RDSPR_NOCOMPRESSION | RDSPR_TRANS; spriteInfo.blend = 0; int startLine = 0; int scrollPos = 0; bool abortCredits = false; int scrollSteps = lineTop + CREDITS_FONT_HEIGHT; uint32 musicStart = getTick(); // Ideally the music should last just a tiny bit longer than the // credits. Note that musicTimeRemaining() will return 0 if the music // is muted, so we need a sensible fallback for that case. uint32 musicLength = MAX((int32)(1000 * (_vm->_sound->musicTimeRemaining() - 3)), 25 * (int32)scrollSteps); while (scrollPos < scrollSteps && !_vm->shouldQuit()) { clearScene(); for (i = startLine; i < lineCount; i++) { if (!creditsLines[i]) continue; // Free any sprites that have scrolled off the screen if (creditsLines[i]->top + creditsLines[i]->height < scrollPos) { debug(2, "Freeing line %d: '%s'", i, creditsLines[i]->str); delete creditsLines[i]; creditsLines[i] = NULL; startLine = i + 1; } else if (creditsLines[i]->top < scrollPos + 400) { if (!creditsLines[i]->sprite) { debug(2, "Creating line %d: '%s'", i, creditsLines[i]->str); creditsLines[i]->sprite = _vm->_fontRenderer->makeTextSprite((byte *)creditsLines[i]->str, 600, 14, _vm->_speechFontId, 0); } FrameHeader frame; frame.read(creditsLines[i]->sprite); spriteInfo.y = creditsLines[i]->top - scrollPos; spriteInfo.w = frame.width; spriteInfo.h = frame.height; spriteInfo.data = creditsLines[i]->sprite + FrameHeader::size(); spriteInfo.isText = true; switch (creditsLines[i]->type) { case LINE_LEFT: spriteInfo.x = RENDERWIDE / 2 - 5 - frame.width; break; case LINE_RIGHT: spriteInfo.x = RENDERWIDE / 2 + 5; break; case LINE_CENTER: if (strcmp(creditsLines[i]->str, "@") == 0) { spriteInfo.data = logoData; spriteInfo.x = (RENDERWIDE - logoWidth) / 2; spriteInfo.w = logoWidth; spriteInfo.h = logoHeight; } else spriteInfo.x = (RENDERWIDE - frame.width) / 2; break; } if (spriteInfo.data) drawSprite(&spriteInfo); } else break; } updateDisplay(); KeyboardEvent *ke = _vm->keyboardEvent(); if (ke && ke->kbd.keycode == Common::KEYCODE_ESCAPE) { if (!abortCredits) { abortCredits = true; fadeDown(); } } if (abortCredits && getFadeStatus() == RDFADE_BLACK) break; _vm->sleepUntil(musicStart + (musicLength * scrollPos) / scrollSteps + _pauseTicks); scrollPos++; } // We're done. Clean up and try to put everything back where it was // before the credits. for (i = 0; i < lineCount; i++) { delete creditsLines[i]; } free(logoData); if (!abortCredits) { fadeDown(); // The music should either have stopped or be about to stop, so // wait for it to really happen. while (_vm->_sound->musicTimeRemaining() && !_vm->shouldQuit()) { updateDisplay(false); _vm->_system->delayMillis(100); } } if (_vm->shouldQuit()) return; waitForFade(); _vm->_sound->muteFx(false); _vm->_sound->muteSpeech(false); if (loopingMusicId) _vm->_sound->streamCompMusic(loopingMusicId, true); else _vm->_sound->stopMusic(false); if (!_vm->_mouse->getMouseStatus() || _vm->_mouse->isChoosing()) _vm->_mouse->setMouse(NORMAL_MOUSE_ID); if (_vm->_logic->readVar(DEAD)) _vm->_mouse->buildSystemMenu(); }
void Screen::displayMsg(byte *text, int time) { byte pal[256 * 3]; byte oldPal[256 * 3]; debug(2, "DisplayMsg: %s", text); if (getFadeStatus() != RDFADE_BLACK) { fadeDown(); waitForFade(); } _vm->_mouse->setMouse(0); _vm->_mouse->setLuggage(0); _vm->_mouse->closeMenuImmediately(); clearScene(); byte *text_spr = _vm->_fontRenderer->makeTextSprite(text, 640, 187, _vm->_speechFontId); FrameHeader frame; frame.read(text_spr); SpriteInfo spriteInfo; spriteInfo.x = _screenWide / 2 - frame.width / 2; if (!time) spriteInfo.y = _screenDeep / 2 - frame.height / 2 - MENUDEEP; else spriteInfo.y = 400 - frame.height; spriteInfo.w = frame.width; spriteInfo.h = frame.height; spriteInfo.scale = 0; spriteInfo.scaledWidth = 0; spriteInfo.scaledHeight = 0; spriteInfo.type = RDSPR_DISPLAYALIGN | RDSPR_NOCOMPRESSION | RDSPR_TRANS; spriteInfo.blend = 0; spriteInfo.data = text_spr + FrameHeader::size(); spriteInfo.colourTable = 0; spriteInfo.isText = true; uint32 rv = drawSprite(&spriteInfo); if (rv) error("Driver Error %.8x (in DisplayMsg)", rv); memcpy(oldPal, _palette, sizeof(oldPal)); memset(pal, 0, sizeof(pal)); pal[187 * 3 + 0] = 255; pal[187 * 3 + 1] = 255; pal[187 * 3 + 2] = 255; setPalette(0, 256, pal, RDPAL_FADE); fadeUp(); free(text_spr); waitForFade(); if (time > 0) { uint32 targetTime = _vm->_system->getMillis() + (time * 1000); _vm->sleepUntil(targetTime); } else { while (!_vm->shouldQuit()) { MouseEvent *me = _vm->mouseEvent(); if (me && (me->buttons & (RD_LEFTBUTTONDOWN | RD_RIGHTBUTTONDOWN))) break; if (_vm->keyboardEvent()) break; updateDisplay(); _vm->_system->delayMillis(50); } } fadeDown(); waitForFade(); clearScene(); setPalette(0, 256, oldPal, RDPAL_FADE); fadeUp(); }
bool NoiseSockets::InitNoiseDataFromFile(char *filename) { int i; if(p_noise_data_buf!=NULL) { delete [] p_noise_data_buf; p_noise_data_buf=NULL; } // Seed the rand() with 12 a.m. today CTime now=CTime::GetCurrentTime(); CTime today(now.GetYear(),now.GetMonth(),now.GetDay(),0,0,0); // 12 a.m. today srand((unsigned int)today.GetTime()); p_noise_data_buf=new unsigned char[NOISE_DATA_LEN+NOISE_BUFFER_LEN]; memset(p_noise_data_buf,0,NOISE_DATA_LEN+NOISE_BUFFER_LEN); CFile file; if(file.Open(filename,CFile::modeRead|CFile::typeBinary|CFile::shareDenyWrite)==NULL) { return false; } // Seek past the zeros to find the first frame unsigned int first_frame_index=0; while(1) { char c; file.Read(&c,1); if(c==0) { first_frame_index++; } else { break; } } // Position the file pointer at the first frame file.Seek(first_frame_index,CFile::begin); FrameHeader hdr; unsigned int offset=0; unsigned int num_read=0; while(1) { // Check to see if a frame header will go beyond the buffer if((NOISE_DATA_LEN-offset)<sizeof(FrameHeader)) { break; } num_read=file.Read(&hdr,sizeof(FrameHeader)); // if EOF, reset file if(num_read!=sizeof(FrameHeader)) { file.Seek(first_frame_index,CFile::begin); file.Read(&hdr,sizeof(FrameHeader)); } if(hdr.IsValid()==false) { return false; } unsigned int frame_len=hdr.ReturnFrameSize(); // Check to see if this frame will go beyond the buffer if((NOISE_DATA_LEN-offset)<frame_len) { break; } memcpy(&p_noise_data_buf[offset],&hdr,sizeof(FrameHeader)); offset+=sizeof(FrameHeader); num_read=file.Read(&p_noise_data_buf[offset],frame_len-sizeof(FrameHeader)); // Make sure that all of the frame data is there if(num_read!=(frame_len-sizeof(FrameHeader))) { return false; } offset+=frame_len-sizeof(FrameHeader); } // Init remainder of dookie for(i=offset;i<NOISE_DATA_LEN;i++) { p_noise_data_buf[i]=rand()%256; } // Copy out the buffer padding memcpy(&p_noise_data_buf[NOISE_DATA_LEN],&p_noise_data_buf[0],NOISE_BUFFER_LEN); return true; }