diff options
Diffstat (limited to 'engines/sci/graphics/paint16.cpp')
| -rw-r--r-- | engines/sci/graphics/paint16.cpp | 333 |
1 files changed, 333 insertions, 0 deletions
diff --git a/engines/sci/graphics/paint16.cpp b/engines/sci/graphics/paint16.cpp new file mode 100644 index 0000000000..539059c4d2 --- /dev/null +++ b/engines/sci/graphics/paint16.cpp @@ -0,0 +1,333 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/util.h" +#include "common/stack.h" +#include "graphics/primitives.h" + +#include "sci/sci.h" +#include "sci/engine/state.h" +#include "sci/engine/selector.h" +#include "sci/graphics/cache.h" +#include "sci/graphics/ports.h" +#include "sci/graphics/paint16.h" +#include "sci/graphics/animate.h" +#include "sci/graphics/font.h" +#include "sci/graphics/picture.h" +#include "sci/graphics/view.h" +#include "sci/graphics/screen.h" +#include "sci/graphics/palette.h" +#include "sci/graphics/text.h" + +namespace Sci { + +GfxPaint16::GfxPaint16(ResourceManager *resMan, SegManager *segMan, Kernel *kernel, GfxCache *cache, GfxPorts *ports, Screen *screen, SciPalette *palette) + : _resMan(resMan), _segMan(segMan), _kernel(kernel), _cache(cache), _ports(ports), _screen(screen), _palette(palette) { +} + +GfxPaint16::~GfxPaint16() { +} + +void GfxPaint16::init(Text *text) { + _text = text; + + _EGAdrawingVisualize = false; +} + +void GfxPaint16::setEGAdrawingVisualize(bool state) { + _EGAdrawingVisualize = state; +} + +void GfxPaint16::drawPicture(GuiResourceId pictureId, int16 animationNr, bool mirroredFlag, bool addToFlag, GuiResourceId paletteId) { + SciGuiPicture *picture = new SciGuiPicture(_resMan, _ports, _screen, _palette, pictureId, _EGAdrawingVisualize); + + // do we add to a picture? if not -> clear screen with white + if (!addToFlag) + clearScreen(_screen->getColorWhite()); + + picture->draw(animationNr, mirroredFlag, addToFlag, paletteId); + delete picture; +} + +// This one is the only one that updates screen! +void GfxPaint16::drawCelAndShow(GuiResourceId viewId, int16 loopNo, int16 celNo, uint16 leftPos, uint16 topPos, byte priority, uint16 paletteNo, uint16 scaleX, uint16 scaleY) { + View *view = _cache->getView(viewId); + Common::Rect celRect; + + if (view) { + celRect.left = leftPos; + celRect.top = topPos; + celRect.right = celRect.left + view->getWidth(loopNo, celNo); + celRect.bottom = celRect.top + view->getHeight(loopNo, celNo); + + drawCel(view, loopNo, celNo, celRect, priority, paletteNo, scaleX, scaleY); + + if (getSciVersion() >= SCI_VERSION_1_1) { + if (!_screen->_picNotValidSci11) { + bitsShow(celRect); + } + } else { + if (!_screen->_picNotValid) + bitsShow(celRect); + } + } +} + +// This version of drawCel is not supposed to call BitsShow()! +void GfxPaint16::drawCel(GuiResourceId viewId, int16 loopNo, int16 celNo, Common::Rect celRect, byte priority, uint16 paletteNo, uint16 scaleX, uint16 scaleY) { + drawCel(_cache->getView(viewId), loopNo, celNo, celRect, priority, paletteNo, scaleX, scaleY); +} + +// This version of drawCel is not supposed to call BitsShow()! +void GfxPaint16::drawCel(View *view, int16 loopNo, int16 celNo, Common::Rect celRect, byte priority, uint16 paletteNo, uint16 scaleX, uint16 scaleY) { + Common::Rect clipRect = celRect; + clipRect.clip(_ports->_curPort->rect); + if (clipRect.isEmpty()) // nothing to draw + return; + + Common::Rect clipRectTranslated = clipRect; + _ports->offsetRect(clipRectTranslated); + if (scaleX == 128 && scaleY == 128) { + view->draw(celRect, clipRect, clipRectTranslated, loopNo, celNo, priority, paletteNo, false); + } else { + view->drawScaled(celRect, clipRect, clipRectTranslated, loopNo, celNo, priority, scaleX, scaleY); + } +} + +// This is used as replacement for drawCelAndShow() when hires-cels are drawn to screen +// Hires-cels are available only SCI 1.1+ +void GfxPaint16::drawHiresCelAndShow(GuiResourceId viewId, int16 loopNo, int16 celNo, uint16 leftPos, uint16 topPos, byte priority, uint16 paletteNo, reg_t upscaledHiresHandle, uint16 scaleX, uint16 scaleY) { + View *view = _cache->getView(viewId); + Common::Rect celRect, curPortRect, clipRect, clipRectTranslated; + Common::Point curPortPos; + bool upscaledHiresHack = false; + + if (view) { + if ((leftPos == 0) && (topPos == 0)) { + // HACK: in kq6, we get leftPos&topPos == 0 SOMETIMES, that's why we need to get coordinates from upscaledHiresHandle + // I'm not sure if this is what we are supposed to do or if there is some other bug that actually makes + // coordinates to be 0 in the first place + byte *memoryPtr = NULL; + memoryPtr = kmem(_segMan, upscaledHiresHandle); + if (memoryPtr) { + Common::Rect upscaledHiresRect; + _screen->bitsGetRect(memoryPtr, &upscaledHiresRect); + leftPos = upscaledHiresRect.left; + topPos = upscaledHiresRect.top; + upscaledHiresHack = true; + } + } + + celRect.left = leftPos; + celRect.top = topPos; + celRect.right = celRect.left + view->getWidth(loopNo, celNo); + celRect.bottom = celRect.top + view->getHeight(loopNo, celNo); + // adjust curPort to upscaled hires + clipRect = celRect; + curPortRect = _ports->_curPort->rect; + curPortRect.top *= 2; curPortRect.bottom *= 2; curPortRect.bottom++; + curPortRect.left *= 2; curPortRect.right *= 2; curPortRect.right++; + clipRect.clip(curPortRect); + if (clipRect.isEmpty()) // nothing to draw + return; + + clipRectTranslated = clipRect; + if (!upscaledHiresHack) { + curPortPos.x = _ports->_curPort->left * 2; curPortPos.y = _ports->_curPort->top * 2; + clipRectTranslated.top += curPortPos.y; clipRectTranslated.bottom += curPortPos.y; + clipRectTranslated.left += curPortPos.x; clipRectTranslated.right += curPortPos.x; + } + + view->draw(celRect, clipRect, clipRectTranslated, loopNo, celNo, priority, paletteNo, true); + if (!_screen->_picNotValidSci11) { + _screen->copyDisplayRectToScreen(clipRectTranslated); + } + } +} + +void GfxPaint16::clearScreen(byte color) { + fillRect(_ports->_curPort->rect, SCI_SCREEN_MASK_ALL, color, 0, 0); +} + +void GfxPaint16::invertRect(const Common::Rect &rect) { + int16 oldpenmode = _ports->_curPort->penMode; + _ports->_curPort->penMode = 2; + fillRect(rect, 1, _ports->_curPort->penClr, _ports->_curPort->backClr); + _ports->_curPort->penMode = oldpenmode; +} + +void GfxPaint16::eraseRect(const Common::Rect &rect) { + fillRect(rect, 1, _ports->_curPort->backClr); +} + +void GfxPaint16::paintRect(const Common::Rect &rect) { + fillRect(rect, 1, _ports->_curPort->penClr); +} + +void GfxPaint16::fillRect(const Common::Rect &rect, int16 drawFlags, byte clrPen, byte clrBack, byte bControl) { + Common::Rect r = rect; + r.clip(_ports->_curPort->rect); + if (r.isEmpty()) // nothing to fill + return; + + int16 oldPenMode = _ports->_curPort->penMode; + _ports->offsetRect(r); + int16 x, y; + byte curVisual; + + // Doing visual first + if (drawFlags & SCI_SCREEN_MASK_VISUAL) { + if (oldPenMode == 2) { // invert mode + for (y = r.top; y < r.bottom; y++) { + for (x = r.left; x < r.right; x++) { + curVisual = _screen->getVisual(x, y); + if (curVisual == clrPen) { + _screen->putPixel(x, y, 1, clrBack, 0, 0); + } else if (curVisual == clrBack) { + _screen->putPixel(x, y, 1, clrPen, 0, 0); + } + } + } + } else { // just fill rect with ClrPen + for (y = r.top; y < r.bottom; y++) { + for (x = r.left; x < r.right; x++) { + _screen->putPixel(x, y, 1, clrPen, 0, 0); + } + } + } + } + + if (drawFlags < 2) + return; + drawFlags &= SCI_SCREEN_MASK_PRIORITY|SCI_SCREEN_MASK_CONTROL; + + if (oldPenMode != 2) { + for (y = r.top; y < r.bottom; y++) { + for (x = r.left; x < r.right; x++) { + _screen->putPixel(x, y, drawFlags, 0, clrBack, bControl); + } + } + } else { + for (y = r.top; y < r.bottom; y++) { + for (x = r.left; x < r.right; x++) { + _screen->putPixel(x, y, drawFlags, 0, !_screen->getPriority(x, y), !_screen->getControl(x, y)); + } + } + } +} + +void GfxPaint16::frameRect(const Common::Rect &rect) { + Common::Rect r; + // left + r = rect; + r.right = rect.left + 1; + paintRect(r); + // right + r.right = rect.right; + r.left = rect.right - 1; + paintRect(r); + //top + r.left = rect.left; + r.bottom = rect.top + 1; + paintRect(r); + //bottom + r.bottom = rect.bottom; + r.top = rect.bottom - 1; + paintRect(r); +} + +void GfxPaint16::bitsShow(const Common::Rect &rect) { + Common::Rect workerRect(rect.left, rect.top, rect.right, rect.bottom); + workerRect.clip(_ports->_curPort->rect); + if (workerRect.isEmpty()) // nothing to show + return; + + _ports->offsetRect(workerRect); + _screen->copyRectToScreen(workerRect); +} + +void GfxPaint16::bitsShowHires(const Common::Rect &rect) { + _screen->copyDisplayRectToScreen(rect); +} + +reg_t GfxPaint16::bitsSave(const Common::Rect &rect, byte screenMask) { + reg_t memoryId; + byte *memoryPtr; + int size; + + Common::Rect workerRect(rect.left, rect.top, rect.right, rect.bottom); + workerRect.clip(_ports->_curPort->rect); + if (workerRect.isEmpty()) // nothing to save + return NULL_REG; + + if (screenMask == SCI_SCREEN_MASK_DISPLAY) { + // Adjust rect to upscaled hires, but dont adjust according to port + workerRect.top *= 2; workerRect.bottom *= 2; workerRect.bottom++; + workerRect.left *= 2; workerRect.right *= 2; workerRect.right++; + } else { + _ports->offsetRect(workerRect); + } + + // now actually ask _screen how much space it will need for saving + size = _screen->bitsGetDataSize(workerRect, screenMask); + + memoryId = kalloc(_segMan, "SaveBits()", size); + memoryPtr = kmem(_segMan, memoryId); + _screen->bitsSave(workerRect, screenMask, memoryPtr); + return memoryId; +} + +void GfxPaint16::bitsGetRect(reg_t memoryHandle, Common::Rect *destRect) { + byte *memoryPtr = NULL; + + if (!memoryHandle.isNull()) { + memoryPtr = kmem(_segMan, memoryHandle); + + if (memoryPtr) { + _screen->bitsGetRect(memoryPtr, destRect); + } + } +} + +void GfxPaint16::bitsRestore(reg_t memoryHandle) { + byte *memoryPtr = NULL; + + if (!memoryHandle.isNull()) { + memoryPtr = kmem(_segMan, memoryHandle); + + if (memoryPtr) { + _screen->bitsRestore(memoryPtr); + kfree(_segMan, memoryHandle); + } + } +} + +void GfxPaint16::bitsFree(reg_t memoryHandle) { + if (!memoryHandle.isNull()) { + kfree(_segMan, memoryHandle); + } +} + +} // End of namespace Sci |
