scummvm/engines/sci/gfx/gfx_driver.cpp
Filippos Karapetis df29b0067e - Unified the screen buffers that are used by the current and the new GUI
- Replaced the FreeSCI line drawing code (which is actually Bresenham) with Graphics::drawLine(), after discussing with waltervn. This shouldn't bring any regressions, as we're no longer offering the option to scale the background at a vector level. After playing through some of the games, I haven't noticed any regressions
- Some cleanup

svn-id: r44692
2009-10-06 12:26:13 +00:00

246 lines
7.9 KiB
C++

/* 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/scummsys.h"
#include "common/system.h"
#include "graphics/cursorman.h"
#include "graphics/primitives.h"
#include "graphics/surface.h"
#include "sci/sci.h"
#include "sci/gui/gui_screen.h"
#include "sci/gfx/gfx_driver.h"
#include "sci/gfx/gfx_tools.h"
#include "sci/gui/gui_screen.h"
namespace Sci {
GfxDriver::GfxDriver(SciGuiScreen *screen, int scaleFactor) : _screen(screen) {
_mode = gfx_new_mode(scaleFactor, new Palette(256));
if (_mode->palette)
_mode->palette->name = "global";
}
GfxDriver::~GfxDriver() {
}
// Drawing operations
static void drawProc(int x, int y, int c, void *data) {
GfxDriver *drv = (GfxDriver *)data;
byte *p = drv->_screen->_displayScreen;
uint8 col = c;
memcpy(p + (y * drv->_screen->_width * drv->getMode()->scaleFactor + x), &col, 1);
}
static void drawProcPriority(int x, int y, int c, void *data) {
GfxDriver *drv = (GfxDriver *)data;
byte *p = drv->_screen->_priorityScreen;
uint8 col = c;
memcpy(p + (y * drv->_screen->_width + x), &col, 1);
}
void GfxDriver::drawLine(Common::Point start, Common::Point end, gfx_color_t color,
gfx_line_mode_t line_mode, gfx_line_style_t line_style) {
uint32 scolor = color.visual.getParentIndex();
int scaleFactor = (line_mode == GFX_LINE_MODE_FINE)? 1: _mode->scaleFactor;
int xsize = _mode->xsize;
int ysize = _mode->ysize;
if (color.mask & GFX_MASK_VISUAL) {
Common::Point nstart, nend;
for (int xc = 0; xc < scaleFactor; xc++) {
for (int yc = 0; yc < scaleFactor; yc++) {
nstart.x = CLIP<int16>(start.x + xc, 0, xsize);
nstart.y = CLIP<int16>(start.y + yc, 0, ysize);
nend.x = CLIP<int16>(end.x + xc, 0, xsize - 1);
nend.y = CLIP<int16>(end.y + yc, 0, ysize - 1);
Graphics::drawLine(nstart.x, nstart.y, nend.x, nend.y, scolor, drawProc, this);
if (color.mask & GFX_MASK_PRIORITY) {
Graphics::drawLine(nstart.x, nstart.y, nend.x, nend.y, color.priority, drawProcPriority, this);
}
}
}
}
}
void GfxDriver::drawFilledRect(rect_t rect, gfx_color_t color1, gfx_color_t color2,
gfx_rectangle_fill_t shade_mode) {
if (color1.mask & GFX_MASK_VISUAL) {
for (int i = rect.y; i < rect.y + rect.height; i++) {
memset(_screen->_displayScreen + (i * _mode->xsize + rect.x),
color1.visual.getParentIndex(), rect.width);
}
}
if (color1.mask & GFX_MASK_PRIORITY) {
gfx_clip_box_basic(&rect, _screen->_width - 1, _screen->_height - 1);
gfx_draw_box_buffer(_screen->_priorityScreen, _screen->_width, rect, color1.priority);
}
}
// Pixmap operations
void GfxDriver::drawPixmap(gfx_pixmap_t *pxm, int priority, rect_t src, rect_t dest, gfx_buffer_t buffer) {
byte *destBuffer = (buffer == GFX_BUFFER_STATIC) ? _screen->_visualScreen : _screen->_displayScreen;
byte *destPriority = (buffer == GFX_BUFFER_STATIC) ? _screen->_controlScreen : _screen->_priorityScreen;
if (dest.width != src.width || dest.height != src.height) {
warning("Attempt to scale pixmap (%dx%d)->(%dx%d): Not supported\n", src.width, src.height, dest.width, dest.height);
return;
}
gfx_crossblit_pixmap(_mode, pxm, priority, src, dest, destBuffer,
_mode->xsize,
destPriority,
_screen->_width, 1, 0);
}
void GfxDriver::grabPixmap(rect_t src, gfx_pixmap_t *pxm, gfx_map_mask_t map) {
if (src.x < 0 || src.y < 0)
error("Attempt to grab pixmap from invalid coordinates (%d,%d)", src.x, src.y);
if (!pxm->data)
error("Attempt to grab pixmap to unallocated memory");
switch (map) {
case GFX_MASK_VISUAL:
pxm->width = src.width;
pxm->height = src.height;
for (int i = 0; i < src.height; i++) {
memcpy(pxm->data + i * src.width,
_screen->_displayScreen + ((i + src.y) * _mode->xsize + src.x),
src.width);
}
break;
case GFX_MASK_PRIORITY:
warning("FIXME: priority map grab not implemented yet");
break;
default:
error("Attempt to grab pixmap from invalid map 0x%02x", map);
}
}
// Buffer operations
void GfxDriver::update(rect_t src, Common::Point dest, gfx_buffer_t buffer) {
switch (buffer) {
case GFX_BUFFER_BACK:
for (int i = 0; i < src.height; i++) {
memcpy(_screen->_displayScreen + ( (dest.y + i) * _mode->xsize + dest.x),
_screen->_visualScreen + ( (src.y + i) * _mode->xsize + src.x), src.width );
}
if ((src.x == dest.x) && (src.y == dest.y)) {
int offset = src.x + (src.y * _screen->_width);
gfx_clip_box_basic(&src, _screen->_width, _screen->_height);
while (src.height--) {
memcpy(_screen->_priorityScreen + offset, _screen->_controlScreen + offset, _screen->_width);
offset += _screen->_width;
}
}
break;
case GFX_BUFFER_FRONT: {
g_system->copyRectToScreen(_screen->_displayScreen + (src.x + src.y * _mode->xsize), _mode->xsize, dest.x, dest.y, src.width, src.height);
g_system->updateScreen();
break;
}
default:
error("Invalid buffer %d in update", buffer);
}
}
void GfxDriver::setStaticBuffer(gfx_pixmap_t *pic, gfx_pixmap_t *priority) {
memcpy(_screen->_visualScreen, pic->data, _mode->xsize * _mode->ysize);
memcpy(_screen->_controlScreen, priority->index_data, _mode->xsize * _mode->ysize);
}
// Mouse pointer operations
void GfxDriver::setPointer(gfx_pixmap_t *pointer, Common::Point *hotspot) {
if (!pointer || !hotspot) {
CursorMan.showMouse(false);
return;
}
pointer->palette->mergeInto(_mode->palette);
// Scale cursor and map its colors to the global palette
byte *cursorData = new byte[pointer->width * pointer->height];
for (int yc = 0; yc < pointer->index_height; yc++) {
byte *linebase = &cursorData[yc * (pointer->width * _mode->scaleFactor)];
for (int xc = 0; xc < pointer->index_width; xc++) {
byte color = pointer->index_data[yc * pointer->index_width + xc];
if (color < pointer->palette->size())
color = pointer->palette->getColor(color).getParentIndex();
memset(&linebase[xc], color, _mode->scaleFactor);
}
// Scale vertically
for (int scalectr = 1; scalectr < _mode->scaleFactor; scalectr++)
memcpy(&linebase[pointer->width * scalectr], linebase, pointer->width);
}
byte color_key = pointer->color_key;
if ((pointer->color_key != GFX_PIXMAP_COLOR_KEY_NONE) && ((uint)pointer->color_key < pointer->palette->size()))
color_key = pointer->palette->getColor(pointer->color_key).getParentIndex();
CursorMan.replaceCursor(cursorData, pointer->width, pointer->height, hotspot->x, hotspot->y, color_key);
CursorMan.showMouse(true);
delete[] cursorData;
cursorData = 0;
}
void GfxDriver::animatePalette(int fromColor, int toColor, int stepCount) {
int i;
PaletteEntry firstColor = _mode->palette->getColor(fromColor);
PaletteEntry loopColor;
for (i=fromColor+1; i<=toColor; i++) {
loopColor = _mode->palette->getColor(i);
loopColor.r = 0;
loopColor.g = 0;
loopColor.b = 0;
_mode->palette->makeSystemColor(i-1, loopColor); // loopColor.r, loopColor.g, loopColor.b);
}
// _mode->palette->setColor(toColor, firstColor.r, firstColor.g, firstColor.b);
_mode->palette->makeSystemColor(toColor, firstColor);
}
} // End of namespace Sci