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 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); }
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; } }
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 void ProcessImage(uint id) { FrameHeader frameHead; int scale; var compact = _objMan.FetchObject(id); if (compact.type == TYPE_TEXT) frameHead = new FrameHeader(_textMan.GiveSpriteData((byte)compact.target)); else frameHead = new FrameHeader(_resMan.FetchFrame(_resMan.OpenFetchRes((uint)compact.resource), (uint)compact.frame)); ushort spriteX = (ushort)compact.anim_x; ushort spriteY = (ushort)compact.anim_y; if ((compact.status & STAT_SHRINK) != 0) { scale = (compact.scale_a * compact.ycoord + compact.scale_b) / 256; spriteX = (ushort)(spriteX + (_resMan.ReadInt16(frameHead.offsetX) * scale) / 256); spriteY = (ushort)(spriteY + (_resMan.ReadInt16(frameHead.offsetY) * scale) / 256); } else { scale = 256; spriteX = (ushort)(spriteX + _resMan.ReadInt16(frameHead.offsetX)); spriteY = (ushort)(spriteY + _resMan.ReadInt16(frameHead.offsetY)); } var sprData = new ByteAccess(frameHead.Data.Data, frameHead.Data.Offset + FrameHeader.Size); if (SystemVars.Platform == Platform.PSX && compact.type != TYPE_TEXT) { // PSX sprites are compressed with HIF var hifBuf = new byte[_resMan.ReadUInt16(frameHead.width) * _resMan.ReadUInt16(frameHead.height) / 2]; DecompressHIF(sprData.Data, sprData.Offset, hifBuf); sprData = new ByteAccess(hifBuf); } else if (frameHead.runTimeComp[3] == '7') { // RLE7 encoded? DecompressRLE7(sprData.Data, sprData.Offset, _resMan.ReadUInt32(frameHead.compSize), _rleBuffer); sprData = new ByteAccess(_rleBuffer); } else if (frameHead.runTimeComp[3] == '0') { // RLE0 encoded? DecompressRLE0(sprData.Data, sprData.Offset, _resMan.ReadUInt32(frameHead.compSize), _rleBuffer); sprData = new ByteAccess(_rleBuffer); } else if (frameHead.runTimeComp[1] == 'I') { // new type var tonyBuf = new byte[_resMan.ReadUInt32(frameHead.width) * _resMan.ReadUInt16(frameHead.height)]; DecompressTony(sprData.Data, sprData.Offset, _resMan.ReadUInt32(frameHead.compSize), tonyBuf); sprData = new ByteAccess(tonyBuf); } ushort sprSizeX, sprSizeY; if ((compact.status & STAT_SHRINK) != 0) { //Clean shrink buffer to avoid corruption Array.Clear(_shrinkBuffer, 0, SHRINK_BUFFER_SIZE); if (SystemVars.Platform == Platform.PSX && (compact.resource != SwordRes.GEORGE_MEGA)) { // PSX Height shrinked sprites sprSizeX = (ushort)((scale * _resMan.ReadUInt16(frameHead.width)) / 256); sprSizeY = (ushort)((scale * (_resMan.ReadUInt16(frameHead.height))) / 256 / 2); FastShrink(sprData, _resMan.ReadUInt16(frameHead.width), (ushort)((_resMan.ReadUInt16(frameHead.height)) / 2), (uint)scale, _shrinkBuffer); } else if (SystemVars.Platform == Platform.PSX) { // PSX width/height shrinked sprites sprSizeX = (ushort)((scale * _resMan.ReadUInt16(frameHead.width)) / 256 / 2); sprSizeY = (ushort)((scale * _resMan.ReadUInt16(frameHead.height)) / 256 / 2); FastShrink(sprData, (ushort)(_resMan.ReadUInt16(frameHead.width) / 2), (ushort)(_resMan.ReadUInt16(frameHead.height) / 2), (uint)scale, _shrinkBuffer); } else { sprSizeX = (ushort)(scale * _resMan.ReadUInt16(frameHead.width) / 256); sprSizeY = (ushort)(scale * _resMan.ReadUInt16(frameHead.height) / 256); FastShrink(sprData, _resMan.ReadUInt16(frameHead.width), _resMan.ReadUInt16(frameHead.height), (uint)scale, _shrinkBuffer); } sprData = new ByteAccess(_shrinkBuffer); } else { sprSizeX = _resMan.ReadUInt16(frameHead.width); if (SystemVars.Platform == Platform.PSX) { // PSX sprites are half height sprSizeY = (ushort)(_resMan.ReadUInt16(frameHead.height) / 2); } else sprSizeY = _resMan.ReadUInt16(frameHead.height); } if ((compact.status & STAT_OVERRIDE) == 0) { //mouse size linked to exact size & coordinates of sprite box - shrink friendly if (_resMan.ReadUInt16((ushort)frameHead.offsetX) != 0 || _resMan.ReadUInt16((ushort)frameHead.offsetY) != 0) { //for megas the mouse area is reduced to account for sprite not //filling the box size is reduced to 1/2 width, 4/5 height compact.mouse_x1 = spriteX + sprSizeX / 4; compact.mouse_x2 = spriteX + 3 * sprSizeX / 4; compact.mouse_y1 = spriteY + sprSizeY / 10; compact.mouse_y2 = spriteY + 9 * sprSizeY / 10; } else { compact.mouse_x1 = spriteX; compact.mouse_x2 = spriteX + sprSizeX; compact.mouse_y1 = spriteY; compact.mouse_y2 = spriteY + sprSizeY; } } ushort sprPitch = sprSizeX; ushort incr; SpriteClipAndSet(ref spriteX, ref spriteY, ref sprSizeX, ref sprSizeY, out incr); if ((sprSizeX > 0) && (sprSizeY > 0)) { if (SystemVars.Platform != Platform.PSX || (compact.type == TYPE_TEXT) || (compact.resource == SwordRes.LVSFLY) || (compact.resource != SwordRes.GEORGE_MEGA && (sprSizeX < 260))) { sprData.Offset += incr; DrawSprite(sprData, spriteX, spriteY, sprSizeX, sprSizeY, sprPitch); } else if (((sprSizeX >= 260) && (sprSizeX < 450)) || ((compact.resource == SwordRes.GMWRITH) && (sprSizeX < 515)) // a psx shrinked sprite (1/2 width) || ((compact.resource == SwordRes.GMPOWER) && (sprSizeX < 515))) { // some needs to be hardcoded, headers don't give useful infos DrawPsxHalfShrinkedSprite(sprData.Data, sprData.Offset + incr, spriteX, spriteY, (ushort)(sprSizeX / 2), sprSizeY, (ushort)(sprPitch / 2)); } else if (sprSizeX >= 450) // A PSX double shrinked sprite (1/3 width) { DrawPsxFullShrinkedSprite(sprData.Data, sprData.Offset + incr, spriteX, spriteY, (ushort)(sprSizeX / 3), sprSizeY, (ushort)(sprPitch / 3)); } else // This is for psx half shrinked, walking george and remaining sprites { DrawPsxHalfShrinkedSprite(sprData.Data, sprData.Offset + incr, spriteX, spriteY, sprSizeX, sprSizeY, sprPitch); } if ((compact.status & STAT_FORE) == 0 && !(SystemVars.Platform == Platform.PSX && (compact.resource == SwordRes.MOUBUSY))) // Check fixes moue sprite being masked by layer, happens only on psx { VerticalMask(spriteX, spriteY, sprSizeX, sprSizeY); } } if (compact.type != TYPE_TEXT) _resMan.ResClose((uint)compact.resource); }
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 void AddToGraphicList(byte listId, uint objId) { if (listId == 0) { Debug.Assert(_foreLength < MAX_FORE); _foreList[_foreLength++] = objId; } if (listId == 1) { Debug.Assert(_sortLength < MAX_SORT); var cpt = _objMan.FetchObject(objId); _sortList[_sortLength].id = (int)objId; _sortList[_sortLength].y = cpt.anim_y; // gives feet coords if boxed mega, otherwise top of sprite box if ((cpt.status & STAT_SHRINK) == 0) { // not a boxed mega using shrinking Header frameRaw = new Header(_resMan.OpenFetchRes((uint)cpt.resource)); FrameHeader frameHead = new FrameHeader(_resMan.FetchFrame(frameRaw.Data, (uint)cpt.frame)); _sortList[_sortLength].y += _resMan.ReadUInt16(frameHead.height) - 1; // now pointing to base of sprite _resMan.ResClose((uint)cpt.resource); } _sortLength++; } if (listId == 2) { Debug.Assert(_backLength < MAX_BACK); _backList[_backLength++] = objId; } }
public void ShowFrame(ushort x, ushort y, uint resId, uint frameNo, byte[] fadeMask = null, sbyte fadeStatus = 0) { byte[] frame = new byte[40 * 40]; int i, j; // PSX top menu is black if (SystemVars.Platform != Platform.PSX) { // Dark gray background frame.Set(0, 199, frame.Length); } if (resId != 0xffffffff) { FrameHeader frameHead = new FrameHeader(_resMan.FetchFrame(_resMan.OpenFetchRes(resId), frameNo)); var frameData = new ByteAccess(frameHead.Data.Data, frameHead.Data.Offset + FrameHeader.Size); if (SystemVars.Platform == Platform.PSX) { //We need to decompress PSX frames var frameBufferPSX = new byte[_resMan.ReadUInt16(frameHead.width) * _resMan.ReadUInt16(frameHead.height) / 2]; DecompressHIF(frameData.Data, frameData.Offset, frameBufferPSX); for (i = 0; i < _resMan.ReadUInt16(frameHead.height) / 2; i++) { for (j = 0; j < _resMan.ReadUInt16(frameHead.width); j++) { var data = frameBufferPSX[i * _resMan.ReadUInt16(frameHead.width) + j]; frame[(i * 2 + 4) * 40 + j + 2] = data; frame[(i * 2 + 1 + 4) * 40 + j + 2] = data; //Linedoubling the sprite } } } else { for (i = 0; i < _resMan.ReadUInt16(frameHead.height); i++) for (j = 0; j < _resMan.ReadUInt16(frameHead.height); j++) frame[(i + 4) * 40 + j + 2] = frameData[i * _resMan.ReadUInt16(frameHead.width) + j]; } _resMan.ResClose(resId); } if (fadeMask != null) { for (i = 0; i < 40; i++) { for (j = 0; j < 40; j++) { if (fadeMask[((i % 8) * 8) + (j % 8)] >= fadeStatus) frame[i * 40 + j] = 0; } } } _system.GraphicsManager.CopyRectToScreen(frame, 40, x, y, 40, 40); }
private int fnISpeak(SwordObject cpt, int id, int cdt, int textNo, int spr, int f, int z, int x) { _speechClickDelay = 3; if (((textNo & ~1) == 0x3f0012) && (cdt == 0) && (spr == 0)) { cdt = SwordRes.GEOSTDLCDT; // workaround for missing animation when examining spr = SwordRes.GEOSTDL; // the conductor on the train roof } cpt.logic = LOGIC_speech; // first setup the talk animation if (cdt != 0 && (spr == 0)) { // if 'cdt' is non-zero but 'spr' is zero - 'cdt' is an anim table tag var animTabData = _resMan.OpenFetchRes((uint)cdt); var anim = new AnimSet(animTabData, Header.Size + cpt.dir * AnimSet.Size); cpt.anim_resource = (int)_resMan.ReadUInt32(anim.cdt); if (anim.cdt != 0) cpt.resource = (int)_resMan.ReadUInt32(anim.spr); _resMan.ResClose((uint)cdt); } else { cpt.anim_resource = cdt; if (cdt != 0) cpt.resource = spr; } cpt.anim_pc = 0; // start anim from first frame if (cpt.anim_resource != 0) { if (cpt.resource == 0) throw new InvalidOperationException($"ID {id}: Can't run anim with cdt={cdt}, spr={spr}"); FrameHeader frameHead = new FrameHeader(_resMan.FetchFrame(_resMan.OpenFetchRes((uint)cpt.resource), 0)); if (frameHead.offsetX != 0 && frameHead.offsetY != 0) { // is this a boxed mega? cpt.status |= STAT_SHRINK; cpt.anim_x = cpt.xcoord; cpt.anim_y = cpt.ycoord; } else cpt.status &= ~STAT_SHRINK; _resMan.ResClose((uint)cpt.resource); } if (SystemVars.PlaySpeech != 0) _speechRunning = _sound.StartSpeech((ushort)(textNo >> 16), (ushort)(textNo & 0xFFFF)); else _speechRunning = false; _speechFinished = false; if (SystemVars.ShowText != 0 || (!_speechRunning)) { _textRunning = true; var text = _objMan.LockText((uint) textNo); cpt.speech_time = GetTextLength(text) + 5; uint textCptId = _textMan.LowTextManager(text, cpt.speech_width, (byte)cpt.speech_pen); _objMan.UnlockText((uint) textNo); SwordObject textCpt = _objMan.FetchObject(textCptId); textCpt.screen = cpt.screen; textCpt.target = (int)textCptId; // the graphic is a property of Text, so we don't lock/unlock it. ushort textSpriteWidth = _resMan.ReadUInt16(new FrameHeader(_textMan.GiveSpriteData((byte)textCpt.target)).width); ushort textSpriteHeight = _resMan.ReadUInt16(new FrameHeader(_textMan.GiveSpriteData((byte)textCpt.target)).height); cpt.text_id = (int)textCptId; // now set text coords, above the player, usually const int TEXT_MARGIN = 3; // distance kept from edges of screen const int ABOVE_HEAD = 20; // distance kept above talking sprite ushort textX, textY; if (((id == GEORGE) || ((id == NICO) && (ScriptVars[(int)ScriptVariableNames.SCREEN] == 10))) && (cpt.anim_resource == 0)) { // if George is doing Voice-Over text (centered at the bottom of the screen) textX = (ushort)(ScriptVars[(int)ScriptVariableNames.SCROLL_OFFSET_X] + 128 + (640 / 2) - textSpriteWidth / 2); textY = (ushort)(ScriptVars[(int)ScriptVariableNames.SCROLL_OFFSET_Y] + 128 + 400); } else { if ((id == GEORGE) && (ScriptVars[(int)ScriptVariableNames.SCREEN] == 79)) textX = (ushort)cpt.mouse_x2; // move it off george's head else textX = (ushort)((cpt.mouse_x1 + cpt.mouse_x2) / 2 - textSpriteWidth / 2); textY = (ushort)(cpt.mouse_y1 - textSpriteHeight - ABOVE_HEAD); } // now ensure text is within visible screen ushort textLeftMargin, textRightMargin, textTopMargin, textBottomMargin; textLeftMargin = (ushort)(Screen.SCREEN_LEFT_EDGE + TEXT_MARGIN + ScriptVars[(int)ScriptVariableNames.SCROLL_OFFSET_X]); textRightMargin = (ushort)(Screen.SCREEN_RIGHT_EDGE - TEXT_MARGIN + ScriptVars[(int)ScriptVariableNames.SCROLL_OFFSET_X] - textSpriteWidth); textTopMargin = (ushort)(Screen.SCREEN_TOP_EDGE + TEXT_MARGIN + ScriptVars[(int)ScriptVariableNames.SCROLL_OFFSET_Y]); textBottomMargin = (ushort)(Screen.SCREEN_BOTTOM_EDGE - TEXT_MARGIN + ScriptVars[(int)ScriptVariableNames.SCROLL_OFFSET_Y] - textSpriteHeight); textCpt.anim_x = textCpt.xcoord = ScummHelper.Clip(textX, textLeftMargin, textRightMargin); textCpt.anim_y = textCpt.ycoord = ScummHelper.Clip(textY, textTopMargin, textBottomMargin); } return SCRIPT_STOP; }
private int fnAnim(SwordObject cpt, int id, int cdt, int spr, int e, int f, int z, int x) { if (cdt != 0 && (spr == 0)) { var animTab = _resMan.OpenFetchRes((uint)cdt); var animOffset = Header.Size + cpt.dir * AnimSet.Size; var anim = new AnimSet(animTab, animOffset); cpt.anim_resource = (int)_resMan.ReadUInt32(anim.cdt); cpt.resource = (int)_resMan.ReadUInt32(anim.spr); _resMan.ResClose((uint)cdt); } else { cpt.anim_resource = cdt; cpt.resource = spr; } if ((cpt.anim_resource == 0) || (cpt.resource == 0)) throw new InvalidOperationException($"fnAnim called width ({cdt}/{spr}) => ({cpt.anim_resource}/{cpt.resource})"); var frameHead = new FrameHeader(_resMan.FetchFrame(_resMan.OpenFetchRes((uint)cpt.resource), 0)); if (frameHead.offsetX != 0 || frameHead.offsetY != 0) { // boxed mega anim? cpt.status |= STAT_SHRINK; cpt.anim_x = cpt.xcoord; // set anim coords to 'feet' coords - only need to do this once cpt.anim_y = cpt.ycoord; } else { // Anim_driver sets anim coords to cdt coords for every frame of a loose anim cpt.status &= ~STAT_SHRINK; } _resMan.ResClose((uint)cpt.resource); cpt.logic = LOGIC_anim; cpt.anim_pc = 0; cpt.sync = 0; return SCRIPT_STOP; }
private void RenderVolumeBar(byte id, byte volL, byte volR) { ushort destX = (ushort)(_volumeButtons[id].x + 20); ushort destY = (ushort)(_volumeButtons[id].y + 116); for (var chCnt = 0; chCnt < 2; chCnt++) { byte vol = (chCnt == 0) ? volL : volR; FrameHeader frHead = new FrameHeader(_resMan.FetchFrame(_resMan.OpenFetchRes(SwordRes.SR_VLIGHT), (uint)((vol + 15) >> 4))); var destMem = new ByteAccess(_screenBuf, destY * Screen.SCREEN_WIDTH + destX); var srcMem = new ByteAccess(frHead.Data.Data, frHead.Data.Offset + FrameHeader.Size); ushort barHeight = _resMan.ReadUInt16(frHead.height); byte[] psxVolBuf = null; if (SystemVars.Platform == Platform.PSX) { psxVolBuf = new byte[_resMan.ReadUInt16(frHead.height) / 2 * _resMan.ReadUInt16(frHead.width)]; Screen.DecompressHIF(srcMem.Data, srcMem.Offset, psxVolBuf); srcMem = new ByteAccess(psxVolBuf); barHeight /= 2; } for (ushort cnty = 0; cnty < barHeight; cnty++) { Array.Copy(srcMem.Data, srcMem.Offset, destMem.Data, destMem.Offset, _resMan.ReadUInt16(frHead.width)); if (SystemVars.Platform == Platform.PSX) { //linedoubling destMem.Offset += Screen.SCREEN_WIDTH; Array.ConstrainedCopy(srcMem.Data, srcMem.Offset, destMem.Data, destMem.Offset, _resMan.ReadUInt16(frHead.width)); } srcMem.Offset += _resMan.ReadUInt16(frHead.width); destMem.Offset += Screen.SCREEN_WIDTH; } _system.GraphicsManager.CopyRectToScreen(_screenBuf, destY * Screen.SCREEN_WIDTH + destX, Screen.SCREEN_WIDTH, destX, destY, _resMan.ReadUInt16(frHead.width), _resMan.ReadUInt16(frHead.height)); _resMan.ResClose(SwordRes.SR_VLIGHT); destX += 32; } }
private void SetupSaveRestorePanel(bool saving) { ReadSavegameDescriptions(); FrameHeader savePanel = new FrameHeader(_resMan.FetchFrame(_resMan.OpenFetchRes(SwordRes.SR_WINDOW), 0)); short panelX = (short)((640 - _resMan.ReadUInt16(savePanel.width)) / 2); short panelY = (short)((480 - _resMan.ReadUInt16(savePanel.height)) / 2); ControlButton panel = new ControlButton((ushort)panelX, (ushort)panelY, SwordRes.SR_WINDOW, 0, 0, _resMan, _screenBuf, _system); panel.Draw(); _resMan.ResClose(SwordRes.SR_WINDOW); CreateButtons(_saveButtons, 14); RenderText(_lStrings[(int)LangStrings.STR_CANCEL], _saveButtons[13].x - 10, _saveButtons[13].y, TextModes.TEXT_RIGHT_ALIGN); if (saving) { RenderText(_lStrings[(int)LangStrings.STR_SAVE], _saveButtons[12].x + 30, _saveButtons[13].y, TextModes.TEXT_LEFT_ALIGN); } else { RenderText(_lStrings[(int)LangStrings.STR_RESTORE], _saveButtons[12].x + 30, _saveButtons[13].y, TextModes.TEXT_LEFT_ALIGN); } ReadSavegameDescriptions(); _selectedSavegame = 255; ShowSavegameNames(); }
private void RenderText(string str, int x, int y, TextModes mode) { int i = 0; var font = _font; if (mode.HasFlag(TextModes.TEXT_RED_FONT)) { mode &= ~TextModes.TEXT_RED_FONT; font = _redFont; } if (mode == TextModes.TEXT_RIGHT_ALIGN) // negative x coordinate means right-aligned. x -= GetTextWidth(str); else if (mode == TextModes.TEXT_CENTER) x -= GetTextWidth(str) / 2; ushort destX = (ushort)x; while (i < str.Length) { var dst = new ByteAccess(_screenBuf, +y * Screen.SCREEN_WIDTH + destX); FrameHeader chSpr = new FrameHeader(_resMan.FetchFrame(font, (uint)(str[i] - 32))); var sprData = new ByteAccess(chSpr.Data.Data, chSpr.Data.Offset + FrameHeader.Size); if (SystemVars.Platform == Platform.PSX) { //Text fonts are compressed in psx version var HIFbuf = new byte[_resMan.ReadUInt16(chSpr.height) * _resMan.ReadUInt16(chSpr.width)]; Screen.DecompressHIF(sprData.Data, sprData.Offset, HIFbuf); sprData = new ByteAccess(HIFbuf); } for (ushort cnty = 0; cnty < _resMan.ReadUInt16(chSpr.height); cnty++) { for (ushort cntx = 0; cntx < _resMan.ReadUInt16(chSpr.width); cntx++) { if (sprData[cntx] != 0) dst[cntx] = sprData[cntx]; } if (SystemVars.Platform == Platform.PSX) { //On PSX version we need to double horizontal lines dst.Offset += Screen.SCREEN_WIDTH; for (ushort cntx = 0; cntx < _resMan.ReadUInt16(chSpr.width); cntx++) if (sprData[cntx] != 0) dst[cntx] = sprData[cntx]; } sprData.Offset += _resMan.ReadUInt16(chSpr.width); dst.Offset += Screen.SCREEN_WIDTH; } destX = (ushort)(destX + _resMan.ReadUInt16(chSpr.width) - 3); i++; } _system.GraphicsManager.CopyRectToScreen(_screenBuf, +y * Screen.SCREEN_WIDTH + x, Screen.SCREEN_WIDTH, x, y, (destX - x) + 3, 28); }