private ushort CopyChar(byte ch, ByteAccess sprPtr, ushort sprWidth, byte pen) { if (ch < ' ') { ch = 64; } var chFrame = new FrameHeader(_resMan.FetchFrame(_font, (uint)(ch - ' '))); var chData = FrameHeader.Size; var dest = sprPtr; ByteAccess decChr; ushort frameHeight; if (SystemVars.Platform == Platform.PSX) { frameHeight = (ushort)(_resMan.ReadUInt16(chFrame.height) / 2); if (_fontId == SwordRes.CZECH_GAME_FONT) { //Czech game fonts are compressed var decBuf = new byte[_resMan.ReadUInt16(chFrame.width) * (_resMan.ReadUInt16(chFrame.height) / 2)]; Screen.DecompressHIF(chFrame.Data.Data, chFrame.Data.Offset + chData, decBuf); decChr = new ByteAccess(decBuf); } else //Normal game fonts are not compressed { decChr = new ByteAccess(chFrame.Data.Data, chFrame.Data.Offset + chData); } } else { frameHeight = _resMan.ReadUInt16(chFrame.height); decChr = new ByteAccess(chFrame.Data.Data, chFrame.Data.Offset + chData); } for (ushort cnty = 0; cnty < frameHeight; cnty++) { for (ushort cntx = 0; cntx < _resMan.ReadUInt16(chFrame.width); cntx++) { if (decChr[0] == LetterCol) { dest[cntx] = pen; } else if (((decChr[0] == BorderCol) || (decChr[0] == BorderColPsx)) && (dest[cntx] == 0)) // don't do a border if there's already a color underneath (chars can overlap) { dest[cntx] = BorderCol; } decChr.Offset++; } dest.Offset += sprWidth; } return(_resMan.ReadUInt16(chFrame.width)); }
private ushort AnalyzeSentence(ByteAccess textSrc, ushort maxWidth, LineInfo[] line) { ushort lineNo = 0; var text = new ByteAccess(textSrc.Data, textSrc.Offset); var firstWord = true; while (text.Offset < text.Data.Length && text[0] != 0) { ushort wordWidth = 0; ushort wordLength = 0; while (text.Offset < text.Data.Length && (text[0] != ' ') && text[0] != 0) { wordWidth = (ushort)(wordWidth + CharWidth(text[0]) - Overlap); wordLength++; text.Offset++; } if (text.Offset < text.Data.Length && text[0] == ' ') { text.Offset++; } wordWidth += Overlap; // no overlap on final letter of word! if (firstWord) { // first word on first line, so no separating SPACE needed line[0].Width = wordWidth; line[0].Length = wordLength; firstWord = false; } else { // see how much extra space this word will need to fit on current line // (with a separating space character - also overlapped) var spaceNeeded = (ushort)(_joinWidth + wordWidth); if (line[lineNo].Width + spaceNeeded <= maxWidth) { line[lineNo].Width += spaceNeeded; line[lineNo].Length = (ushort)(line[lineNo].Length + 1 + wordLength); // NB. space+word characters } else { // put word (without separating SPACE) at start of next line lineNo++; Debug.Assert(lineNo < MaxLines); line[lineNo].Width = wordWidth; line[lineNo].Length = wordLength; } } } return((ushort)(lineNo + 1)); // return no of lines }
public void MakeTextSprite(byte slot, ByteAccess text, ushort maxWidth, byte pen) { var lines = new LineInfo[MaxLines]; var numLines = AnalyzeSentence(text, maxWidth, lines); ushort sprWidth = 0; ushort lineCnt; for (lineCnt = 0; lineCnt < numLines; lineCnt++) { if (lines[lineCnt].Width > sprWidth) { sprWidth = lines[lineCnt].Width; } } var sprHeight = (ushort)(_charHeight * numLines); var sprSize = (uint)(sprWidth * sprHeight); Debug.Assert(_textBlocks[slot] == null); // if this triggers, the speechDriver failed to call Text::releaseText. _textBlocks[slot] = new FrameHeader(new byte[sprSize + FrameHeader.Size]); Array.Copy(new[] { (byte)'N', (byte)'u', (byte)' ', (byte)' ' }, 0, _textBlocks[slot].runTimeComp.Data, _textBlocks[slot].runTimeComp.Offset, 4); _textBlocks[slot].compSize = 0; _textBlocks[slot].width = _resMan.ReadUInt16(sprWidth); _textBlocks[slot].height = _resMan.ReadUInt16(sprHeight); _textBlocks[slot].offsetX = 0; _textBlocks[slot].offsetY = 0; var linePtr = new ByteAccess(_textBlocks[slot].Data.Data, _textBlocks[slot].Data.Offset + FrameHeader.Size); linePtr.Data.Set(linePtr.Offset, NoCol, (int)sprSize); for (lineCnt = 0; lineCnt < numLines; lineCnt++) { var sprPtr = (sprWidth - lines[lineCnt].Width) / 2; // center the text for (ushort pos = 0; pos < lines[lineCnt].Length; pos++) { sprPtr += CopyChar(text[0], new ByteAccess(linePtr.Data, linePtr.Offset + sprPtr), sprWidth, pen) - Overlap; text.Offset++; } text.Offset++; // skip space at the end of the line if (SystemVars.Platform == Platform.PSX) //Chars are half height in psx version { linePtr.Offset += _charHeight / 2 * sprWidth; } else { linePtr.Offset += _charHeight * sprWidth; } } }
public void LoadLiveList(UShortAccess src) { for (var cnt = 0; cnt < TOTAL_SECTIONS; cnt++) { if (_liveList[cnt] != 0) { _resMan.ResClose(_objectList[cnt]); _cptData[cnt] = null; } _liveList[cnt] = src[cnt]; if (_liveList[cnt] != 0) { _cptData[cnt] = new ByteAccess(_resMan.CptResOpen(_objectList[cnt]), Header.Size); } } }
public uint LowTextManager(ByteAccess ascii, int width, byte pen) { _textCount++; if (_textCount > MaxTextObs) { throw new InvalidOperationException("Text::lowTextManager: MAX_TEXT_OBS exceeded"); } uint textObjId = ObjectMan.TEXT_sect * ObjectMan.ITM_PER_SEC - 1; do { textObjId++; } while (_objMan.FetchObject(textObjId).status != 0); // okay, found a free text object _objMan.FetchObject(textObjId).status = Logic.STAT_FORE; MakeTextSprite((byte)textObjId, ascii, (ushort)width, pen); return(textObjId); }
public ControlButton(ushort x, ushort y, uint resId, ButtonIds id, byte flag, ResMan pResMan, byte[] screenBuf, ISystem system) { _x = x; _y = y; _id = id; _flag = flag; _resId = resId; _resMan = pResMan; _frameIdx = 0; _resMan.ResOpen(_resId); FrameHeader tmp = new FrameHeader(_resMan.FetchFrame(_resMan.FetchRes(_resId), 0)); _width = _resMan.ReadUInt16(tmp.width); _width = (ushort)((_width > Screen.SCREEN_WIDTH) ? Screen.SCREEN_WIDTH : _width); _height = _resMan.ReadUInt16(tmp.height); if ((x == 0) && (y == 0)) { // center the frame (used for panels); _x = (ushort)((((640 - _width) / 2) < 0) ? 0 : ((640 - _width) / 2)); _y = (ushort)((((480 - _height) / 2) < 0) ? 0 : ((480 - _height) / 2)); } _dstBuf = new ByteAccess(screenBuf, _y * Screen.SCREEN_WIDTH + _x); _system = system; }
public MousePtr(byte[] data) { Data = data; Offset = 0; dummyData = new ByteAccess(data, Offset + 10); }
private void PerformPostProcessing(byte[] screen) { // TODO: We don't support displaying these in true color yet, // nor using the PSX fonts to display subtitles. if (SystemVars.Platform == Core.IO.Platform.PSX /* || _decoderType == kVideoDecoderMP2*/) { return; } if (_movieTexts.Count > 0) { if (_decoder.CurrentFrame == _movieTexts[0]._startFrame) { var text = new ByteAccess(System.Text.Encoding.UTF8.GetBytes(_movieTexts[0]._text)); _textMan.MakeTextSprite(2, text, 600, Text.LetterCol); var frame = new FrameHeader(_textMan.GiveSpriteData(2)); _textWidth = _resMan.ReadUInt16(frame.width); _textHeight = _resMan.ReadUInt16(frame.height); _textX = 320 - _textWidth / 2; _textY = 420 - _textHeight; _textColor = _movieTexts[0]._color; } if (_decoder.CurrentFrame == _movieTexts[0]._endFrame) { _textMan.ReleaseText(2, false); _movieTexts.RemoveAt(0); } } ByteAccess src, dst; int x, y; if (_textMan.GiveSpriteData(2) != null) { src = new ByteAccess(_textMan.GiveSpriteData(2)); src.Offset += FrameHeader.Size; dst = new ByteAccess(screen, _textY * Screen.SCREEN_WIDTH + _textX * 1); for (y = 0; y < _textHeight; y++) { for (x = 0; x < _textWidth; x++) { switch (src[x]) { case Text.BorderCol: dst[x] = (byte)GetBlackColor(); break; case Text.LetterCol: dst[x] = (byte)FindTextColor(); break; } } src.Offset += _textWidth; dst.Offset += Screen.SCREEN_WIDTH; } } else if (_textX != 0 && _textY != 0) { // If the frame doesn't cover the entire screen, we have to // erase the subtitles manually. int frameWidth = _decoder.GetWidth(); int frameHeight = _decoder.GetHeight(); int frameX = (_vm.Settings.Game.Width - frameWidth) / 2; int frameY = (_vm.Settings.Game.Height - frameHeight) / 2; dst = new ByteAccess(screen, _textY * _vm.Settings.Game.Width); for (y = 0; y < _textHeight; y++) { if (_textY + y < frameY || _textY + y >= frameY + frameHeight) { dst.Data.Set(dst.Offset + _textX, (byte)GetBlackColor(), _textWidth); } else { if (frameX > _textX) { dst.Data.Set(dst.Offset + _textX, (byte)GetBlackColor(), frameX - _textX); } if (frameX + frameWidth < _textX + _textWidth) { dst.Data.Set(dst.Offset + frameX + frameWidth, (byte)GetBlackColor(), _textX + _textWidth - (frameX + frameWidth)); } } dst.Offset += _vm.Settings.Game.Width; } _textX = 0; _textY = 0; } }
public ByteAccess(ByteAccess data) : this(data.Data, data.Offset) { }
public void Draw() { FrameHeader fHead = new FrameHeader(_resMan.FetchFrame(_resMan.FetchRes(_resId), (uint)_frameIdx)); ByteAccess src = new ByteAccess(fHead.Data.Data, fHead.Data.Offset + FrameHeader.Size); var dst = new ByteAccess(_dstBuf); if (SystemVars.Platform == Platform.PSX && _resId != 0) { var HIFbuf = new byte[_resMan.ReadUInt16(fHead.height) * _resMan.ReadUInt16(fHead.width)]; Screen.DecompressHIF(src.Data, src.Offset, HIFbuf); src = new ByteAccess(HIFbuf); if (_resMan.ReadUInt16(fHead.width) < 300) { for (var cnt = 0; cnt < _resMan.ReadUInt16(fHead.height); cnt++) { for (var cntx = 0; cntx < _resMan.ReadUInt16(fHead.width); cntx++) { if (src[cntx] != 0) { dst[cntx] = src[cntx]; } } dst.Offset += Screen.SCREEN_WIDTH; for (var cntx = 0; cntx < _resMan.ReadUInt16(fHead.width); cntx++) { if (src[cntx] != 0) { dst[cntx] = src[cntx]; } } dst.Offset += Screen.SCREEN_WIDTH; src.Offset += _resMan.ReadUInt16(fHead.width); } } else if (_resId == SwordRes.SR_DEATHPANEL) { // Check for death panel psx version (which is 1/3 of original width) for (var cnt = 0; cnt < _resMan.ReadUInt16(fHead.height) / 2; cnt++) { //Stretched panel is bigger than 640px, check we don't draw outside screen for (var cntx = 0; (cntx < (_resMan.ReadUInt16(fHead.width)) / 3) && (cntx < (Screen.SCREEN_WIDTH - 3)); cntx++) { if (src[cntx] != 0) { dst[cntx * 3] = src[cntx]; dst[cntx * 3 + 1] = src[cntx]; dst[cntx * 3 + 2] = src[cntx]; } } dst.Offset += Screen.SCREEN_WIDTH; for (var cntx = 0; cntx < (_resMan.ReadUInt16(fHead.width)) / 3; cntx++) { if (src[cntx] != 0) { dst[cntx * 3] = src[cntx]; dst[cntx * 3 + 1] = src[cntx]; dst[cntx * 3 + 2] = src[cntx]; } } dst.Offset += Screen.SCREEN_WIDTH; src.Offset += _resMan.ReadUInt16(fHead.width) / 3; } } else { //save slots needs to be multiplied by 2 in height for (var cnt = 0; cnt < _resMan.ReadUInt16(fHead.height); cnt++) { for (var cntx = 0; cntx < _resMan.ReadUInt16(fHead.width) / 2; cntx++) { if (src[cntx] != 0) { dst[cntx * 2] = src[cntx]; dst[cntx * 2 + 1] = src[cntx]; } } dst.Offset += Screen.SCREEN_WIDTH; for (var cntx = 0; cntx < _resMan.ReadUInt16(fHead.width) / 2; cntx++) { if (src[cntx] != 0) { dst[cntx * 2] = src[cntx]; dst[cntx * 2 + 1] = src[cntx]; } } dst.Offset += Screen.SCREEN_WIDTH; src.Offset += _resMan.ReadUInt16(fHead.width) / 2; } } } else { for (var cnt = 0; cnt < _resMan.ReadUInt16(fHead.height); cnt++) { for (var cntx = 0; cntx < _resMan.ReadUInt16(fHead.width); cntx++) { if (src[cntx] != 0) { dst[cntx] = src[cntx]; } } dst.Offset += Screen.SCREEN_WIDTH; src.Offset += _resMan.ReadUInt16(fHead.width); } } _system.GraphicsManager.CopyRectToScreen(_dstBuf.Data, _dstBuf.Offset, Screen.SCREEN_WIDTH, _x, _y, _width, _height); }