diff options
author | Torbjörn Andersson | 2005-02-19 14:02:16 +0000 |
---|---|---|
committer | Torbjörn Andersson | 2005-02-19 14:02:16 +0000 |
commit | 43cfe01f3d8d2307a23933920cce43740871f367 (patch) | |
tree | fe56072f944bc980981d5f0cfe1683116645d076 | |
parent | 0de5fa2f33147529edcf4dccd24a2750b23a2867 (diff) | |
download | scummvm-rg350-43cfe01f3d8d2307a23933920cce43740871f367.tar.gz scummvm-rg350-43cfe01f3d8d2307a23933920cce43740871f367.tar.bz2 scummvm-rg350-43cfe01f3d8d2307a23933920cce43740871f367.zip |
This is the second part of the BS2 restructuring. There are two new
classes: Screen and Mouse. Screen handles most of the drawing, except the
mouse cursor and in-game menus.
The old Graphics class is no more.
I've also fixed some "reverse stereo" regressions from the first part of
the restructuring.
I'm not sure what the next step will be, but hopefully it will be smaller
than this one was.
svn-id: r16812
39 files changed, 1636 insertions, 1511 deletions
diff --git a/sword2/anims.cpp b/sword2/anims.cpp index 385ff1885b..f8db3c57eb 100644 --- a/sword2/anims.cpp +++ b/sword2/anims.cpp @@ -26,8 +26,10 @@ #include "common/stdafx.h" #include "common/file.h" + #include "sword2/sword2.h" #include "sword2/defs.h" +#include "sword2/build_display.h" #include "sword2/controls.h" #include "sword2/interpreter.h" #include "sword2/logic.h" @@ -36,7 +38,6 @@ #include "sword2/resman.h" #include "sword2/sound.h" #include "sword2/driver/animation.h" -#include "sword2/driver/d_draw.h" namespace Sword2 { diff --git a/sword2/build_display.cpp b/sword2/build_display.cpp index 98f738f75b..26f997a2ff 100644 --- a/sword2/build_display.cpp +++ b/sword2/build_display.cpp @@ -24,19 +24,77 @@ #include "common/stdafx.h" #include "common/system.h" + #include "sword2/sword2.h" #include "sword2/console.h" #include "sword2/defs.h" -#include "sword2/interpreter.h" #include "sword2/logic.h" #include "sword2/maketext.h" -#include "sword2/memory.h" +#include "sword2/mouse.h" #include "sword2/resman.h" -#include "sword2/driver/d_draw.h" namespace Sword2 { -void Sword2Engine::buildDisplay(void) { +Screen::Screen(Sword2Engine *vm, int16 width, int16 height) { + _vm = vm; + + _dirtyGrid = _buffer = NULL; + + _vm->_system->initSize(width, height); + + _screenWide = width; + _screenDeep = height; + + _gridWide = width / CELLWIDE; + _gridDeep = height / CELLDEEP; + + if ((width % CELLWIDE) || (height % CELLDEEP)) + error("Bad cell size"); + + _dirtyGrid = (byte *) calloc(_gridWide, _gridDeep); + if (!_dirtyGrid) + error("Could not initialise dirty grid"); + + _buffer = (byte *) malloc(width * height); + if (!_buffer) + error("Could not initialise display"); + + for (int i = 0; i < ARRAYSIZE(_blockSurfaces); i++) + _blockSurfaces[i] = NULL; + + _lightMask = NULL; + _needFullRedraw = false; + + memset(&_thisScreen, 0, sizeof(_thisScreen)); + + _fps = 0; + _frameCount = 0; + _cycleTime = 0; + + _lastPaletteRes = 0; + + _scrollFraction = 16; + + _largestLayerArea = 0; + _largestSpriteArea = 0; + + strcpy(_largestLayerInfo, "largest layer: none registered"); + strcpy(_largestSpriteInfo, "largest sprite: none registered"); + + _fadeStatus = RDFADE_NONE; + _renderAverageTime = 60; + + _layer = 0; +} + +Screen::~Screen() { + free(_buffer); + free(_dirtyGrid); + closeBackgroundLayer(); + free(_lightMask); +} + +void Screen::buildDisplay() { if (_thisScreen.new_palette) { // start the layer palette fading up startNewPalette(); @@ -52,11 +110,11 @@ void Sword2Engine::buildDisplay(void) { // there is a valid screen to run - _graphics->setScrollTarget(_thisScreen.scroll_offset_x, _thisScreen.scroll_offset_y); - _graphics->animateMouse(); - _graphics->startRenderCycle(); + setScrollTarget(_thisScreen.scroll_offset_x, _thisScreen.scroll_offset_y); + _vm->_mouse->animateMouse(); + startRenderCycle(); - byte *file = _resman->openResource(_thisScreen.background_layer_id); + byte *file = _vm->_resman->openResource(_thisScreen.background_layer_id); MultiScreenHeader *screenLayerTable = (MultiScreenHeader *) (file + sizeof(StandardHeader)); // Render at least one frame, but if the screen is scrolling, and if @@ -66,18 +124,18 @@ void Sword2Engine::buildDisplay(void) { do { // first background parallax + related anims if (screenLayerTable->bg_parallax[0]) { - _graphics->renderParallax(fetchBackgroundParallaxLayer(file, 0), 0); + renderParallax(_vm->fetchBackgroundParallaxLayer(file, 0), 0); drawBackPar0Frames(); } // second background parallax + related anims if (screenLayerTable->bg_parallax[1]) { - _graphics->renderParallax(fetchBackgroundParallaxLayer(file, 1), 1); + renderParallax(_vm->fetchBackgroundParallaxLayer(file, 1), 1); drawBackPar1Frames(); } // normal backround layer (just the one!) - _graphics->renderParallax(fetchBackgroundLayer(file), 2); + renderParallax(_vm->fetchBackgroundLayer(file), 2); // sprites & layers drawBackFrames(); // background sprites @@ -87,32 +145,32 @@ void Sword2Engine::buildDisplay(void) { // first foreground parallax + related anims if (screenLayerTable->fg_parallax[0]) { - _graphics->renderParallax(fetchForegroundParallaxLayer(file, 0), 3); + renderParallax(_vm->fetchForegroundParallaxLayer(file, 0), 3); drawForePar0Frames(); } // second foreground parallax + related anims if (screenLayerTable->fg_parallax[1]) { - _graphics->renderParallax(fetchForegroundParallaxLayer(file, 1), 4); + renderParallax(_vm->fetchForegroundParallaxLayer(file, 1), 4); drawForePar1Frames(); } - _debugger->drawDebugGraphics(); - _fontRenderer->printTextBlocs(); - _graphics->processMenu(); + _vm->_debugger->drawDebugGraphics(); + _vm->_fontRenderer->printTextBlocs(); + _vm->_mouse->processMenu(); - _graphics->updateDisplay(); + updateDisplay(); _frameCount++; - if (getMillis() > _cycleTime) { + if (_vm->getMillis() > _cycleTime) { _fps = _frameCount; _frameCount = 0; - _cycleTime = getMillis() + 1000; + _cycleTime = _vm->getMillis() + 1000; } - } while (!_graphics->endRenderCycle()); + } while (!endRenderCycle()); - _resman->closeResource(_thisScreen.background_layer_id); + _vm->_resman->closeResource(_thisScreen.background_layer_id); } /** @@ -122,31 +180,31 @@ void Sword2Engine::buildDisplay(void) { * until the user clicks the mouse or presses a key. */ -void Sword2Engine::displayMsg(byte *text, int time) { +void Screen::displayMsg(byte *text, int time) { byte pal[256 * 4]; byte oldPal[256 * 4]; debug(2, "DisplayMsg: %s", text); - if (_graphics->getFadeStatus() != RDFADE_BLACK) { - _graphics->fadeDown(); - _graphics->waitForFade(); + if (getFadeStatus() != RDFADE_BLACK) { + fadeDown(); + waitForFade(); } - setMouse(0); - setLuggage(0); + _vm->_mouse->setMouse(0); + _vm->_mouse->setLuggage(0); + _vm->_mouse->closeMenuImmediately(); - _graphics->closeMenuImmediately(); - _graphics->clearScene(); + clearScene(); - byte *text_spr = _fontRenderer->makeTextSprite(text, 640, 187, _speechFontId); + byte *text_spr = _vm->_fontRenderer->makeTextSprite(text, 640, 187, _vm->_speechFontId); FrameHeader *frame = (FrameHeader *) text_spr; SpriteInfo spriteInfo; - spriteInfo.x = _graphics->_screenWide / 2 - frame->width / 2; + spriteInfo.x = _screenWide / 2 - frame->width / 2; if (!time) - spriteInfo.y = _graphics->_screenDeep / 2 - frame->height / 2 - RDMENU_MENUDEEP; + spriteInfo.y = _screenDeep / 2 - frame->height / 2 - RDMENU_MENUDEEP; else spriteInfo.y = 400 - frame->height; spriteInfo.w = frame->width; @@ -159,65 +217,65 @@ void Sword2Engine::displayMsg(byte *text, int time) { spriteInfo.data = text_spr + sizeof(FrameHeader); spriteInfo.colourTable = 0; - uint32 rv = _graphics->drawSprite(&spriteInfo); + uint32 rv = drawSprite(&spriteInfo); if (rv) error("Driver Error %.8x (in DisplayMsg)", rv); - memcpy(oldPal, _graphics->_palette, sizeof(oldPal)); + memcpy(oldPal, _palette, sizeof(oldPal)); memset(pal, 0, sizeof(pal)); pal[187 * 4 + 0] = 255; pal[187 * 4 + 1] = 255; pal[187 * 4 + 2] = 255; - _graphics->setPalette(0, 256, pal, RDPAL_FADE); - _graphics->fadeUp(); + setPalette(0, 256, pal, RDPAL_FADE); + fadeUp(); free(text_spr); - _graphics->waitForFade(); + waitForFade(); if (time > 0) { - uint32 targetTime = getMillis() + (time * 1000); - sleepUntil(targetTime); + uint32 targetTime = _vm->getMillis() + (time * 1000); + _vm->sleepUntil(targetTime); } else { - while (!_quit) { - MouseEvent *me = mouseEvent(); + while (!_vm->_quit) { + MouseEvent *me = _vm->mouseEvent(); if (me && (me->buttons & (RD_LEFTBUTTONDOWN | RD_RIGHTBUTTONDOWN))) break; - if (keyboardEvent()) + if (_vm->keyboardEvent()) break; - _graphics->updateDisplay(); - _system->delayMillis(50); + updateDisplay(); + _vm->_system->delayMillis(50); } } - _graphics->fadeDown(); - _graphics->waitForFade(); - _graphics->clearScene(); - _graphics->setPalette(0, 256, oldPal, RDPAL_FADE); - _graphics->fadeUp(); + fadeDown(); + waitForFade(); + clearScene(); + setPalette(0, 256, oldPal, RDPAL_FADE); + fadeUp(); } -void Sword2Engine::drawBackPar0Frames(void) { +void Screen::drawBackPar0Frames() { // frame attached to 1st background parallax for (uint i = 0; i < _curBgp0; i++) processImage(&_bgp0List[i]); } -void Sword2Engine::drawBackPar1Frames(void) { +void Screen::drawBackPar1Frames() { // frame attached to 2nd background parallax for (uint i = 0; i < _curBgp1; i++) processImage(&_bgp1List[i]); } -void Sword2Engine::drawBackFrames(void) { +void Screen::drawBackFrames() { // background sprite, fixed to main background for (uint i = 0; i < _curBack; i++) processImage(&_backList[i]); } -void Sword2Engine::drawSortFrames(byte *file) { +void Screen::drawSortFrames(byte *file) { uint i, j; // Sort the sort list. Used to be a separate function, but it was only @@ -248,26 +306,26 @@ void Sword2Engine::drawSortFrames(byte *file) { } } -void Sword2Engine::drawForeFrames(void) { +void Screen::drawForeFrames() { // foreground sprite, fixed to main background for (uint i = 0; i < _curFore; i++) processImage(&_foreList[i]); } -void Sword2Engine::drawForePar0Frames(void) { +void Screen::drawForePar0Frames() { // frame attached to 1st foreground parallax for (uint i = 0; i < _curFgp0; i++) processImage(&_fgp0List[i]); } -void Sword2Engine::drawForePar1Frames(void) { +void Screen::drawForePar1Frames() { // frame attached to 2nd foreground parallax for (uint i = 0; i < _curFgp1; i++) processImage(&_fgp1List[i]); } -void Sword2Engine::processLayer(byte *file, uint32 layer_number) { - LayerHeader *layer_head = fetchLayerHeader(file, layer_number); +void Screen::processLayer(byte *file, uint32 layer_number) { + LayerHeader *layer_head = _vm->fetchLayerHeader(file, layer_number); SpriteInfo spriteInfo; @@ -293,22 +351,22 @@ void Sword2Engine::processLayer(byte *file, uint32 layer_number) { _largestLayerArea = current_layer_area; sprintf(_largestLayerInfo, "largest layer: %s layer(%d) is %dx%d", - fetchObjectName(_thisScreen.background_layer_id, buf), + _vm->fetchObjectName(_thisScreen.background_layer_id, buf), layer_number, layer_head->width, layer_head->height); } - uint32 rv = _graphics->drawSprite(&spriteInfo); + uint32 rv = drawSprite(&spriteInfo); if (rv) error("Driver Error %.8x in processLayer(%d)", rv, layer_number); } -void Sword2Engine::processImage(BuildUnit *build_unit) { - byte *file = _resman->openResource(build_unit->anim_resource); +void Screen::processImage(BuildUnit *build_unit) { + byte *file = _vm->_resman->openResource(build_unit->anim_resource); byte *colTablePtr = NULL; - AnimHeader *anim_head = fetchAnimHeader(file); - CdtEntry *cdt_entry = fetchCdtEntry(file, build_unit->anim_pc); - FrameHeader *frame_head = fetchFrameHeader(file, build_unit->anim_pc); + AnimHeader *anim_head = _vm->fetchAnimHeader(file); + CdtEntry *cdt_entry = _vm->fetchCdtEntry(file, build_unit->anim_pc); + FrameHeader *frame_head = _vm->fetchFrameHeader(file, build_unit->anim_pc); // so that 0-colour is transparent uint32 spriteType = RDSPR_TRANS; @@ -379,7 +437,7 @@ void Sword2Engine::processImage(BuildUnit *build_unit) { _largestSpriteArea = current_sprite_area; sprintf(_largestSpriteInfo, "largest sprite: %s frame(%d) is %dx%d", - fetchObjectName(build_unit->anim_resource, buf), + _vm->fetchObjectName(build_unit->anim_resource, buf), build_unit->anim_pc, frame_head->width, frame_head->height); @@ -401,26 +459,27 @@ void Sword2Engine::processImage(BuildUnit *build_unit) { spriteInfo.y = 1; // create box to surround sprite - just outside sprite box - _debugger->_rectX1 = spriteInfo.x - 1; - _debugger->_rectY1 = spriteInfo.y - 1; - _debugger->_rectX2 = spriteInfo.x + spriteInfo.scaledWidth; - _debugger->_rectY2 = spriteInfo.y + spriteInfo.scaledHeight; + _vm->_debugger->_rectX1 = spriteInfo.x - 1; + _vm->_debugger->_rectY1 = spriteInfo.y - 1; + _vm->_debugger->_rectX2 = spriteInfo.x + spriteInfo.scaledWidth; + _vm->_debugger->_rectY2 = spriteInfo.y + spriteInfo.scaledHeight; } - uint32 rv = _graphics->drawSprite(&spriteInfo); + uint32 rv = drawSprite(&spriteInfo); if (rv) { byte buf[NAME_LEN]; error("Driver Error %.8x with sprite %s (%d) in processImage", - rv, fetchObjectName(build_unit->anim_resource, buf), + rv, + _vm->fetchObjectName(build_unit->anim_resource, buf), build_unit->anim_resource); } // release the anim resource - _resman->closeResource(build_unit->anim_resource); + _vm->_resman->closeResource(build_unit->anim_resource); } -void Sword2Engine::resetRenderLists(void) { +void Screen::resetRenderLists() { // reset the sort lists - do this before a logic loop // takes into account the fact that the start of the list is pre-built // with the special sortable layers @@ -441,28 +500,22 @@ void Sword2Engine::resetRenderLists(void) { } } -void Sword2Engine::registerFrame(int32 *params, BuildUnit *build_unit) { - // params: 0 pointer to mouse structure or NULL for no write to mouse - // list (non-zero means write sprite-shape to mouse list) - // 1 pointer to graphic structure - // 2 pointer to mega structure - - ObjectGraphic *ob_graph = (ObjectGraphic *) _memory->decodePtr(params[1]); +void Screen::registerFrame(ObjectMouse *ob_mouse, ObjectGraphic *ob_graph, ObjectMega *ob_mega, BuildUnit *build_unit) { assert(ob_graph->anim_resource); - byte *file = _resman->openResource(ob_graph->anim_resource); + byte *file = _vm->_resman->openResource(ob_graph->anim_resource); - AnimHeader *anim_head = fetchAnimHeader(file); - CdtEntry *cdt_entry = fetchCdtEntry(file, ob_graph->anim_pc); - FrameHeader *frame_head = fetchFrameHeader(file, ob_graph->anim_pc); + AnimHeader *anim_head = _vm->fetchAnimHeader(file); + CdtEntry *cdt_entry = _vm->fetchCdtEntry(file, ob_graph->anim_pc); + FrameHeader *frame_head = _vm->fetchFrameHeader(file, ob_graph->anim_pc); // update player graphic details for on-screen debug info if (Logic::_scriptVars[ID] == CUR_PLAYER_ID) { - _debugger->_playerGraphic.type = ob_graph->type; - _debugger->_playerGraphic.anim_resource = ob_graph->anim_resource; + _vm->_debugger->_playerGraphic.type = ob_graph->type; + _vm->_debugger->_playerGraphic.anim_resource = ob_graph->anim_resource; // counting 1st frame as 'frame 1' - _debugger->_playerGraphic.anim_pc = ob_graph->anim_pc + 1; - _debugger->_playerGraphicNoFrames = anim_head->noAnimFrames; + _vm->_debugger->_playerGraphic.anim_pc = ob_graph->anim_pc + 1; + _vm->_debugger->_playerGraphicNoFrames = anim_head->noAnimFrames; } // fill in the BuildUnit structure for this frame @@ -482,9 +535,7 @@ void Sword2Engine::registerFrame(int32 *params, BuildUnit *build_unit) { int scale = 0; if (cdt_entry->frameType & FRAME_OFFSET) { - ObjectMega *ob_mega = (ObjectMega *) _memory->decodePtr(params[2]); - - // calc scale at which to print the sprite, based on feet + // Calc scale at which to print the sprite, based on feet // y-coord & scaling constants (NB. 'scale' is actually // 256 * true_scale, to maintain accuracy) @@ -519,184 +570,58 @@ void Sword2Engine::registerFrame(int32 *params, BuildUnit *build_unit) { // calc the bottom y-coord for sorting purposes build_unit->sort_y = build_unit->y + build_unit->scaled_height - 1; - if (params[0]) { + if (ob_mouse) { // passed a mouse structure, so add to the _mouseList - ObjectMouse *ob_mouse = (ObjectMouse *) _memory->decodePtr(params[0]); - - if (ob_mouse->pointer) { - assert(_curMouse < TOTAL_mouse_list); - - _mouseList[_curMouse].x1 = build_unit->x; - _mouseList[_curMouse].y1 = build_unit->y; - _mouseList[_curMouse].x2 = build_unit->x + build_unit->scaled_width; - _mouseList[_curMouse].y2 = build_unit->y + build_unit->scaled_height; - - _mouseList[_curMouse].priority = ob_mouse->priority; - _mouseList[_curMouse].pointer = ob_mouse->pointer; - - // check if pointer text field is set due to previous - // object using this slot (ie. not correct for this - // one) - - // if 'pointer_text' field is set, but the 'id' field - // isn't same is current id then we don't want this - // "left over" pointer text - - if (_mouseList[_curMouse].pointer_text && _mouseList[_curMouse].id != (int32) Logic::_scriptVars[ID]) - _mouseList[_curMouse].pointer_text = 0; - - _mouseList[_curMouse].id = Logic::_scriptVars[ID]; - // not using sprite as detection mask - _mouseList[_curMouse].anim_resource = 0; - _mouseList[_curMouse].anim_pc = 0; + _vm->_mouse->registerMouse(ob_mouse, build_unit); - _curMouse++; - } } - _resman->closeResource(ob_graph->anim_resource); + _vm->_resman->closeResource(ob_graph->anim_resource); } -int32 Sword2Engine::registerFrame(int32 *params) { - ObjectGraphic *ob_graph = (ObjectGraphic *) _memory->decodePtr(params[1]); - +void Screen::registerFrame(ObjectMouse *ob_mouse, ObjectGraphic *ob_graph, ObjectMega *ob_mega) { // check low word for sprite type switch (ob_graph->type & 0x0000ffff) { case BGP0_SPRITE: assert(_curBgp0 < MAX_bgp0_sprites); - registerFrame(params, &_bgp0List[_curBgp0]); + registerFrame(ob_mouse, ob_graph, ob_mega, &_bgp0List[_curBgp0]); _curBgp0++; break; case BGP1_SPRITE: assert(_curBgp1 < MAX_bgp1_sprites); - registerFrame(params, &_bgp1List[_curBgp1]); + registerFrame(ob_mouse, ob_graph, ob_mega, &_bgp1List[_curBgp1]); _curBgp1++; break; case BACK_SPRITE: assert(_curBack < MAX_back_sprites); - registerFrame(params, &_backList[_curBack]); + registerFrame(ob_mouse, ob_graph, ob_mega, &_backList[_curBack]); _curBack++; break; case SORT_SPRITE: assert(_curSort < MAX_sort_sprites); _sortOrder[_curSort] = _curSort; - registerFrame(params, &_sortList[_curSort]); + registerFrame(ob_mouse, ob_graph, ob_mega, &_sortList[_curSort]); _curSort++; break; case FORE_SPRITE: assert(_curFore < MAX_fore_sprites); - registerFrame(params, &_foreList[_curFore]); + registerFrame(ob_mouse, ob_graph, ob_mega, &_foreList[_curFore]); _curFore++; break; case FGP0_SPRITE: assert(_curFgp0 < MAX_fgp0_sprites); - registerFrame(params, &_fgp0List[_curFgp0]); + registerFrame(ob_mouse, ob_graph, ob_mega, &_fgp0List[_curFgp0]); _curFgp0++; break; case FGP1_SPRITE: assert(_curFgp1 < MAX_fgp1_sprites); - registerFrame(params, &_fgp1List[_curFgp1]); + registerFrame(ob_mouse, ob_graph, ob_mega, &_fgp1List[_curFgp1]); _curFgp1++; break; default: // NO_SPRITE no registering! break; } - - return IR_CONT; -} - -/** - * Start layer palette fading up - */ - -void Sword2Engine::startNewPalette(void) { - // if the screen is still fading down then wait for black - could - // happen when everythings cached into a large memory model - _graphics->waitForFade(); - - byte *screenFile = _resman->openResource(_thisScreen.background_layer_id); - - _graphics->updatePaletteMatchTable((byte *) fetchPaletteMatchTable(screenFile)); - _graphics->setPalette(0, 256, fetchPalette(screenFile), RDPAL_FADE); - - // indicating that it's a screen palette - _lastPaletteRes = 0; - - _resman->closeResource(_thisScreen.background_layer_id); - _graphics->fadeUp(); - _thisScreen.new_palette = 0; -} - -void Sword2Engine::setFullPalette(int32 palRes) { - // fudge for hut interior - // - unpausing should restore last palette as normal (could be screen - // palette or 'dark_palette_13') - // - but restoring the screen palette after 'dark_palette_13' should - // now work properly too! - - // "Hut interior" refers to the watchman's hut in Marseille, and this - // is apparently needed for the palette to be restored properly when - // you turn the light off. (I didn't even notice the light switch!) - - if (Logic::_scriptVars[LOCATION] == 13) { - // unpausing - if (palRes == -1) { - // restore whatever palette was last set (screen - // palette or 'dark_palette_13') - palRes = _lastPaletteRes; - } - } else { - // check if we're just restoring the current screen palette - // because we might actually need to use a separate palette - // file anyway eg. for pausing & unpausing during the eclipse - - // unpausing (fudged for location 13) - if (palRes == -1) { - // we really meant '0' - palRes = 0; - } - - if (palRes == 0 && _lastPaletteRes) - palRes = _lastPaletteRes; - } - - // If non-zero, set palette to this separate palette file. Otherwise, - // set palette to current screen palette. - - byte *file; - - if (palRes) { - file = _resman->openResource(palRes); - - StandardHeader *head = (StandardHeader *) file; - assert(head->fileType == PALETTE_FILE); - - file += sizeof(StandardHeader); - - // always set colour 0 to black because most background screen - // palettes have a bright colour 0 although it should come out - // as black in the game! - - file[0] = 0; - file[1] = 0; - file[2] = 0; - file[3] = 0; - - _graphics->setPalette(0, 256, file, RDPAL_INSTANT); - _resman->closeResource(palRes); - } else { - if (_thisScreen.background_layer_id) { - file = _resman->openResource(_thisScreen.background_layer_id); - _graphics->updatePaletteMatchTable(fetchPaletteMatchTable(file)); - _graphics->setPalette(0, 256, fetchPalette(file), RDPAL_INSTANT); - _resman->closeResource(_thisScreen.background_layer_id); - } else - error("setFullPalette(0) called, but no current screen available!"); - } - - if (palRes != CONTROL_PANEL_PALETTE) - _lastPaletteRes = palRes; } } // End of namespace Sword2 diff --git a/sword2/build_display.h b/sword2/build_display.h index fe27009027..2b3bc0c6d6 100644 --- a/sword2/build_display.h +++ b/sword2/build_display.h @@ -21,6 +21,8 @@ #ifndef _BUILD_DISPLAY #define _BUILD_DISPLAY +#include "common/rect.h" + #define MAX_bgp0_sprites 6 #define MAX_bgp1_sprites 6 #define MAX_back_sprites 30 @@ -29,7 +31,341 @@ #define MAX_fgp0_sprites 6 #define MAX_fgp1_sprites 6 +#define PALTABLESIZE (64 * 64 * 64) + +#define BLOCKWIDTH 64 +#define BLOCKHEIGHT 64 +#define MAXLAYERS 5 + +// Maximum scaled size of a sprite +#define SCALE_MAXWIDTH 512 +#define SCALE_MAXHEIGHT 512 + +// Dirty grid cell size +#define CELLWIDE 10 +#define CELLDEEP 20 + namespace Sword2 { + +struct ObjectMouse; +struct ObjectGraphic; +struct ObjectMega; + +// Structure filled out by each object to register its graphic printing +// requrements + +struct BuildUnit { + int16 x; + int16 y; + uint16 scaled_width; + uint16 scaled_height; + int16 sort_y; + uint32 anim_resource; + uint16 anim_pc; + + // Denotes a scaling sprite at print time - and holds the scaling value + // for the shrink routine + + uint16 scale; + + // Non-zero means this item is a layer - retrieve from background layer + // and send to special renderer + + uint16 layer_number; + + // True means we want this frame to be affected by the shading mask + + bool shadingFlag; +}; + +enum { + MOUSE_normal = 0, // normal in game + MOUSE_menu = 1, // menu chooser + MOUSE_drag = 2, // dragging luggage + MOUSE_system_menu = 3, // system menu chooser + MOUSE_holding = 4 // special +}; + +struct ScreenInfo { + uint16 scroll_offset_x; // Position x + uint16 scroll_offset_y; // Position y + uint16 max_scroll_offset_x; // Calc'ed in fnInitBackground + uint16 max_scroll_offset_y; + int16 player_feet_x; // Feet coordinates to use - cant just + int16 player_feet_y; // fetch the player compact anymore + int16 feet_x; // Special offset-to-player position - + int16 feet_y; // tweek as desired - always set in + // screen manager object startup + uint16 screen_wide; // Size of background layer - hence + uint16 screen_deep; // size of back buffer itself (Paul + // actually malloc's it) + uint32 background_layer_id; // Id of the normal background layer + // from the header of the main + // background layer + uint16 number_of_layers; + uint8 new_palette; // Set to non zero to start the + // palette held within layer file + // fading up after a build_display + uint8 scroll_flag; // Scroll mode 0 off 1 on + bool mask_flag; // Using shading mask +}; + +// The SpriteInfo structure is used to tell the driver96 code what attributes +// are linked to a sprite for drawing. These include position, scaling and +// compression. + +struct SpriteInfo { + int16 x; // coords for top-left of sprite + int16 y; + uint16 w; // dimensions of sprite (before scaling) + uint16 h; + uint16 scale; // scale at which to draw, given in 256ths ['0' or '256' MEANS DON'T SCALE] + uint16 scaledWidth; // new dimensions (we calc these for the mouse area, so may as well pass to you to save time) + uint16 scaledHeight; // + uint16 type; // mask containing 'RDSPR_' bits specifying compression type, flip, transparency, etc + uint16 blend; // holds the blending values. + byte *data; // pointer to the sprite data + byte *colourTable; // pointer to 16-byte colour table, only applicable to 16-col compression type +}; + +struct BlockSurface { + byte data[BLOCKWIDTH * BLOCKHEIGHT]; + bool transparent; +}; + +class Screen { +private: + Sword2Engine *_vm; + + // _thisScreen describes the current back buffer and its in-game scroll + // positions, etc. + + ScreenInfo _thisScreen; + + int32 _renderCaps; + int8 _renderLevel; + + byte *_buffer; + byte *_lightMask; + + // Game screen metrics + int16 _screenWide; + int16 _screenDeep; + + bool _needFullRedraw; + + // Scroll variables. _scrollX and _scrollY hold the current scroll + // position, and _scrollXTarget and _scrollYTarget are the target + // position for the end of the game cycle. + + int16 _scrollX; + int16 _scrollY; + + int16 _scrollXTarget; + int16 _scrollYTarget; + int16 _scrollXOld; + int16 _scrollYOld; + + int16 _parallaxScrollX; // current x offset to link a sprite to the + // parallax layer + int16 _parallaxScrollY; // current y offset to link a sprite to the + // parallax layer + int16 _locationWide; + int16 _locationDeep; + + // Dirty grid handling + byte *_dirtyGrid; + + uint16 _gridWide; + uint16 _gridDeep; + + byte _palette[256 * 4]; + byte _paletteMatch[PALTABLESIZE]; + + uint8 _fadeStatus; + int32 _fadeStartTime; + int32 _fadeTotalTime; + + // 'frames per second' counting stuff + uint32 _fps; + uint32 _cycleTime; + uint32 _frameCount; + + int32 _initialTime; + int32 _startTime; + int32 _totalTime; + int32 _renderAverageTime; + int32 _framesPerGameCycle; + bool _renderTooSlow; + + void startNewPalette(); + + void resetRenderEngine(); + + void startRenderCycle(); + bool endRenderCycle(); + + // Holds the order of the sort list, i.e. the list stays static and we + // sort this array. + + uint16 _sortOrder[MAX_sort_sprites]; + + BuildUnit _bgp0List[MAX_bgp0_sprites]; + BuildUnit _bgp1List[MAX_bgp1_sprites]; + BuildUnit _backList[MAX_back_sprites]; + BuildUnit _sortList[MAX_sort_sprites]; + BuildUnit _foreList[MAX_fore_sprites]; + BuildUnit _fgp0List[MAX_fgp0_sprites]; + BuildUnit _fgp1List[MAX_fgp1_sprites]; + + uint32 _curBgp0; + uint32 _curBgp1; + uint32 _curBack; + uint32 _curSort; + uint32 _curFore; + uint32 _curFgp0; + uint32 _curFgp1; + + void drawBackPar0Frames(); + void drawBackPar1Frames(); + void drawBackFrames(); + void drawSortFrames(byte *file); + void drawForeFrames(); + void drawForePar0Frames(); + void drawForePar1Frames(); + + void processLayer(byte *file, uint32 layer_number); + void processImage(BuildUnit *build_unit); + + uint8 _scrollFraction; + + // Last palette used - so that we can restore the correct one after a + // pause (which dims the screen) and it's not always the main screen + // palette that we want, eg. during the eclipse + + // This flag gets set in startNewPalette() and setFullPalette() + + uint32 _lastPaletteRes; + + // Debugging stuff + uint32 _largestLayerArea; + uint32 _largestSpriteArea; + char _largestLayerInfo[128]; + char _largestSpriteInfo[128]; + + void registerFrame(ObjectMouse *ob_mouse, ObjectGraphic *ob_graph, ObjectMega *ob_mega, BuildUnit *build_unit); + + void mirrorSprite(byte *dst, byte *src, int16 w, int16 h); + int32 decompressRLE256(byte *dst, byte *src, int32 decompSize); + void unwindRaw16(byte *dst, byte *src, uint8 blockSize, byte *colTable); + int32 decompressRLE16(byte *dst, byte *src, int32 decompSize, byte *colTable); + void renderParallax(Parallax *p, int16 layer); + + void markAsDirty(int16 x0, int16 y0, int16 x1, int16 y1); + + uint8 _xBlocks[MAXLAYERS]; + uint8 _yBlocks[MAXLAYERS]; + + // An array of sub-blocks, one for each of the parallax layers. + + BlockSurface **_blockSurfaces[MAXLAYERS]; + + uint16 _xScale[SCALE_MAXWIDTH]; + uint16 _yScale[SCALE_MAXHEIGHT]; + + void blitBlockSurface(BlockSurface *s, Common::Rect *r, Common::Rect *clipRect); + + uint16 _layer; + +public: + Screen(Sword2Engine *vm, int16 width, int16 height); + ~Screen(); + + int8 getRenderLevel(); + void setRenderLevel(int8 level); + + byte *getScreen() { return _buffer; } + byte *getPalette() { return _palette; } + ScreenInfo *getScreenInfo() { return &_thisScreen; } + + int16 getScreenWide() { return _screenWide; } + int16 getScreenDeep() { return _screenDeep; } + + uint32 getCurBgp0() { return _curBgp0; } + uint32 getCurBgp1() { return _curBgp1; } + uint32 getCurBack() { return _curBack; } + uint32 getCurSort() { return _curSort; } + uint32 getCurFore() { return _curFore; } + uint32 getCurFgp0() { return _curFgp0; } + uint32 getCurFgp1() { return _curFgp1; } + + uint32 getFps() { return _fps; } + + uint32 getLargestLayerArea() { return _largestLayerArea; } + uint32 getLargestSpriteArea() { return _largestSpriteArea; } + char *getLargestLayerInfo() { return _largestLayerInfo; } + char *getLargestSpriteInfo() { return _largestSpriteInfo; } + + void setNeedFullRedraw(); + + void clearScene(); + + void resetRenderLists(); + + void setLocationMetrics(uint16 w, uint16 h); + int32 initialiseBackgroundLayer(Parallax *p); + void closeBackgroundLayer(); + + void initialiseRenderCycle(); + + void initBackground(int32 res, int32 new_palette); + void registerFrame(ObjectMouse *ob_mouse, ObjectGraphic *ob_graph, ObjectMega *ob_mega); + + void setScrollFraction(uint8 f) { _scrollFraction = f; } + void setScrollTarget(int16 x, int16 y); + void setScrolling(); + + void setFullPalette(int32 palRes); + void setPalette(int16 startEntry, int16 noEntries, byte *palette, uint8 setNow); + uint8 quickMatch(uint8 r, uint8 g, uint8 b); + int32 fadeUp(float time = 0.75); + int32 fadeDown(float time = 0.75); + uint8 getFadeStatus(); + void dimPalette(); + void waitForFade(); + void fadeServer(); + + void updateDisplay(bool redrawScene = true); + + void displayMsg(byte *text, int time); + + int32 createSurface(SpriteInfo *s, byte **surface); + void drawSurface(SpriteInfo *s, byte *surface, Common::Rect *clipRect = NULL); + void deleteSurface(byte *surface); + int32 drawSprite(SpriteInfo *s); + + void scaleImageFast(byte *dst, uint16 dstPitch, uint16 dstWidth, + uint16 dstHeight, byte *src, uint16 srcPitch, uint16 srcWidth, + uint16 srcHeight); + void scaleImageGood(byte *dst, uint16 dstPitch, uint16 dstWidth, + uint16 dstHeight, byte *src, uint16 srcPitch, uint16 srcWidth, + uint16 srcHeight, byte *backbuf); + + void updateRect(Common::Rect *r); + + int32 openLightMask(SpriteInfo *s); + int32 closeLightMask(); + + void buildDisplay(); + + void plotPoint(int16 x, int16 y, uint8 colour); + void drawLine(int16 x1, int16 y1, int16 x2, int16 y2, uint8 colour); +#ifdef BACKEND_8BIT + void plotYUV(byte *lut, int width, int height, byte *const *dat); +#endif + +}; + } // End of namespace Sword2 #endif diff --git a/sword2/console.cpp b/sword2/console.cpp index 4c0ab2f550..32e7d6eeb2 100644 --- a/sword2/console.cpp +++ b/sword2/console.cpp @@ -25,9 +25,9 @@ #include "sword2/logic.h" #include "sword2/maketext.h" #include "sword2/memory.h" +#include "sword2/mouse.h" #include "sword2/resman.h" #include "sword2/sound.h" -#include "sword2/driver/d_draw.h" #include "common/debugger.cpp" @@ -144,9 +144,9 @@ void Debugger::postEnter() { _vm->_sound->unpauseMusic(); } - if (_vm->_graphics) { + if (_vm->_mouse) { // Restore old mouse cursor - _vm->_graphics->drawMouse(); + _vm->_mouse->drawMouse(); } } @@ -219,7 +219,7 @@ bool Debugger::Cmd_Start(int argc, const char **argv) { } _vm->conStart(atoi(argv[1])); - _vm->_graphics->setPalette(187, 1, pal, RDPAL_INSTANT); + _vm->_screen->setPalette(187, 1, pal, RDPAL_INSTANT); return true; } diff --git a/sword2/controls.cpp b/sword2/controls.cpp index 08444ed4d9..5ff77f8008 100644 --- a/sword2/controls.cpp +++ b/sword2/controls.cpp @@ -22,14 +22,15 @@ #include "common/rect.h" #include "common/config-manager.h" #include "common/system.h" + #include "sword2/sword2.h" #include "sword2/controls.h" #include "sword2/defs.h" #include "sword2/logic.h" +#include "sword2/mouse.h" #include "sword2/resman.h" #include "sword2/router.h" #include "sword2/sound.h" -#include "sword2/driver/d_draw.h" #define MAX_STRING_LEN 64 // 20 was too low; better to be safe ;) #define CHARACTER_OVERLAP 2 // overlap characters by 3 pixels @@ -176,7 +177,7 @@ FontRendererGui::FontRendererGui(Gui *gui, int fontId) sprite.data = (byte *) (head + 1); sprite.w = head->width; sprite.h = head->height; - _gui->_vm->_graphics->createSurface(&sprite, &_glyph[i]._data); + _gui->_vm->_screen->createSurface(&sprite, &_glyph[i]._data); _glyph[i]._width = head->width; _glyph[i]._height = head->height; } @@ -186,7 +187,7 @@ FontRendererGui::FontRendererGui(Gui *gui, int fontId) FontRendererGui::~FontRendererGui() { for (int i = 0; i < SIZE_OF_CHAR_SET; i++) - _gui->_vm->_graphics->deleteSurface(_glyph[i]._data); + _gui->_vm->_screen->deleteSurface(_glyph[i]._data); } void FontRendererGui::fetchText(uint32 textId, byte *buf) { @@ -255,7 +256,7 @@ void FontRendererGui::drawText(byte *text, int x, int y, int alignment) { sprite.w = getCharWidth(text[i]); sprite.h = getCharHeight(text[i]); - _gui->_vm->_graphics->drawSurface(&sprite, _glyph[text[i] - 32]._data); + _gui->_vm->_screen->drawSurface(&sprite, _glyph[text[i] - 32]._data); sprite.x += (getCharWidth(text[i]) - CHARACTER_OVERLAP); } @@ -275,14 +276,14 @@ void FontRendererGui::drawText(uint32 textId, int x, int y, int alignment) { Dialog::Dialog(Gui *gui) : _numWidgets(0), _finish(false), _result(0), _gui(gui) { - _gui->_vm->setFullPalette(CONTROL_PANEL_PALETTE); - _gui->_vm->_graphics->clearScene(); + _gui->_vm->_screen->setFullPalette(CONTROL_PANEL_PALETTE); + _gui->_vm->_screen->clearScene(); // HACK: Since the dialogs don't do normal scene updates we need to // trigger a full redraw manually. - _gui->_vm->_graphics->setNeedFullRedraw(); - _gui->_vm->_graphics->updateDisplay(); + _gui->_vm->_screen->setNeedFullRedraw(); + _gui->_vm->_screen->updateDisplay(); } Dialog::~Dialog() { @@ -296,7 +297,7 @@ void Dialog::registerWidget(Widget *widget) { } void Dialog::paint() { - _gui->_vm->_graphics->clearScene(); + _gui->_vm->_screen->clearScene(); for (int i = 0; i < _numWidgets; i++) _widgets[i]->paint(); } @@ -313,16 +314,19 @@ int Dialog::run() { paint(); - int16 oldMouseX = -1; - int16 oldMouseY = -1; + int oldMouseX = -1; + int oldMouseY = -1; while (!_finish) { // So that the menu icons will reach their full size - _gui->_vm->_graphics->processMenu(); - _gui->_vm->_graphics->updateDisplay(false); + _gui->_vm->_mouse->processMenu(); + _gui->_vm->_screen->updateDisplay(false); + + int newMouseX, newMouseY; + + _gui->_vm->_mouse->getPos(newMouseX, newMouseY); - int16 newMouseX = _gui->_vm->_mouseX; - int16 newMouseY = _gui->_vm->_mouseY + 40; + newMouseY += 40; MouseEvent *me = _gui->_vm->mouseEvent(); KeyboardEvent *ke = _gui->_vm->keyboardEvent(); @@ -429,7 +433,7 @@ Widget::Widget(Dialog *parent, int states) Widget::~Widget() { for (int i = 0; i < _numStates; i++) { if (_surfaces[i]._original) - _parent->_gui->_vm->_graphics->deleteSurface(_surfaces[i]._surface); + _parent->_gui->_vm->_screen->deleteSurface(_surfaces[i]._surface); } free(_sprites); free(_surfaces); @@ -484,7 +488,7 @@ void Widget::createSurfaceImage(int state, uint32 res, int x, int y, uint32 pc) // Points to just after frame header, ie. start of sprite data _sprites[state].data = (byte *) (frame_head + 1); - _parent->_gui->_vm->_graphics->createSurface(&_sprites[state], &_surfaces[state]._surface); + _parent->_gui->_vm->_screen->createSurface(&_sprites[state], &_surfaces[state]._surface); _surfaces[state]._original = true; // Release the anim resource @@ -537,7 +541,7 @@ int Widget::getState() { } void Widget::paint(Common::Rect *clipRect) { - _parent->_gui->_vm->_graphics->drawSurface(&_sprites[_state], _surfaces[_state]._surface, clipRect); + _parent->_gui->_vm->_screen->drawSurface(&_sprites[_state], _surfaces[_state]._surface, clipRect); } /** @@ -940,7 +944,7 @@ public: _objectLabelsSwitch->setValue(_gui->_pointerTextSelected); _subtitlesSwitch->setValue(_gui->_subtitles); - _reverseStereoSwitch->setValue(_gui->_stereoReversed); + _reverseStereoSwitch->setValue(_gui->_vm->_sound->isReverseStereo()); _musicSwitch->setValue(!_gui->_vm->_sound->isMusicMute()); _speechSwitch->setValue(!_gui->_vm->_sound->isSpeechMute()); _fxSwitch->setValue(!_gui->_vm->_sound->isFxMute()); @@ -949,8 +953,8 @@ public: _speechSlider->setValue(_mixer->getVolumeForSoundType(SoundMixer::kSpeechAudioDataType)); _fxSlider->setValue(_mixer->getVolumeForSoundType(SoundMixer::kSFXAudioDataType)); - _gfxSlider->setValue(_gui->_vm->_graphics->getRenderLevel()); - _gfxPreview->setState(_gui->_vm->_graphics->getRenderLevel()); + _gfxSlider->setValue(_gui->_vm->_screen->getRenderLevel()); + _gfxPreview->setState(_gui->_vm->_screen->getRenderLevel()); } ~OptionsDialog() { @@ -1020,12 +1024,12 @@ public: } else if (widget == _okButton) { _gui->_subtitles = _subtitlesSwitch->getValue(); _gui->_pointerTextSelected = _objectLabelsSwitch->getValue(); - _gui->_stereoReversed = _reverseStereoSwitch->getValue(); // Apply the changes _gui->_vm->_sound->muteMusic(!_musicSwitch->getValue()); _gui->_vm->_sound->muteSpeech(!_speechSwitch->getValue()); _gui->_vm->_sound->muteFx(!_fxSwitch->getValue()); + _gui->_vm->_sound->setReverseStereo(_reverseStereoSwitch->getValue()); _mixer->setVolumeForSoundType(SoundMixer::kMusicAudioDataType, _musicSlider->getValue()); _mixer->setVolumeForSoundType(SoundMixer::kSpeechAudioDataType, _speechSlider->getValue()); _mixer->setVolumeForSoundType(SoundMixer::kSFXAudioDataType, _fxSlider->getValue()); @@ -1449,7 +1453,7 @@ public: break; } - _gui->_vm->displayMsg(_gui->_vm->fetchTextLine(_gui->_vm->_resman->openResource(textId / SIZE), textId & 0xffff) + 2, 0); + _gui->_vm->_screen->displayMsg(_gui->_vm->fetchTextLine(_gui->_vm->_resman->openResource(textId / SIZE), textId & 0xffff) + 2, 0); result = 0; } } else { @@ -1470,18 +1474,18 @@ public: break; } - _gui->_vm->displayMsg(_gui->_vm->fetchTextLine(_gui->_vm->_resman->openResource(textId / SIZE), textId & 0xffff) + 2, 0); + _gui->_vm->_screen->displayMsg(_gui->_vm->fetchTextLine(_gui->_vm->_resman->openResource(textId / SIZE), textId & 0xffff) + 2, 0); result = 0; } else { // Prime system with a game cycle // Reset the graphic 'BuildUnit' list before a // new logic list (see fnRegisterFrame) - _gui->_vm->resetRenderLists(); + _gui->_vm->_screen->resetRenderLists(); // Reset the mouse hot-spot list (see // fnRegisterMouse and fnRegisterFrame) - _gui->_vm->resetMouseList(); + _gui->_vm->_mouse->resetMouseList(); if (_gui->_vm->_logic->processSession()) error("restore 1st cycle failed??"); @@ -1504,7 +1508,6 @@ Gui::Gui(Sword2Engine *vm) : _vm(vm), _baseSlot(0) { void Gui::readOptionSettings(void) { _subtitles = ConfMan.getBool("subtitles"); _pointerTextSelected = ConfMan.getBool("object_labels"); - _stereoReversed = ConfMan.getBool("reverse_stereo"); updateGraphicsLevel((uint8) ConfMan.getInt("gfx_details")); @@ -1514,6 +1517,7 @@ void Gui::readOptionSettings(void) { _vm->_sound->muteMusic(ConfMan.getBool("music_mute")); _vm->_sound->muteSpeech(ConfMan.getBool("speech_mute")); _vm->_sound->muteFx(ConfMan.getBool("sfx_mute")); + _vm->_sound->setReverseStereo(ConfMan.getBool("reverse_stereo")); } void Gui::writeOptionSettings(void) { @@ -1523,10 +1527,10 @@ void Gui::writeOptionSettings(void) { ConfMan.set("music_mute", _vm->_sound->isMusicMute()); ConfMan.set("speech_mute", _vm->_sound->isSpeechMute()); ConfMan.set("sfx_mute", _vm->_sound->isFxMute()); - ConfMan.set("gfx_details", _vm->_graphics->getRenderLevel()); + ConfMan.set("gfx_details", _vm->_screen->getRenderLevel()); ConfMan.set("subtitles", _subtitles); ConfMan.set("object_labels", _pointerTextSelected); - ConfMan.set("reverse_stereo", _stereoReversed); + ConfMan.set("reverse_stereo", _vm->_sound->isReverseStereo()); ConfMan.flushToDisk(); } @@ -1574,6 +1578,7 @@ void Gui::quitControl(void) { } void Gui::restartControl(void) { + ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); uint32 temp_demo_flag; MiniDialog restartDialog(this, 149618693); @@ -1581,7 +1586,7 @@ void Gui::restartControl(void) { if (!restartDialog.run()) return; - _vm->_graphics->closeMenuImmediately(); + _vm->_mouse->closeMenuImmediately(); // Restart the game. To do this, we must... @@ -1613,25 +1618,25 @@ void Gui::restartControl(void) { // Reset the graphic 'BuildUnit' list before a new logic list // (see fnRegisterFrame) - _vm->resetRenderLists(); + _vm->_screen->resetRenderLists(); // Reset the mouse hot-spot list (see fnRegisterMouse and // fnRegisterFrame) - _vm->resetMouseList(); + _vm->_mouse->resetMouseList(); - _vm->_graphics->closeMenuImmediately(); + _vm->_mouse->closeMenuImmediately(); // FOR THE DEMO - FORCE THE SCROLLING TO BE RESET! // - this is taken from fnInitBackground // switch on scrolling (2 means first time on screen) - _vm->_thisScreen.scroll_flag = 2; + screenInfo->scroll_flag = 2; if (_vm->_logic->processSession()) error("restart 1st cycle failed??"); // So palette not restored immediately after control panel - we want // to fade up instead! - _vm->_thisScreen.new_palette = 99; + screenInfo->new_palette = 99; } void Gui::optionControl(void) { @@ -1647,7 +1652,7 @@ void Gui::updateGraphicsLevel(int newLevel) { else if (newLevel > 3) newLevel = 3; - _vm->_graphics->setRenderLevel(newLevel); + _vm->_screen->setRenderLevel(newLevel); // update our global variable - which needs to be checked when dimming // the palette in PauseGame() in sword2.cpp (since palette-matching diff --git a/sword2/controls.h b/sword2/controls.h index d3eacc3822..27cf07f9f5 100644 --- a/sword2/controls.h +++ b/sword2/controls.h @@ -33,7 +33,6 @@ public: uint8 _currentGraphicsLevel; bool _subtitles; - bool _stereoReversed; bool _pointerTextSelected; Gui(Sword2Engine *vm); diff --git a/sword2/debug.cpp b/sword2/debug.cpp index 5b9c9597e0..4d4d4eb8ff 100644 --- a/sword2/debug.cpp +++ b/sword2/debug.cpp @@ -25,9 +25,9 @@ #include "sword2/logic.h" #include "sword2/maketext.h" #include "sword2/memory.h" +#include "sword2/mouse.h" #include "sword2/resman.h" #include "sword2/router.h" -#include "sword2/driver/d_draw.h" namespace Sword2 { @@ -63,20 +63,24 @@ void Debugger::buildDebugText(void) { int32 showVarPos; int32 varNo; + ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); + // clear the array of text block numbers for the debug text clearDebugTextBlocks(); // mouse coords -/* // print mouse coords beside mouse-marker, if it's being displayed - if (displayMouseMarker) { - sprintf(buf, "%d,%d", mousex + _thisScreen.scroll_offset_x, mousey + _thisScreen.scroll_offset_y); - if (mousex>560) - makeDebugTextBlock(buf, mousex - 50, mousey - 15); + if (_displayMouseMarker) { + int mouseX, mouseY; + + _vm->_mouse->getPos(mouseX, mouseY); + + sprintf(buf, "%d,%d", mouseX + screenInfo->scroll_offset_x, mouseY + screenInfo->scroll_offset_y); + if (mouseX > 560) + makeDebugTextBlock(buf, mouseX - 50, mouseY - 15); else - makeDebugTextBlock(buf, mousex + 5, mousey - 15); + makeDebugTextBlock(buf, mouseX + 5, mouseY - 15); } -*/ // mouse area coords @@ -186,16 +190,22 @@ void Debugger::buildDebugText(void) { makeDebugTextBlock(buf, 0, 15); - if (_vm->_mouseTouching) + uint32 mouseTouching = _vm->_mouse->getMouseTouching(); + + int mouseX, mouseY; + + _vm->_mouse->getPos(mouseX, mouseY); + + if (mouseTouching) sprintf(buf, "mouse %d,%d (id %d: %s)", - _vm->_mouseX + _vm->_thisScreen.scroll_offset_x, - _vm->_mouseY + _vm->_thisScreen.scroll_offset_y, - _vm->_mouseTouching, - _vm->fetchObjectName(_vm->_mouseTouching, name)); + mouseX + screenInfo->scroll_offset_x, + mouseY + screenInfo->scroll_offset_y, + mouseTouching, + _vm->fetchObjectName(mouseTouching, name)); else sprintf(buf, "mouse %d,%d (not touching)", - _vm->_mouseX + _vm->_thisScreen.scroll_offset_x, - _vm->_mouseY + _vm->_thisScreen.scroll_offset_y); + mouseX + screenInfo->scroll_offset_x, + mouseY + screenInfo->scroll_offset_y); makeDebugTextBlock(buf, 0, 30); @@ -204,23 +214,23 @@ void Debugger::buildDebugText(void) { if (_playerGraphic.anim_resource) sprintf(buf, "player %d,%d %s (%d) #%d/%d", - _vm->_thisScreen.player_feet_x, - _vm->_thisScreen.player_feet_y, + screenInfo->player_feet_x, + screenInfo->player_feet_y, _vm->fetchObjectName(_playerGraphic.anim_resource, name), _playerGraphic.anim_resource, _playerGraphic.anim_pc, _playerGraphicNoFrames); else sprintf(buf, "player %d,%d --- %d", - _vm->_thisScreen.player_feet_x, - _vm->_thisScreen.player_feet_y, + screenInfo->player_feet_x, + screenInfo->player_feet_y, _playerGraphic.anim_pc); makeDebugTextBlock(buf, 0, 45); // frames-per-second counter - sprintf(buf, "fps %d", _vm->_fps); + sprintf(buf, "fps %d", _vm->_screen->getFps()); makeDebugTextBlock(buf, 440, 0); // location number @@ -240,32 +250,32 @@ void Debugger::buildDebugText(void) { // sprite list usage - sprintf(buf, "bgp0: %d/%d", _vm->_curBgp0, MAX_bgp0_sprites); + sprintf(buf, "bgp0: %d/%d", _vm->_screen->getCurBgp0(), MAX_bgp0_sprites); makeDebugTextBlock(buf, 560, 0); - sprintf(buf, "bgp1: %d/%d", _vm->_curBgp1, MAX_bgp1_sprites); + sprintf(buf, "bgp1: %d/%d", _vm->_screen->getCurBgp1(), MAX_bgp1_sprites); makeDebugTextBlock(buf, 560, 15); - sprintf(buf, "back: %d/%d", _vm->_curBack, MAX_back_sprites); + sprintf(buf, "back: %d/%d", _vm->_screen->getCurBack(), MAX_back_sprites); makeDebugTextBlock(buf, 560, 30); - sprintf(buf, "sort: %d/%d", _vm->_curSort, MAX_sort_sprites); + sprintf(buf, "sort: %d/%d", _vm->_screen->getCurSort(), MAX_sort_sprites); makeDebugTextBlock(buf, 560, 45); - sprintf(buf, "fore: %d/%d", _vm->_curFore, MAX_fore_sprites); + sprintf(buf, "fore: %d/%d", _vm->_screen->getCurFore(), MAX_fore_sprites); makeDebugTextBlock(buf, 560, 60); - sprintf(buf, "fgp0: %d/%d", _vm->_curFgp0, MAX_fgp0_sprites); + sprintf(buf, "fgp0: %d/%d", _vm->_screen->getCurFgp0(), MAX_fgp0_sprites); makeDebugTextBlock(buf, 560, 75); - sprintf(buf, "fgp1: %d/%d", _vm->_curFgp1, MAX_fgp1_sprites); + sprintf(buf, "fgp1: %d/%d", _vm->_screen->getCurFgp1(), MAX_fgp1_sprites); makeDebugTextBlock(buf, 560, 90); // largest layer & sprite // NB. Strings already constructed in Build_display.cpp - makeDebugTextBlock(_vm->_largestLayerInfo, 0, 60); - makeDebugTextBlock(_vm->_largestSpriteInfo, 0, 75); + makeDebugTextBlock(_vm->_screen->getLargestLayerInfo(), 0, 60); + makeDebugTextBlock(_vm->_screen->getLargestSpriteInfo(), 0, 75); // "waiting for person" indicator - set form fnTheyDo and // fnTheyDoWeWait @@ -303,6 +313,7 @@ void Debugger::buildDebugText(void) { } void Debugger::drawDebugGraphics(void) { + ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); // walk-grid if (_displayWalkGrid) @@ -311,12 +322,17 @@ void Debugger::drawDebugGraphics(void) { // player feet coord marker if (_displayPlayerMarker) - plotCrossHair(_vm->_thisScreen.player_feet_x, _vm->_thisScreen.player_feet_y, 215); + plotCrossHair(screenInfo->player_feet_x, screenInfo->player_feet_y, 215); // mouse marker & coords - if (_displayMouseMarker) - plotCrossHair(_vm->_mouseX + _vm->_thisScreen.scroll_offset_x, _vm->_mouseY + _vm->_thisScreen.scroll_offset_y, 215); + if (_displayMouseMarker) { + int mouseX, mouseY; + + _vm->_mouse->getPos(mouseX, mouseY); + + plotCrossHair(mouseX + screenInfo->scroll_offset_x, mouseY + screenInfo->scroll_offset_y, 215); + } // mouse area rectangle / sprite box rectangle when testing anims @@ -332,29 +348,30 @@ void Debugger::drawDebugGraphics(void) { } void Debugger::plotCrossHair(int16 x, int16 y, uint8 pen) { - _vm->_graphics->plotPoint(x, y, pen); + _vm->_screen->plotPoint(x, y, pen); - _vm->_graphics->drawLine(x - 2, y, x - 5, y, pen); - _vm->_graphics->drawLine(x + 2, y, x + 5, y, pen); + _vm->_screen->drawLine(x - 2, y, x - 5, y, pen); + _vm->_screen->drawLine(x + 2, y, x + 5, y, pen); - _vm->_graphics->drawLine(x, y - 2, x, y - 5, pen); - _vm->_graphics->drawLine(x, y + 2, x, y + 5, pen); + _vm->_screen->drawLine(x, y - 2, x, y - 5, pen); + _vm->_screen->drawLine(x, y + 2, x, y + 5, pen); } void Debugger::drawRect(int16 x1, int16 y1, int16 x2, int16 y2, uint8 pen) { - _vm->_graphics->drawLine(x1, y1, x2, y1, pen); // top edge - _vm->_graphics->drawLine(x1, y2, x2, y2, pen); // bottom edge - _vm->_graphics->drawLine(x1, y1, x1, y2, pen); // left edge - _vm->_graphics->drawLine(x2, y1, x2, y2, pen); // right edge + _vm->_screen->drawLine(x1, y1, x2, y1, pen); // top edge + _vm->_screen->drawLine(x1, y2, x2, y2, pen); // bottom edge + _vm->_screen->drawLine(x1, y1, x1, y2, pen); // left edge + _vm->_screen->drawLine(x2, y1, x2, y2, pen); // right edge } void Debugger::printCurrentInfo(void) { // prints general stuff about the screen, etc. + ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); - if (_vm->_thisScreen.background_layer_id) { - DebugPrintf("background layer id %d\n", _vm->_thisScreen.background_layer_id); - DebugPrintf("%d wide, %d high\n", _vm->_thisScreen.screen_wide, _vm->_thisScreen.screen_deep); - DebugPrintf("%d normal layers\n", _vm->_thisScreen.number_of_layers); + if (screenInfo->background_layer_id) { + DebugPrintf("background layer id %d\n", screenInfo->background_layer_id); + DebugPrintf("%d wide, %d high\n", screenInfo->screen_wide, screenInfo->screen_deep); + DebugPrintf("%d normal layers\n", screenInfo->number_of_layers); _vm->_logic->examineRunList(); } else diff --git a/sword2/debug.h b/sword2/debug.h index 87a9043990..a733052e14 100644 --- a/sword2/debug.h +++ b/sword2/debug.h @@ -22,7 +22,7 @@ #define D_DEBUG // FIXME: I don't know how large this constant used to be -#define MAX_DEBUG_TEXTS 50 +#define MAX_DEBUG_TEXTS 55 #define MAX_SHOWVARS 15 diff --git a/sword2/driver/_mouse.cpp b/sword2/driver/_mouse.cpp index 42ee42872c..606d362767 100644 --- a/sword2/driver/_mouse.cpp +++ b/sword2/driver/_mouse.cpp @@ -20,14 +20,19 @@ #include "common/stdafx.h" #include "common/system.h" + #include "sword2/sword2.h" -#include "sword2/driver/d_draw.h" +#include "sword2/mouse.h" namespace Sword2 { +// This is the maximum mouse cursor size in the SDL backend +#define MAX_MOUSE_W 80 +#define MAX_MOUSE_H 80 + #define MOUSEFLASHFRAME 6 -void Graphics::decompressMouse(byte *decomp, byte *comp, int width, int height, int pitch, int xOff, int yOff) { +void Mouse::decompressMouse(byte *decomp, byte *comp, int width, int height, int pitch, int xOff, int yOff) { int32 size = width * height; int32 i = 0; int x = 0; @@ -52,7 +57,7 @@ void Graphics::decompressMouse(byte *decomp, byte *comp, int width, int height, } } -void Graphics::drawMouse(void) { +void Mouse::drawMouse() { byte mouseData[MAX_MOUSE_W * MAX_MOUSE_H]; if (!_mouseAnim && !_luggageAnim) @@ -129,7 +134,7 @@ void Graphics::drawMouse(void) { * Animates the current mouse pointer */ -int32 Graphics::animateMouse(void) { +int32 Mouse::animateMouse() { uint8 prevMouseFrame = _mouseFrame; if (!_mouseAnim) @@ -154,7 +159,7 @@ int32 Graphics::animateMouse(void) { * or not there is a lead-in animation */ -int32 Graphics::setMouseAnim(byte *ma, int32 size, int32 mouseFlash) { +int32 Mouse::setMouseAnim(byte *ma, int32 size, int32 mouseFlash) { if (_mouseAnim) { free(_mouseAnim); _mouseAnim = NULL; @@ -194,7 +199,7 @@ int32 Graphics::setMouseAnim(byte *ma, int32 size, int32 mouseFlash) { * @param size the size of the animation data */ -int32 Graphics::setLuggageAnim(byte *ma, int32 size) { +int32 Mouse::setLuggageAnim(byte *ma, int32 size) { if (_luggageAnim) { free(_luggageAnim); _luggageAnim = NULL; diff --git a/sword2/driver/animation.cpp b/sword2/driver/animation.cpp index d6d58e856d..260d42f454 100644 --- a/sword2/driver/animation.cpp +++ b/sword2/driver/animation.cpp @@ -31,7 +31,6 @@ #include "sword2/resman.h" #include "sword2/sound.h" #include "sword2/driver/animation.h" -#include "sword2/driver/d_draw.h" #include "sword2/driver/menu.h" #include "sword2/driver/render.h" @@ -47,7 +46,7 @@ AnimationState::~AnimationState() { #ifdef BACKEND_8BIT void AnimationState::setPalette(byte *pal) { - _vm->_graphics->setPalette(0, 256, pal, RDPAL_INSTANT); + _vm->_screen->setPalette(0, 256, pal, RDPAL_INSTANT); } #else @@ -82,7 +81,7 @@ void AnimationState::drawTextObject(SpriteInfo *s, byte *src) { void AnimationState::clearScreen(void) { #ifdef BACKEND_8BIT - memset(_vm->_graphics->getScreen(), 0, MOVIE_WIDTH * MOVIE_HEIGHT); + memset(_vm->_screen->getScreen(), 0, MOVIE_WIDTH * MOVIE_HEIGHT); #else OverlayColor black = _sys->RGBToColor(0, 0, 0); @@ -93,7 +92,7 @@ void AnimationState::clearScreen(void) { void AnimationState::updateScreen(void) { #ifdef BACKEND_8BIT - byte *buf = _vm->_graphics->getScreen() + ((480 - MOVIE_HEIGHT) / 2) * RENDERWIDE + (640 - MOVIE_WIDTH) / 2; + byte *buf = _vm->_screen->getScreen() + ((480 - MOVIE_HEIGHT) / 2) * RENDERWIDE + (640 - MOVIE_WIDTH) / 2; _vm->_system->copyRectToScreen(buf, MOVIE_WIDTH, (640 - MOVIE_WIDTH) / 2, (480 - MOVIE_HEIGHT) / 2, MOVIE_WIDTH, MOVIE_HEIGHT); #else @@ -104,7 +103,7 @@ void AnimationState::updateScreen(void) { void AnimationState::drawYUV(int width, int height, byte *const *dat) { #ifdef BACKEND_8BIT - _vm->_graphics->plotYUV(lut, width, height, dat); + _vm->_screen->plotYUV(lut, width, height, dat); #else plotYUV(lookup, width, height, dat); #endif @@ -138,12 +137,12 @@ MoviePlayer::MoviePlayer(Sword2Engine *vm) void MoviePlayer::openTextObject(MovieTextObject *obj) { if (obj->textSprite) - _vm->_graphics->createSurface(obj->textSprite, &_textSurface); + _vm->_screen->createSurface(obj->textSprite, &_textSurface); } void MoviePlayer::closeTextObject(MovieTextObject *obj) { if (_textSurface) { - _vm->_graphics->deleteSurface(_textSurface); + _vm->_screen->deleteSurface(_textSurface); _textSurface = NULL; } } @@ -151,12 +150,12 @@ void MoviePlayer::closeTextObject(MovieTextObject *obj) { void MoviePlayer::drawTextObject(AnimationState *anim, MovieTextObject *obj) { if (obj->textSprite && _textSurface) { #ifdef BACKEND_8BIT - _vm->_graphics->drawSurface(obj->textSprite, _textSurface); + _vm->_screen->drawSurface(obj->textSprite, _textSurface); #else if (anim) anim->drawTextObject(obj->textSprite, _textSurface); else - _vm->_graphics->drawSurface(obj->textSprite, _textSurface); + _vm->_screen->drawSurface(obj->textSprite, _textSurface); #endif } } @@ -211,7 +210,7 @@ int32 MoviePlayer::play(const char *filename, MovieTextObject *text[], int32 lea // Wait for the lead-out to stop, if there is any. while (_leadOutHandle.isActive()) { - _vm->_graphics->updateDisplay(); + _vm->_screen->updateDisplay(); _vm->_system->delayMillis(30); } @@ -232,7 +231,7 @@ void MoviePlayer::playMPEG(const char *filename, MovieTextObject *text[], byte * bool startNextText = false; byte oldPal[256 * 4]; - memcpy(oldPal, _vm->_graphics->_palette, sizeof(oldPal)); + memcpy(oldPal, _vm->_screen->getPalette(), sizeof(oldPal)); AnimationState *anim = new AnimationState(_vm); @@ -246,8 +245,8 @@ void MoviePlayer::playMPEG(const char *filename, MovieTextObject *text[], byte * #ifndef BACKEND_8BIT // Clear the screen, because whatever is on it will be visible when the // overlay is removed. - _vm->_graphics->clearScene(); - _vm->_graphics->updateDisplay(); + _vm->_screen->clearScene(); + _vm->_screen->updateDisplay(); #endif #ifndef SCUMM_BIG_ENDIAN @@ -357,7 +356,7 @@ void MoviePlayer::playMPEG(const char *filename, MovieTextObject *text[], byte * _snd->stopHandle(handle); while (handle.isActive()) { - _vm->_graphics->updateDisplay(false); + _vm->_screen->updateDisplay(false); _sys->delayMillis(100); } @@ -365,7 +364,7 @@ void MoviePlayer::playMPEG(const char *filename, MovieTextObject *text[], byte * anim->clearScreen(); anim->updateScreen(); - _vm->_graphics->setPalette(0, 256, oldPal, RDPAL_INSTANT); + _vm->_screen->setPalette(0, 256, oldPal, RDPAL_INSTANT); delete anim; } @@ -384,14 +383,14 @@ void MoviePlayer::playDummy(const char *filename, MovieTextObject *text[], byte byte oldPal[256 * 4]; byte tmpPal[256 * 4]; - _vm->_graphics->clearScene(); + _vm->_screen->clearScene(); // HACK: Draw instructions // // I'm using the the menu area, because that's unlikely to be touched // by anything else during the cutscene. - memset(_vm->_graphics->_buffer, 0, _vm->_graphics->_screenWide * MENUDEEP); + memset(_vm->_screen->getScreen(), 0, _vm->_screen->getScreenWide() * MENUDEEP); byte *data; @@ -415,16 +414,16 @@ void MoviePlayer::playDummy(const char *filename, MovieTextObject *text[], byte SpriteInfo msgSprite; byte *msgSurface; - msgSprite.x = _vm->_graphics->_screenWide / 2 - frame->width / 2; + msgSprite.x = _vm->_screen->getScreenWide() / 2 - frame->width / 2; msgSprite.y = RDMENU_MENUDEEP / 2 - frame->height / 2; msgSprite.w = frame->width; msgSprite.h = frame->height; msgSprite.type = RDSPR_NOCOMPRESSION; msgSprite.data = data + sizeof(FrameHeader); - _vm->_graphics->createSurface(&msgSprite, &msgSurface); - _vm->_graphics->drawSurface(&msgSprite, msgSurface); - _vm->_graphics->deleteSurface(msgSurface); + _vm->_screen->createSurface(&msgSprite, &msgSurface); + _vm->_screen->drawSurface(&msgSprite, msgSurface); + _vm->_screen->deleteSurface(msgSurface); free(data); @@ -436,12 +435,12 @@ void MoviePlayer::playDummy(const char *filename, MovieTextObject *text[], byte // Fake a palette that will hopefully make the text visible. In the // opening cutscene it seems to use colours 1 (black) and 255 (white). - memcpy(oldPal, _vm->_graphics->_palette, sizeof(oldPal)); + memcpy(oldPal, _vm->_screen->getPalette(), sizeof(oldPal)); memset(tmpPal, 0, sizeof(tmpPal)); tmpPal[255 * 4 + 0] = 255; tmpPal[255 * 4 + 1] = 255; tmpPal[255 * 4 + 2] = 255; - _vm->_graphics->setPalette(0, 256, tmpPal, RDPAL_INSTANT); + _vm->_screen->setPalette(0, 256, tmpPal, RDPAL_INSTANT); PlayingSoundHandle handle; @@ -458,7 +457,7 @@ void MoviePlayer::playDummy(const char *filename, MovieTextObject *text[], byte break; if (frameCounter == text[textCounter]->startFrame) { - _vm->_graphics->clearScene(); + _vm->_screen->clearScene(); openTextObject(text[textCounter]); drawTextObject(NULL, text[textCounter]); if (text[textCounter]->speech) { @@ -468,13 +467,13 @@ void MoviePlayer::playDummy(const char *filename, MovieTextObject *text[], byte if (frameCounter == text[textCounter]->endFrame) { closeTextObject(text[textCounter]); - _vm->_graphics->clearScene(); - _vm->_graphics->setNeedFullRedraw(); + _vm->_screen->clearScene(); + _vm->_screen->setNeedFullRedraw(); textCounter++; } frameCounter++; - _vm->_graphics->updateDisplay(); + _vm->_screen->updateDisplay(); KeyboardEvent *ke = _vm->keyboardEvent(); @@ -496,23 +495,23 @@ void MoviePlayer::playDummy(const char *filename, MovieTextObject *text[], byte // importantly - that we don't free the sound buffer while it's in use. while (handle.isActive()) { - _vm->_graphics->updateDisplay(false); + _vm->_screen->updateDisplay(false); _sys->delayMillis(100); } closeTextObject(text[textCounter]); - _vm->_graphics->clearScene(); - _vm->_graphics->setNeedFullRedraw(); + _vm->_screen->clearScene(); + _vm->_screen->setNeedFullRedraw(); // HACK: Remove the instructions created above Common::Rect r; - memset(_vm->_graphics->_buffer, 0, _vm->_graphics->_screenWide * MENUDEEP); + memset(_vm->_screen->getScreen(), 0, _vm->_screen->getScreenWide() * MENUDEEP); r.left = r.top = 0; - r.right = _vm->_graphics->_screenWide; + r.right = _vm->_screen->getScreenWide(); r.bottom = MENUDEEP; - _vm->_graphics->updateRect(&r); + _vm->_screen->updateRect(&r); // FIXME: For now, only play the lead-out music for cutscenes that have // subtitles. @@ -520,7 +519,7 @@ void MoviePlayer::playDummy(const char *filename, MovieTextObject *text[], byte if (!skipCutscene && leadOut) _vm->_sound->playFx(&_leadOutHandle, leadOut, leadOutLen, SoundMixer::kMaxChannelVolume, 0, false, SoundMixer::kMusicAudioDataType); - _vm->_graphics->setPalette(0, 256, oldPal, RDPAL_INSTANT); + _vm->_screen->setPalette(0, 256, oldPal, RDPAL_INSTANT); } } // End of namespace Sword2 diff --git a/sword2/driver/animation.h b/sword2/driver/animation.h index f34d8c8b06..0dcac3fc81 100644 --- a/sword2/driver/animation.h +++ b/sword2/driver/animation.h @@ -23,12 +23,24 @@ #define ANIMATION_H #include "graphics/animation.h" - #include "sound/mixer.h" - namespace Sword2 { +struct SpriteInfo; + +// This is the structure which is passed to the sequence player. It includes +// the smack to play, and any text lines which are to be displayed over the top +// of the sequence. + +struct MovieTextObject { + uint16 startFrame; + uint16 endFrame; + SpriteInfo *textSprite; + uint32 speechBufferSize; + uint16 *speech; +}; + class AnimationState : public ::Graphics::BaseAnimationState { private: Sword2Engine *_vm; diff --git a/sword2/driver/d_draw.cpp b/sword2/driver/d_draw.cpp index cee13d5d06..b20123e4b5 100644 --- a/sword2/driver/d_draw.cpp +++ b/sword2/driver/d_draw.cpp @@ -21,72 +21,20 @@ #include "common/stdafx.h" #include "common/system.h" #include "sword2/sword2.h" -#include "sword2/driver/d_draw.h" #include "sword2/driver/menu.h" #include "sword2/driver/render.h" namespace Sword2 { -Graphics::Graphics(Sword2Engine *vm, int16 width, int16 height) - : _vm(vm), _iconCount(0), _needFullRedraw(false), - _fadeStatus(RDFADE_NONE), _mouseSprite(NULL), _mouseAnim(NULL), - _luggageAnim(NULL), _layer(0), _renderAverageTime(60), - _lightMask(NULL), _screenWide(width), _screenDeep(height) { - - int i, j; - - _buffer = _dirtyGrid = NULL; - - _buffer = (byte *) malloc(width * height); - if (!_buffer) - error("Could not initialise display"); - - _vm->_system->initSize(width, height); - - _gridWide = width / CELLWIDE; - _gridDeep = height / CELLDEEP; - - if ((width % CELLWIDE) || (height % CELLDEEP)) - error("Bad cell size"); - - _dirtyGrid = (byte *) calloc(_gridWide, _gridDeep); - if (!_buffer) - error("Could not initialise dirty grid"); - - for (i = 0; i < ARRAYSIZE(_blockSurfaces); i++) - _blockSurfaces[i] = NULL; - - for (i = 0; i < 2; i++) { - for (j = 0; j < RDMENU_MAXPOCKETS; j++) { - _icons[i][j] = NULL; - _pocketStatus[i][j] = 0; - } - - _menuStatus[i] = RDMENU_HIDDEN; - } -} - -Graphics::~Graphics() { - free(_buffer); - free(_dirtyGrid); - closeBackgroundLayer(); - free(_lightMask); - free(_mouseAnim); - free(_luggageAnim); - for (int i = 0; i < 2; i++) - for (int j = 0; j < RDMENU_MAXPOCKETS; j++) - free(_icons[i][j]); -} - /** * @return the graphics detail setting */ -int8 Graphics::getRenderLevel(void) { +int8 Screen::getRenderLevel() { return _renderLevel; } -void Graphics::setRenderLevel(int8 level) { +void Screen::setRenderLevel(int8 level) { _renderLevel = level; switch (_renderLevel) { @@ -115,7 +63,7 @@ void Graphics::setRenderLevel(int8 level) { * touch the menu areas of the screen. */ -void Graphics::clearScene(void) { +void Screen::clearScene() { memset(_buffer + MENUDEEP * _screenWide, 0, _screenWide * RENDERDEEP); _needFullRedraw = true; } diff --git a/sword2/driver/d_draw.h b/sword2/driver/d_draw.h deleted file mode 100644 index e9b27c7f2c..0000000000 --- a/sword2/driver/d_draw.h +++ /dev/null @@ -1,242 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2005 The ScummVM project - * - * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * $Header$ - */ - -#ifndef D_DRAW_H -#define D_DRAW_H - -#include "common/rect.h" - -namespace Sword2 { - -// This is the maximum mouse cursor size in the SDL backend - -#define MAX_MOUSE_W 80 -#define MAX_MOUSE_H 80 - -#define RENDERAVERAGETOTAL 4 - -#define BLOCKWIDTH 64 -#define BLOCKHEIGHT 64 -#define MAXLAYERS 5 - -#define PALTABLESIZE 64 * 64 * 64 - -// Maximum scaled size of a sprite -#define SCALE_MAXWIDTH 512 -#define SCALE_MAXHEIGHT 512 - -// Dirty grid cell size -#define CELLWIDE 10 -#define CELLDEEP 20 - -#if !defined(__GNUC__) - #pragma START_PACK_STRUCTS -#endif - -struct MouseAnim { - uint8 runTimeComp; // type of runtime compression used for the - // frame data - uint8 noAnimFrames; // number of frames in the anim - int8 xHotSpot; - int8 yHotSpot; - uint8 mousew; - uint8 mouseh; -} GCC_PACK; - -#if !defined(__GNUC__) - #pragma END_PACK_STRUCTS -#endif - -struct BlockSurface { - byte data[BLOCKWIDTH * BLOCKHEIGHT]; - bool transparent; -}; - -class Graphics { - friend class MoviePlayer; - -private: - Sword2Engine *_vm; - - byte *_buffer; - byte *_dirtyGrid; - - uint16 _gridWide; - uint16 _gridDeep; - - int32 _renderCaps; - int8 _renderLevel; - - uint8 _menuStatus[2]; - byte *_icons[2][RDMENU_MAXPOCKETS]; - uint8 _pocketStatus[2][RDMENU_MAXPOCKETS]; - - uint8 _iconCount; - - bool _needFullRedraw; - - byte _paletteMatch[PALTABLESIZE]; - - uint8 _fadeStatus; - - int32 _fadeStartTime; - int32 _fadeTotalTime; - - uint8 _mouseFrame; - byte *_mouseSprite; - struct MouseAnim *_mouseAnim; - struct MouseAnim *_luggageAnim; - int32 *_mouseOffsets; - int32 *_luggageOffset; - - // Scroll variables. _scrollX and _scrollY hold the current scroll - // position, and _scrollXTarget and _scrollYTarget are the target - // position for the end of the game cycle. - - int16 _scrollX; - int16 _scrollY; - - int16 _scrollXTarget; - int16 _scrollYTarget; - int16 _scrollXOld; - int16 _scrollYOld; - - int16 _parallaxScrollX; // current x offset to link a sprite to the - // parallax layer - int16 _parallaxScrollY; // current y offset to link a sprite to the - // parallax layer - int16 _locationWide; - int16 _locationDeep; - - uint16 _layer; - - int32 _initialTime; - int32 _startTime; - int32 _totalTime; - int32 _renderAverageTime; - int32 _framesPerGameCycle; - bool _renderTooSlow; - - uint8 _xBlocks[MAXLAYERS]; - uint8 _yBlocks[MAXLAYERS]; - - // An array of sub-blocks, one for each of the parallax layers. - - BlockSurface **_blockSurfaces[MAXLAYERS]; - - uint16 _xScale[SCALE_MAXWIDTH]; - uint16 _yScale[SCALE_MAXHEIGHT]; - - byte *_lightMask; - - void clearIconArea(int menu, int pocket, Common::Rect *r); - - void decompressMouse(byte *decomp, byte *comp, int width, int height, int pitch, int xOff = 0, int yOff = 0); - - void fadeServer(void); - - void scaleImageFast(byte *dst, uint16 dstPitch, uint16 dstWidth, - uint16 dstHeight, byte *src, uint16 srcPitch, uint16 srcWidth, - uint16 srcHeight); - void scaleImageGood(byte *dst, uint16 dstPitch, uint16 dstWidth, - uint16 dstHeight, byte *src, uint16 srcPitch, uint16 srcWidth, - uint16 srcHeight, byte *backbuf); - - void updateRect(Common::Rect *r); - - void blitBlockSurface(BlockSurface *s, Common::Rect *r, Common::Rect *clipRect); - - void mirrorSprite(byte *dst, byte *src, int16 w, int16 h); - int32 decompressRLE256(byte *dest, byte *source, int32 decompSize); - void unwindRaw16(byte *dest, byte *source, uint8 blockSize, byte *colTable); - int32 decompressRLE16(byte *dest, byte *source, int32 decompSize, byte *colTable); - - -public: - Graphics(Sword2Engine *vm, int16 width, int16 height); - ~Graphics(); - - // Game screen metrics - int16 _screenWide; - int16 _screenDeep; - - byte _palette[256 * 4]; - - byte *getScreen(void) { return _buffer; } - - int8 getRenderLevel(void); - void setRenderLevel(int8 level); - - void clearScene(void); - - void processMenu(void); - int32 showMenu(uint8 menu); - int32 hideMenu(uint8 menu); - int32 setMenuIcon(uint8 menu, uint8 pocket, byte *icon); - void closeMenuImmediately(void); - - void markAsDirty(int16 x0, int16 y0, int16 x1, int16 y1); - void updateDisplay(bool redrawScene = true); - void setNeedFullRedraw(void); - - void setPalette(int16 startEntry, int16 noEntries, byte *palette, uint8 setNow); - void updatePaletteMatchTable(byte *data); - uint8 quickMatch(uint8 r, uint8 g, uint8 b); - int32 fadeUp(float time = 0.75); - int32 fadeDown(float time = 0.75); - uint8 getFadeStatus(void); - void dimPalette(void); - void waitForFade(void); - - int32 setMouseAnim(byte *ma, int32 size, int32 mouseFlash); - int32 setLuggageAnim(byte *la, int32 size); - int32 animateMouse(void); - - void drawMouse(void); - - void resetRenderEngine(void); - - void setScrollTarget(int16 sx, int16 sy); - void initialiseRenderCycle(void); - void startRenderCycle(void); - bool endRenderCycle(void); - void renderParallax(Parallax *p, int16 layer); - void setLocationMetrics(uint16 w, uint16 h); - int32 initialiseBackgroundLayer(Parallax *p); - void closeBackgroundLayer(void); - - void plotPoint(int16 x, int16 y, uint8 colour); - void drawLine(int16 x1, int16 y1, int16 x2, int16 y2, uint8 colour); -#ifdef BACKEND_8BIT - void plotYUV(byte *lut, int width, int height, byte *const *dat); -#endif - - - int32 createSurface(SpriteInfo *s, byte **surface); - void drawSurface(SpriteInfo *s, byte *surface, Common::Rect *clipRect = NULL); - void deleteSurface(byte *surface); - int32 drawSprite(SpriteInfo *s); - int32 openLightMask(SpriteInfo *s); - int32 closeLightMask(void); -}; - -} // End of namespace Sword2 - -#endif diff --git a/sword2/driver/d_sound.cpp b/sword2/driver/d_sound.cpp index 39992b18d6..a8e3d444e0 100644 --- a/sword2/driver/d_sound.cpp +++ b/sword2/driver/d_sound.cpp @@ -35,7 +35,6 @@ #include "sword2/sword2.h" #include "sword2/resman.h" #include "sword2/sound.h" -#include "sword2/driver/d_draw.h" namespace Sword2 { @@ -790,8 +789,11 @@ int32 Sound::setFxIdVolumePan(int32 i, int vol, int pan) { _fxQueue[i].volume = (vol * SoundMixer::kMaxChannelVolume) / 16; - if (pan != -1) + if (pan != 255) { + if (isReverseStereo()) + pan = -pan; _fxQueue[i].pan = (pan * 127) / 16; + } if (!_fxMuted && _fxQueue[i].handle.isActive()) { _vm->_mixer->setChannelVolume(_fxQueue[i].handle, _fxQueue[i].volume); diff --git a/sword2/driver/driver96.h b/sword2/driver/driver96.h index a10c4652f1..43acd6e7b2 100644 --- a/sword2/driver/driver96.h +++ b/sword2/driver/driver96.h @@ -177,36 +177,6 @@ struct Parallax { #pragma END_PACK_STRUCTS #endif -// The SpriteInfo structure is used to tell the driver96 code what attributes -// are linked to a sprite for drawing. These include position, scaling and -// compression. - -struct SpriteInfo { - int16 x; // coords for top-left of sprite - int16 y; - uint16 w; // dimensions of sprite (before scaling) - uint16 h; - uint16 scale; // scale at which to draw, given in 256ths ['0' or '256' MEANS DON'T SCALE] - uint16 scaledWidth; // new dimensions (we calc these for the mouse area, so may as well pass to you to save time) - uint16 scaledHeight; // - uint16 type; // mask containing 'RDSPR_' bits specifying compression type, flip, transparency, etc - uint16 blend; // holds the blending values. - byte *data; // pointer to the sprite data - byte *colourTable; // pointer to 16-byte colour table, only applicable to 16-col compression type -}; - -// This is the structure which is passed to the sequence player. It includes -// the smack to play, and any text lines which are to be displayed over the top -// of the sequence. - -struct MovieTextObject { - uint16 startFrame; - uint16 endFrame; - SpriteInfo *textSprite; - uint32 speechBufferSize; - uint16 *speech; -}; - } // End of namespace Sword2 #endif diff --git a/sword2/driver/menu.cpp b/sword2/driver/menu.cpp index 4929a97696..267a254a4d 100644 --- a/sword2/driver/menu.cpp +++ b/sword2/driver/menu.cpp @@ -20,7 +20,7 @@ #include "common/stdafx.h" #include "sword2/sword2.h" -#include "sword2/driver/d_draw.h" +#include "sword2/mouse.h" #include "sword2/driver/render.h" namespace Sword2 { @@ -28,17 +28,20 @@ namespace Sword2 { #define MENUDEEP 40 #define MAXMENUANIMS 8 -void Graphics::clearIconArea(int menu, int pocket, Common::Rect *r) { +void Mouse::clearIconArea(int menu, int pocket, Common::Rect *r) { + byte *buf = _vm->_screen->getScreen(); + int16 screenWide = _vm->_screen->getScreenWide(); + r->top = menu * (RENDERDEEP + MENUDEEP) + (MENUDEEP - RDMENU_ICONDEEP) / 2; r->bottom = r->top + RDMENU_ICONDEEP; r->left = RDMENU_ICONSTART + pocket * (RDMENU_ICONWIDE + RDMENU_ICONSPACING); r->right = r->left + RDMENU_ICONWIDE; - byte *dst = _buffer + r->top * _screenWide + r->left; + byte *dst = buf + r->top * screenWide + r->left; for (int i = 0; i < RDMENU_ICONDEEP; i++) { memset(dst, 0, RDMENU_ICONWIDE); - dst += _screenWide; + dst += screenWide; } } @@ -48,13 +51,16 @@ void Graphics::clearIconArea(int menu, int pocket, Common::Rect *r) { * system is. */ -void Graphics::processMenu(void) { +void Mouse::processMenu() { uint8 menu; uint8 i, j; uint8 frameCount; Common::Rect r1, r2; static int32 lastTime = 0; + byte *buf = _vm->_screen->getScreen(); + int16 screenWide = _vm->_screen->getScreenWide(); + if (lastTime == 0) { lastTime = _vm->getMillis(); frameCount = 1; @@ -153,22 +159,22 @@ void Graphics::processMenu(void) { } if (xoff != 0 && yoff != 0) { - byte *dst = _buffer + r2.top * _screenWide + r2.left; + byte *dst = buf + r2.top * screenWide + r2.left; byte *src = _icons[menu][i]; if (_pocketStatus[menu][i] != MAXMENUANIMS) { - scaleImageFast( - dst, _screenWide, r2.right - r2.left, r2.bottom - r2.top, + _vm->_screen->scaleImageFast( + dst, screenWide, r2.right - r2.left, r2.bottom - r2.top, src, RDMENU_ICONWIDE, RDMENU_ICONWIDE, RDMENU_ICONDEEP); } else { for (j = 0; j < RDMENU_ICONDEEP; j++) { memcpy(dst, src, RDMENU_ICONWIDE); src += RDMENU_ICONWIDE; - dst += _screenWide; + dst += screenWide; } } } - updateRect(&r1); + _vm->_screen->updateRect(&r1); } curx += (RDMENU_ICONSPACING + RDMENU_ICONWIDE); } @@ -181,7 +187,7 @@ void Graphics::processMenu(void) { * @return RD_OK, or an error code */ -int32 Graphics::showMenu(uint8 menu) { +int32 Mouse::showMenu(uint8 menu) { // Check for invalid menu parameter if (menu > RDMENU_BOTTOM) return RDERR_INVALIDMENU; @@ -201,7 +207,7 @@ int32 Graphics::showMenu(uint8 menu) { * @return RD_OK, or an error code */ -int32 Graphics::hideMenu(uint8 menu) { +int32 Mouse::hideMenu(uint8 menu) { // Check for invalid menu parameter if (menu > RDMENU_BOTTOM) return RDERR_INVALIDMENU; @@ -219,7 +225,7 @@ int32 Graphics::hideMenu(uint8 menu) { * This function hides both menus immediately. */ -void Graphics::closeMenuImmediately(void) { +void Mouse::closeMenuImmediately() { Common::Rect r; int i; @@ -229,11 +235,11 @@ void Graphics::closeMenuImmediately(void) { for (i = 0; i < RDMENU_MAXPOCKETS; i++) { if (_icons[RDMENU_TOP][i]) { clearIconArea(RDMENU_TOP, i, &r); - updateRect(&r); + _vm->_screen->updateRect(&r); } if (_icons[RDMENU_BOTTOM][i]) { clearIconArea(RDMENU_BOTTOM, i, &r); - updateRect(&r); + _vm->_screen->updateRect(&r); } } @@ -248,7 +254,7 @@ void Graphics::closeMenuImmediately(void) { * @return RD_OK, or an error code */ -int32 Graphics::setMenuIcon(uint8 menu, uint8 pocket, byte *icon) { +int32 Mouse::setMenuIcon(uint8 menu, uint8 pocket, byte *icon) { Common::Rect r; // Check for invalid menu parameter. @@ -265,7 +271,7 @@ int32 Graphics::setMenuIcon(uint8 menu, uint8 pocket, byte *icon) { free(_icons[menu][pocket]); _icons[menu][pocket] = NULL; clearIconArea(menu, pocket, &r); - updateRect(&r); + _vm->_screen->updateRect(&r); } // Only put the icon in the pocket if it is not NULL diff --git a/sword2/driver/palette.cpp b/sword2/driver/palette.cpp index 754a3564ce..3e42cef493 100644 --- a/sword2/driver/palette.cpp +++ b/sword2/driver/palette.cpp @@ -21,19 +21,101 @@ #include "common/stdafx.h" #include "common/system.h" #include "sword2/sword2.h" -#include "sword2/driver/d_draw.h" +#include "sword2/defs.h" +#include "sword2/logic.h" +#include "sword2/resman.h" namespace Sword2 { /** - * Sets a table of palette indices which will be searched later for a quick - * palette match. - * @param data the palette match table + * Start layer palette fading up */ -void Graphics::updatePaletteMatchTable(byte *data) { - assert(data); - memcpy(_paletteMatch, data, PALTABLESIZE); +void Screen::startNewPalette() { + // If the screen is still fading down then wait for black - could + // happen when everythings cached into a large memory model + waitForFade(); + + byte *screenFile = _vm->_resman->openResource(_thisScreen.background_layer_id); + + memcpy(_paletteMatch, _vm->fetchPaletteMatchTable(screenFile), PALTABLESIZE); + setPalette(0, 256, _vm->fetchPalette(screenFile), RDPAL_FADE); + + // Indicating that it's a screen palette + _lastPaletteRes = 0; + + _vm->_resman->closeResource(_thisScreen.background_layer_id); + fadeUp(); + _thisScreen.new_palette = 0; +} + +void Screen::setFullPalette(int32 palRes) { + // fudge for hut interior + // - unpausing should restore last palette as normal (could be screen + // palette or 'dark_palette_13') + // - but restoring the screen palette after 'dark_palette_13' should + // now work properly too! + + // "Hut interior" refers to the watchman's hut in Marseille, and this + // is apparently needed for the palette to be restored properly when + // you turn the light off. (I didn't even notice the light switch!) + + if (Logic::_scriptVars[LOCATION] == 13) { + // unpausing + if (palRes == -1) { + // restore whatever palette was last set (screen + // palette or 'dark_palette_13') + palRes = _lastPaletteRes; + } + } else { + // check if we're just restoring the current screen palette + // because we might actually need to use a separate palette + // file anyway eg. for pausing & unpausing during the eclipse + + // unpausing (fudged for location 13) + if (palRes == -1) { + // we really meant '0' + palRes = 0; + } + + if (palRes == 0 && _lastPaletteRes) + palRes = _lastPaletteRes; + } + + // If non-zero, set palette to this separate palette file. Otherwise, + // set palette to current screen palette. + + if (palRes) { + byte *pal = _vm->_resman->openResource(palRes); + + StandardHeader *head = (StandardHeader *) pal; + assert(head->fileType == PALETTE_FILE); + + pal += sizeof(StandardHeader); + + // always set colour 0 to black because most background screen + // palettes have a bright colour 0 although it should come out + // as black in the game! + + pal[0] = 0; + pal[1] = 0; + pal[2] = 0; + pal[3] = 0; + + setPalette(0, 256, pal, RDPAL_INSTANT); + _vm->_resman->closeResource(palRes); + } else { + if (_thisScreen.background_layer_id) { + byte *data = _vm->_resman->openResource(_thisScreen.background_layer_id); + memcpy(_paletteMatch, _vm->fetchPaletteMatchTable(data), PALTABLESIZE); + setPalette(0, 256, _vm->fetchPalette(data), RDPAL_INSTANT); + _vm->_resman->closeResource(_thisScreen.background_layer_id); + } else + error("setFullPalette(0) called, but no current screen available!"); + } + + if (palRes != CONTROL_PANEL_PALETTE) + _lastPaletteRes = palRes; } /** @@ -47,7 +129,7 @@ void Graphics::updatePaletteMatchTable(byte *data) { // FIXME: This used to be inlined - probably a good idea - but the // linker complained when I tried to use it in sprite.cpp. -uint8 Graphics::quickMatch(uint8 r, uint8 g, uint8 b) { +uint8 Screen::quickMatch(uint8 r, uint8 g, uint8 b) { return _paletteMatch[((int32) (r >> 2) << 12) + ((int32) (g >> 2) << 6) + (b >> 2)]; } @@ -59,7 +141,7 @@ uint8 Graphics::quickMatch(uint8 r, uint8 g, uint8 b) { * @param fadeNow whether to perform the change immediately or delayed */ -void Graphics::setPalette(int16 startEntry, int16 noEntries, byte *colourTable, uint8 fadeNow) { +void Screen::setPalette(int16 startEntry, int16 noEntries, byte *colourTable, uint8 fadeNow) { assert(noEntries > 0); memcpy(&_palette[4 * startEntry], colourTable, noEntries * 4); @@ -70,7 +152,7 @@ void Graphics::setPalette(int16 startEntry, int16 noEntries, byte *colourTable, } } -void Graphics::dimPalette(void) { +void Screen::dimPalette() { byte *p = _palette; for (int i = 0; i < 256; i++) { @@ -88,7 +170,7 @@ void Graphics::dimPalette(void) { * @param time the time it will take the palette to fade up */ -int32 Graphics::fadeUp(float time) { +int32 Screen::fadeUp(float time) { if (getFadeStatus() != RDFADE_BLACK && getFadeStatus() != RDFADE_NONE) return RDERR_FADEINCOMPLETE; @@ -104,7 +186,7 @@ int32 Graphics::fadeUp(float time) { * @param time the time it will take the palette to fade down */ -int32 Graphics::fadeDown(float time) { +int32 Screen::fadeDown(float time) { if (getFadeStatus() != RDFADE_BLACK && getFadeStatus() != RDFADE_NONE) return RDERR_FADEINCOMPLETE; @@ -121,18 +203,18 @@ int32 Graphics::fadeDown(float time) { * (not faded), or RDFADE_BLACK (completely faded down) */ -uint8 Graphics::getFadeStatus(void) { +uint8 Screen::getFadeStatus() { return _fadeStatus; } -void Graphics::waitForFade(void) { +void Screen::waitForFade() { while (getFadeStatus() != RDFADE_NONE && getFadeStatus() != RDFADE_BLACK) { updateDisplay(); _vm->_system->delayMillis(20); } } -void Graphics::fadeServer(void) { +void Screen::fadeServer() { static int32 previousTime = 0; byte fadePalette[256 * 4]; byte *newPalette = fadePalette; diff --git a/sword2/driver/rdwin.cpp b/sword2/driver/rdwin.cpp index 14d4e144f5..d74cc89bc8 100644 --- a/sword2/driver/rdwin.cpp +++ b/sword2/driver/rdwin.cpp @@ -21,7 +21,6 @@ #include "common/stdafx.h" #include "common/system.h" #include "sword2/sword2.h" -#include "sword2/driver/d_draw.h" #include "sword2/driver/menu.h" namespace Sword2 { @@ -30,7 +29,7 @@ namespace Sword2 { * Tell updateDisplay() that the scene needs to be completely updated. */ -void Graphics::setNeedFullRedraw(void) { +void Screen::setNeedFullRedraw() { _needFullRedraw = true; } @@ -38,7 +37,7 @@ void Graphics::setNeedFullRedraw(void) { * Mark an area of the screen as dirty, first generation. */ -void Graphics::markAsDirty(int16 x0, int16 y0, int16 x1, int16 y1) { +void Screen::markAsDirty(int16 x0, int16 y0, int16 x1, int16 y1) { int16 gridX0 = x0 / CELLWIDE; int16 gridY0 = y0 / CELLDEEP; int16 gridX1 = x1 / CELLWIDE; @@ -58,7 +57,7 @@ void Graphics::markAsDirty(int16 x0, int16 y0, int16 x1, int16 y1) { * @param redrawScene If true, redraw the scene. */ -void Graphics::updateDisplay(bool redrawScene) { +void Screen::updateDisplay(bool redrawScene) { _vm->parseEvents(); fadeServer(); diff --git a/sword2/driver/render.cpp b/sword2/driver/render.cpp index 5ea1c63b06..ff0dcab5a9 100644 --- a/sword2/driver/render.cpp +++ b/sword2/driver/render.cpp @@ -21,22 +21,23 @@ #include "common/stdafx.h" #include "common/system.h" #include "sword2/sword2.h" +#include "sword2/build_display.h" #include "sword2/driver/animation.h" -#include "sword2/driver/d_draw.h" #include "sword2/driver/menu.h" #include "sword2/driver/render.h" namespace Sword2 { -#define MILLISECSPERCYCLE 83 +#define MILLISECSPERCYCLE 83 +#define RENDERAVERAGETOTAL 4 -void Graphics::updateRect(Common::Rect *r) { +void Screen::updateRect(Common::Rect *r) { _vm->_system->copyRectToScreen(_buffer + r->top * _screenWide + r->left, _screenWide, r->left, r->top, r->right - r->left, r->bottom - r->top); } -void Graphics::blitBlockSurface(BlockSurface *s, Common::Rect *r, Common::Rect *clipRect) { +void Screen::blitBlockSurface(BlockSurface *s, Common::Rect *r, Common::Rect *clipRect) { if (!r->intersects(*clipRect)) return; @@ -85,7 +86,7 @@ void Graphics::blitBlockSurface(BlockSurface *s, Common::Rect *r, Common::Rect * // This code isn't quite like the original DrawSprite(), but should be close // enough. -void Graphics::scaleImageFast(byte *dst, uint16 dstPitch, uint16 dstWidth, uint16 dstHeight, byte *src, uint16 srcPitch, uint16 srcWidth, uint16 srcHeight) { +void Screen::scaleImageFast(byte *dst, uint16 dstPitch, uint16 dstWidth, uint16 dstHeight, byte *src, uint16 srcPitch, uint16 srcWidth, uint16 srcHeight) { int x, y; for (x = 0; x < dstWidth; x++) @@ -102,7 +103,7 @@ void Graphics::scaleImageFast(byte *dst, uint16 dstPitch, uint16 dstWidth, uint1 } } -void Graphics::scaleImageGood(byte *dst, uint16 dstPitch, uint16 dstWidth, uint16 dstHeight, byte *src, uint16 srcPitch, uint16 srcWidth, uint16 srcHeight, byte *backbuf) { +void Screen::scaleImageGood(byte *dst, uint16 dstPitch, uint16 dstWidth, uint16 dstHeight, byte *src, uint16 srcPitch, uint16 srcWidth, uint16 srcHeight, byte *backbuf) { for (int y = 0; y < dstHeight; y++) { for (int x = 0; x < dstWidth; x++) { uint8 c1, c2, c3, c4; @@ -194,7 +195,7 @@ void Graphics::scaleImageGood(byte *dst, uint16 dstPitch, uint16 dstWidth, uint1 * @param colour colour of the point */ -void Graphics::plotPoint(int16 x, int16 y, uint8 colour) { +void Screen::plotPoint(int16 x, int16 y, uint8 colour) { byte *buf = _buffer + MENUDEEP * RENDERWIDE; x -= _scrollX; @@ -217,7 +218,7 @@ void Graphics::plotPoint(int16 x, int16 y, uint8 colour) { // Uses Bresenham's incremental algorithm! -void Graphics::drawLine(int16 x0, int16 y0, int16 x1, int16 y1, uint8 colour) { +void Screen::drawLine(int16 x0, int16 y0, int16 x1, int16 y1, uint8 colour) { int dxmod, dymod; int ince, incne; int d; @@ -363,7 +364,7 @@ void Graphics::drawLine(int16 x0, int16 y0, int16 x1, int16 y1, uint8 colour) { * @param h height of the current location */ -void Graphics::setLocationMetrics(uint16 w, uint16 h) { +void Screen::setLocationMetrics(uint16 w, uint16 h) { _locationWide = w; _locationDeep = h; setNeedFullRedraw(); @@ -374,7 +375,7 @@ void Graphics::setLocationMetrics(uint16 w, uint16 h) { * parallax can be either foreground, background or the main screen. */ -void Graphics::renderParallax(Parallax *p, int16 l) { +void Screen::renderParallax(Parallax *p, int16 l) { int16 x, y; Common::Rect r; @@ -420,7 +421,7 @@ void Graphics::renderParallax(Parallax *p, int16 l) { * Initialises the timers before the render loop is entered. */ -void Graphics::initialiseRenderCycle(void) { +void Screen::initialiseRenderCycle(void) { _initialTime = _vm->_system->getMillis(); _totalTime = _initialTime + MILLISECSPERCYCLE; } @@ -430,7 +431,7 @@ void Graphics::initialiseRenderCycle(void) { * render cycle. */ -void Graphics::startRenderCycle(void) { +void Screen::startRenderCycle(void) { _scrollXOld = _scrollX; _scrollYOld = _scrollY; @@ -458,7 +459,7 @@ void Graphics::startRenderCycle(void) { * or false if it should continue */ -bool Graphics::endRenderCycle(void) { +bool Screen::endRenderCycle(void) { static int32 renderTimeLog[4] = { 60, 60, 60, 60 }; static int32 renderCountIndex = 0; int32 time; @@ -524,7 +525,7 @@ bool Graphics::endRenderCycle(void) { * Reset scrolling stuff. This function is called from initBackground() */ -void Graphics::resetRenderEngine(void) { +void Screen::resetRenderEngine(void) { _parallaxScrollX = 0; _parallaxScrollY = 0; _scrollX = 0; @@ -532,22 +533,11 @@ void Graphics::resetRenderEngine(void) { } /** - * Sets the scroll target position for the end of the game cycle. The driver - * will then automatically scroll as many times as it can to reach this - * position in the allotted time. - */ - -void Graphics::setScrollTarget(int16 sx, int16 sy) { - _scrollXTarget = sx; - _scrollYTarget = sy; -} - -/** * This function should be called five times with either the parallax layer * or a NULL pointer in order of background parallax to foreground parallax. */ -int32 Graphics::initialiseBackgroundLayer(Parallax *p) { +int32 Screen::initialiseBackgroundLayer(Parallax *p) { uint16 i, j, k; byte *data; byte *dst; @@ -666,7 +656,7 @@ int32 Graphics::initialiseBackgroundLayer(Parallax *p) { * Should be called once after leaving the room to free up memory. */ -void Graphics::closeBackgroundLayer(void) { +void Screen::closeBackgroundLayer(void) { debug(2, "CloseBackgroundLayer"); for (int i = 0; i < MAXLAYERS; i++) { @@ -683,7 +673,7 @@ void Graphics::closeBackgroundLayer(void) { } #ifdef BACKEND_8BIT -void Graphics::plotYUV(byte *lut, int width, int height, byte *const *dat) { +void Screen::plotYUV(byte *lut, int width, int height, byte *const *dat) { byte *buf = _buffer + ((480 - height) / 2) * RENDERWIDE + (640 - width) / 2; int x, y; diff --git a/sword2/driver/sprite.cpp b/sword2/driver/sprite.cpp index e6c1ffe0e8..7c96df75c2 100644 --- a/sword2/driver/sprite.cpp +++ b/sword2/driver/sprite.cpp @@ -20,7 +20,7 @@ #include "common/stdafx.h" #include "sword2/sword2.h" -#include "sword2/driver/d_draw.h" +#include "sword2/build_display.h" namespace Sword2 { @@ -32,7 +32,7 @@ namespace Sword2 { * @param h height of the sprite */ -void Graphics::mirrorSprite(byte *dst, byte *src, int16 w, int16 h) { +void Screen::mirrorSprite(byte *dst, byte *src, int16 w, int16 h) { for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { *dst++ = *(src + w - x - 1); @@ -44,12 +44,12 @@ void Graphics::mirrorSprite(byte *dst, byte *src, int16 w, int16 h) { /** * This function takes a compressed frame of a sprite with up to 256 colours * and decompresses it. - * @param dest destination buffer - * @param source source buffer + * @param dst destination buffer + * @param src source buffer * @param decompSize the expected size of the decompressed sprite */ -int32 Graphics::decompressRLE256(byte *dest, byte *source, int32 decompSize) { +int32 Screen::decompressRLE256(byte *dst, byte *src, int32 decompSize) { // PARAMETERS: // source points to the start of the sprite data for input // decompSize gives size of decompressed data in bytes @@ -57,35 +57,35 @@ int32 Graphics::decompressRLE256(byte *dest, byte *source, int32 decompSize) { // data byte headerByte; // block header byte - byte *endDest = dest + decompSize; // pointer to byte after end of decomp buffer + byte *endDest = dst + decompSize; // pointer to byte after end of decomp buffer int32 rv; - while(1) { + while (1) { // FLAT block // read FLAT block header & increment 'scan' to first pixel // of block - headerByte = *source++; + headerByte = *src++; // if this isn't a zero-length block if (headerByte) { - if (dest + headerByte > endDest) { + if (dst + headerByte > endDest) { rv = 1; break; } // set the next 'headerByte' pixels to the next colour // at 'source' - memset(dest, *source, headerByte); + memset(dst, *src, headerByte); // increment destination pointer to just after this // block - dest += headerByte; + dst += headerByte; // increment source pointer to just after this colour - source++; + src++; // if we've decompressed all of the data - if (dest == endDest) { + if (dst == endDest) { rv = 0; // return "OK" break; } @@ -94,28 +94,28 @@ int32 Graphics::decompressRLE256(byte *dest, byte *source, int32 decompSize) { // RAW block // read RAW block header & increment 'scan' to first pixel of // block - headerByte = *source++; + headerByte = *src++; // if this isn't a zero-length block if (headerByte) { - if (dest + headerByte > endDest) { + if (dst + headerByte > endDest) { rv = 1; break; } // copy the next 'headerByte' pixels from source to // destination - memcpy(dest,source,headerByte); + memcpy(dst, src, headerByte); // increment destination pointer to just after this // block - dest += headerByte; + dst += headerByte; // increment source pointer to just after this block - source += headerByte; + src += headerByte; // if we've decompressed all of the data - if (dest == endDest) { + if (dst == endDest) { rv = 0; // return "OK" break; } @@ -129,19 +129,19 @@ int32 Graphics::decompressRLE256(byte *dest, byte *source, int32 decompSize) { * Unwinds a run of 16-colour data into 256-colour palette data. */ -void Graphics::unwindRaw16(byte *dest, byte *source, uint8 blockSize, byte *colTable) { +void Screen::unwindRaw16(byte *dst, byte *src, uint8 blockSize, byte *colTable) { // for each pair of pixels while (blockSize > 1) { // 1st colour = number in table at position given by upper // nibble of source byte - *dest++ = colTable[(*source) >> 4]; + *dst++ = colTable[(*src) >> 4]; // 2nd colour = number in table at position given by lower // nibble of source byte - *dest++ = colTable[(*source) & 0x0f]; + *dst++ = colTable[(*src) & 0x0f]; // point to next source byte - source++; + src++; // decrement count of how many pixels left to read blockSize -= 2; @@ -151,50 +151,50 @@ void Graphics::unwindRaw16(byte *dest, byte *source, uint8 blockSize, byte *colT if (blockSize) { // colour = number in table at position given by upper nibble // of source byte - *dest++ = colTable[(*source) >> 4]; + *dst++ = colTable[(*src) >> 4]; } } /** * This function takes a compressed frame of a sprite (with up to 16 colours) * and decompresses it. - * @param dest destination buffer - * @param source source buffer + * @param dst destination buffer + * @param src source buffer * @param decompSize the expected size of the uncompressed sprite * @param colTable mapping from the 16 encoded colours to the current palette */ -int32 Graphics::decompressRLE16(byte *dest, byte *source, int32 decompSize, byte *colTable) { +int32 Screen::decompressRLE16(byte *dst, byte *src, int32 decompSize, byte *colTable) { byte headerByte; // block header byte - byte *endDest = dest + decompSize; // pointer to byte after end of decomp buffer + byte *endDest = dst + decompSize; // pointer to byte after end of decomp buffer int32 rv; - while(1) { + while (1) { // FLAT block // read FLAT block header & increment 'scan' to first pixel // of block - headerByte = *source++; + headerByte = *src++; // if this isn't a zero-length block if (headerByte) { - if (dest + headerByte > endDest) { + if (dst + headerByte > endDest) { rv = 1; break; } // set the next 'headerByte' pixels to the next // colour at 'source' - memset(dest, *source, headerByte); + memset(dst, *src, headerByte); // increment destination pointer to just after this // block - dest += headerByte; + dst += headerByte; // increment source pointer to just after this colour - source++; + src++; // if we've decompressed all of the data - if (dest == endDest) { + if (dst == endDest) { rv = 0; // return "OK" break; } @@ -203,29 +203,29 @@ int32 Graphics::decompressRLE16(byte *dest, byte *source, int32 decompSize, byte // RAW block // read RAW block header & increment 'scan' to first pixel of // block - headerByte = *source++; + headerByte = *src++; // if this isn't a zero-length block if (headerByte) { - if (dest + headerByte > endDest) { + if (dst + headerByte > endDest) { rv = 1; break; } // copy the next 'headerByte' pixels from source to // destination (NB. 2 pixels per byte) - unwindRaw16(dest, source, headerByte, colTable); + unwindRaw16(dst, src, headerByte, colTable); // increment destination pointer to just after this // block - dest += headerByte; + dst += headerByte; // increment source pointer to just after this block // (NB. headerByte gives pixels, so /2 for bytes) - source += (headerByte + 1) / 2; + src += (headerByte + 1) / 2; // if we've decompressed all of the data - if (dest >= endDest) { + if (dst >= endDest) { rv = 0; // return "OK" break; } @@ -244,7 +244,7 @@ int32 Graphics::decompressRLE16(byte *dest, byte *source, int32 decompSize, byte * @return RD_OK, or an error code */ -int32 Graphics::createSurface(SpriteInfo *s, byte **sprite) { +int32 Screen::createSurface(SpriteInfo *s, byte **sprite) { *sprite = (byte *) malloc(s->w * s->h); if (!*sprite) return RDERR_OUTOFMEMORY; @@ -269,7 +269,7 @@ int32 Graphics::createSurface(SpriteInfo *s, byte **sprite) { * @param clipRect the clipping rectangle */ -void Graphics::drawSurface(SpriteInfo *s, byte *surface, Common::Rect *clipRect) { +void Screen::drawSurface(SpriteInfo *s, byte *surface, Common::Rect *clipRect) { Common::Rect rd, rs; uint16 x, y; byte *src, *dst; @@ -328,7 +328,7 @@ void Graphics::drawSurface(SpriteInfo *s, byte *surface, Common::Rect *clipRect) * Destroys a surface. */ -void Graphics::deleteSurface(byte *surface) { +void Screen::deleteSurface(byte *surface) { free(surface); } @@ -353,7 +353,7 @@ void Graphics::deleteSurface(byte *surface) { // FIXME: I'm sure this could be optimized. There's plenty of data copying and // mallocing here. -int32 Graphics::drawSprite(SpriteInfo *s) { +int32 Screen::drawSprite(SpriteInfo *s) { byte *src, *dst; byte *sprite, *newSprite; uint16 scale; @@ -610,7 +610,7 @@ int32 Graphics::drawSprite(SpriteInfo *s) { * Opens the light masking sprite for a room. */ -int32 Graphics::openLightMask(SpriteInfo *s) { +int32 Screen::openLightMask(SpriteInfo *s) { // FIXME: The light mask is only needed on higher graphics detail // settings, so to save memory we could simply ignore it on lower // settings. But then we need to figure out how to ensure that it @@ -633,7 +633,7 @@ int32 Graphics::openLightMask(SpriteInfo *s) { * Closes the light masking sprite for a room. */ -int32 Graphics::closeLightMask(void) { +int32 Screen::closeLightMask(void) { if (!_lightMask) return RDERR_NOTOPEN; diff --git a/sword2/function.cpp b/sword2/function.cpp index 748de8bec4..51931417b2 100644 --- a/sword2/function.cpp +++ b/sword2/function.cpp @@ -21,19 +21,21 @@ #include "common/stdafx.h" #include "common/file.h" #include "common/system.h" + #include "sword2/sword2.h" #include "sword2/defs.h" +#include "sword2/build_display.h" #include "sword2/console.h" #include "sword2/controls.h" #include "sword2/interpreter.h" #include "sword2/logic.h" #include "sword2/maketext.h" #include "sword2/memory.h" +#include "sword2/mouse.h" #include "sword2/resman.h" #include "sword2/router.h" #include "sword2/sound.h" #include "sword2/driver/animation.h" -#include "sword2/driver/d_draw.h" #include "sword2/driver/render.h" namespace Sword2 { @@ -65,7 +67,8 @@ int32 Logic::fnInitBackground(int32 *params) { // params: 0 res id of normal background layer - cannot be 0 // 1 1 yes 0 no for a new palette - return _vm->initBackground(params[0], params[1]); + _vm->_screen->initBackground(params[0], params[1]); + return IR_CONT; } /** @@ -106,7 +109,9 @@ int32 Logic::fnRegisterMouse(int32 *params) { // params: 0 pointer to ObjectMouse or 0 for no write to mouse // list - _vm->registerMouse((ObjectMouse *) _vm->_memory->decodePtr(params[0])); + ObjectMouse *ob_mouse = (ObjectMouse *) _vm->_memory->decodePtr(params[0]); + + _vm->_mouse->registerMouse(ob_mouse, NULL); return IR_CONT; } @@ -244,15 +249,15 @@ int32 Logic::fnChoose(int32 *params) { for (i = 0; i < _scriptVars[IN_SUBJECT]; i++) { icon = _vm->_resman->openResource(_subjectList[i].res) + sizeof(StandardHeader) + RDMENU_ICONWIDE * RDMENU_ICONDEEP; - _vm->_graphics->setMenuIcon(RDMENU_BOTTOM, i, icon); + _vm->_mouse->setMenuIcon(RDMENU_BOTTOM, i, icon); _vm->_resman->closeResource(_subjectList[i].res); } for (; i < 15; i++) - _vm->_graphics->setMenuIcon(RDMENU_BOTTOM, (uint8) i, NULL); + _vm->_mouse->setMenuIcon(RDMENU_BOTTOM, (uint8) i, NULL); - _vm->_graphics->showMenu(RDMENU_BOTTOM); - _vm->setMouse(NORMAL_MOUSE_ID); + _vm->_mouse->showMenu(RDMENU_BOTTOM); + _vm->_mouse->setMouse(NORMAL_MOUSE_ID); _choosing = true; return IR_REPEAT; } @@ -261,13 +266,16 @@ int32 Logic::fnChoose(int32 *params) { // about left clicks. MouseEvent *me = _vm->mouseEvent(); + int mouseX, mouseY; - if (!me || !(me->buttons & RD_LEFTBUTTONDOWN) || _vm->_mouseY < 400) + _vm->_mouse->getPos(mouseX, mouseY); + + if (!me || !(me->buttons & RD_LEFTBUTTONDOWN) || mouseY < 400) return IR_REPEAT; // Check for click on a menu. - int hit = _vm->menuClick(_scriptVars[IN_SUBJECT]); + int hit = _vm->_mouse->menuClick(_scriptVars[IN_SUBJECT]); if (hit < 0) return IR_REPEAT; @@ -276,7 +284,7 @@ int32 Logic::fnChoose(int32 *params) { for (i = 0; i < _scriptVars[IN_SUBJECT]; i++) { if ((int) i != hit) { icon = _vm->_resman->openResource(_subjectList[i].res) + sizeof(StandardHeader); - _vm->_graphics->setMenuIcon(RDMENU_BOTTOM, i, icon); + _vm->_mouse->setMenuIcon(RDMENU_BOTTOM, i, icon); _vm->_resman->closeResource(_subjectList[i].res); } } @@ -288,7 +296,7 @@ int32 Logic::fnChoose(int32 *params) { _choosing = false; _scriptVars[IN_SUBJECT] = 0; - _vm->setMouse(0); + _vm->_mouse->setMouse(0); return IR_CONT | (_subjectList[hit].ref << 3); } @@ -371,7 +379,7 @@ int32 Logic::fnWalk(int32 *params) { // Walk is about to start, so set the mega's graphic resource ob_graph->anim_resource = ob_mega->megaset_res; - } else if (_scriptVars[EXIT_FADING] && _vm->_graphics->getFadeStatus() == RDFADE_BLACK) { + } else if (_scriptVars[EXIT_FADING] && _vm->_screen->getFadeStatus() == RDFADE_BLACK) { // Double clicked an exit so quit the walk when screen is black // ok, thats it - back to script and change screen @@ -687,8 +695,9 @@ int32 Logic::fnMegaTableAnim(int32 *params) { int32 Logic::fnAddMenuObject(int32 *params) { // params: 0 pointer to a MenuObject structure to copy down + MenuObject *menuObject = (MenuObject *) _vm->_memory->decodePtr(params[0]); - _vm->addMenuObject((MenuObject *) _vm->_memory->decodePtr(params[0])); + _vm->_mouse->addMenuObject(menuObject); return IR_CONT; } @@ -704,12 +713,7 @@ int32 Logic::fnAddMenuObject(int32 *params) { int32 Logic::fnStartConversation(int32 *params) { // params: none - if (_scriptVars[TALK_FLAG] == 0) { - // See fnChooser & speech scripts - _scriptVars[CHOOSER_COUNT_FLAG] = 0; - } - - fnNoHuman(params); + _vm->_mouse->startConversation(); return IR_CONT; } @@ -720,16 +724,7 @@ int32 Logic::fnStartConversation(int32 *params) { int32 Logic::fnEndConversation(int32 *params) { // params: none - _vm->_graphics->hideMenu(RDMENU_BOTTOM); - - if (_vm->_mouseY > 399) { - // Will wait for cursor to move off the bottom menu - _vm->_mouseMode = MOUSE_holding; - } - - // In case DC forgets - _scriptVars[TALK_FLAG] = 0; - + _vm->_mouse->endConversation(); return IR_CONT; } @@ -789,7 +784,12 @@ int32 Logic::fnRegisterFrame(int32 *params) { // 1 pointer to graphic structure // 2 pointer to mega structure or NULL if not a mega - return _vm->registerFrame(params); + ObjectMouse *ob_mouse = (ObjectMouse *) _vm->_memory->decodePtr(params[0]); + ObjectGraphic *ob_graph = (ObjectGraphic *) _vm->_memory->decodePtr(params[1]); + ObjectMega *ob_mega = (ObjectMega *) _vm->_memory->decodePtr(params[2]); + + _vm->_screen->registerFrame(ob_mouse, ob_graph, ob_mega); + return IR_CONT; } int32 Logic::fnNoSprite(int32 *params) { @@ -824,15 +824,16 @@ int32 Logic::fnUpdatePlayerStats(int32 *params) { // params: 0 pointer to mega structure ObjectMega *ob_mega = (ObjectMega *) _vm->_memory->decodePtr(params[0]); + ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); - _vm->_thisScreen.player_feet_x = ob_mega->feet_x; - _vm->_thisScreen.player_feet_y = ob_mega->feet_y; + screenInfo->player_feet_x = ob_mega->feet_x; + screenInfo->player_feet_y = ob_mega->feet_y; // for the script _scriptVars[PLAYER_FEET_X] = ob_mega->feet_x; _scriptVars[PLAYER_FEET_Y] = ob_mega->feet_y; _scriptVars[PLAYER_CUR_DIR] = ob_mega->current_dir; - _scriptVars[SCROLL_OFFSET_X] = _vm->_thisScreen.scroll_offset_x; + _scriptVars[SCROLL_OFFSET_X] = screenInfo->scroll_offset_x; debug(5, "fnUpdatePlayerStats: %d %d", ob_mega->feet_x, ob_mega->feet_y); @@ -856,13 +857,14 @@ int32 Logic::fnInitFloorMouse(int32 *params) { // params: 0 pointer to object's mouse structure ObjectMouse *ob_mouse = (ObjectMouse *) _vm->_memory->decodePtr(params[0]); + ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); // floor is always lowest priority ob_mouse->x1 = 0; ob_mouse->y1 = 0; - ob_mouse->x2 = _vm->_thisScreen.screen_wide - 1; - ob_mouse->y2 = _vm->_thisScreen.screen_deep - 1; + ob_mouse->x2 = screenInfo->screen_wide - 1; + ob_mouse->y2 = screenInfo->screen_deep - 1; ob_mouse->priority = 9; ob_mouse->pointer = NORMAL_MOUSE_ID; return IR_CONT; @@ -939,95 +941,14 @@ int32 Logic::fnEndSession(int32 *params) { int32 Logic::fnNoHuman(int32 *params) { // params: none - _vm->noHuman(); - _vm->clearPointerText(); - - // must be normal mouse situation or a largely neutral situation - - // special menus use noHuman - - // dont hide menu in conversations - if (_scriptVars[TALK_FLAG] == 0) - _vm->_graphics->hideMenu(RDMENU_BOTTOM); - - if (_vm->_mouseMode == MOUSE_system_menu) { - // close menu - _vm->_mouseMode = MOUSE_normal; - _vm->_graphics->hideMenu(RDMENU_TOP); - } - + _vm->_mouse->noHuman(); return IR_CONT; } int32 Logic::fnAddHuman(int32 *params) { // params: none - // for logic scripts - _scriptVars[MOUSE_AVAILABLE] = 1; - - // off - if (_vm->_mouseStatus) { - _vm->_mouseStatus = false; // on - _vm->_mouseTouching = 1; // forces engine to choose a cursor - } - - // clear this to reset no-second-click system - _scriptVars[CLICKED_ID] = 0; - - // this is now done outside the OBJECT_HELD check in case it's set to - // zero before now! - - // unlock the mouse from possible large object lock situtations - see - // syphon in rm 3 - - _vm->_mouseModeLocked = false; - - if (_scriptVars[OBJECT_HELD]) { - // was dragging something around - // need to clear this again - _scriptVars[OBJECT_HELD] = 0; - - // and these may also need clearing, just in case - _vm->_examiningMenuIcon = false; - Logic::_scriptVars[COMBINE_BASE] = 0; - - _vm->setLuggage(0); - } - - // if mouse is over menu area - if (_vm->_mouseY > 399) { - if (_vm->_mouseMode != MOUSE_holding) { - // VITAL - reset things & rebuild the menu - _vm->_mouseMode = MOUSE_normal; - _vm->setMouse(NORMAL_MOUSE_ID); - } else - _vm->setMouse(NORMAL_MOUSE_ID); - } - - // enabled/disabled from console; status printed with on-screen debug - // info - - if (_vm->_debugger->_testingSnR) { - uint8 black[4] = { 0, 0, 0, 0 }; - uint8 white[4] = { 255, 255, 255, 0 }; - - // testing logic scripts by simulating an instant Save & - // Restore - - _vm->_graphics->setPalette(0, 1, white, RDPAL_INSTANT); - - // stops all fx & clears the queue - eg. when leaving a - // location - - _vm->_sound->clearFxQueue(); - - // Trash all object resources so they load in fresh & restart - // their logic scripts - - _vm->_resman->killAllObjects(false); - - _vm->_graphics->setPalette(0, 1, black, RDPAL_INSTANT); - } - + _vm->_mouse->addHuman(); return IR_CONT; } @@ -1265,8 +1186,8 @@ int32 Logic::fnFadeDown(int32 *params) { // params: none - if (_vm->_graphics->getFadeStatus() == RDFADE_NONE) - _vm->_graphics->fadeDown(); + if (_vm->_screen->getFadeStatus() == RDFADE_NONE) + _vm->_screen->fadeDown(); return IR_CONT; } @@ -1562,9 +1483,13 @@ int32 Logic::fnISpeak(int32 *params) { // Ok, all is running along smoothly - but a click means stop // unnaturally + int mouseX, mouseY; + + _vm->_mouse->getPos(mouseX, mouseY); + // So that we can go to the options panel while text & speech is // being tested - if (_scriptVars[SYSTEM_TESTING_TEXT] == 0 || _vm->_mouseY > 0) { + if (_scriptVars[SYSTEM_TESTING_TEXT] == 0 || mouseY > 0) { MouseEvent *me = _vm->mouseEvent(); // Note that we now have TWO click-delays - one for LEFT @@ -2299,8 +2224,10 @@ int32 Logic::fnSetScrollCoordinate(int32 *params) { // feet_x & feet_y refer to the physical screen coords where the // system will try to maintain George's feet - _vm->_thisScreen.feet_x = params[0]; - _vm->_thisScreen.feet_y = params[1]; + ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); + + screenInfo->feet_x = params[0]; + screenInfo->feet_y = params[1]; return IR_CONT; } @@ -2350,16 +2277,17 @@ int32 Logic::fnSetScrollLeftMouse(int32 *params) { // params: 0 pointer to object's mouse structure ObjectMouse *ob_mouse = (ObjectMouse *) _vm->_memory->decodePtr(params[0]); + ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); // Highest priority ob_mouse->x1 = 0; ob_mouse->y1 = 0; - ob_mouse->x2 = _vm->_thisScreen.scroll_offset_x + SCROLL_MOUSE_WIDTH; - ob_mouse->y2 = _vm->_thisScreen.screen_deep - 1; + ob_mouse->x2 = screenInfo->scroll_offset_x + SCROLL_MOUSE_WIDTH; + ob_mouse->y2 = screenInfo->screen_deep - 1; ob_mouse->priority = 0; - if (_vm->_thisScreen.scroll_offset_x > 0) { + if (screenInfo->scroll_offset_x > 0) { // not fully scrolled to the left ob_mouse->pointer = SCROLL_LEFT_MOUSE_ID; } else { @@ -2374,16 +2302,17 @@ int32 Logic::fnSetScrollRightMouse(int32 *params) { // params: 0 pointer to object's mouse structure ObjectMouse *ob_mouse = (ObjectMouse *) _vm->_memory->decodePtr(params[0]); + ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); // Highest priority - ob_mouse->x1 = _vm->_thisScreen.scroll_offset_x + _vm->_graphics->_screenWide - SCROLL_MOUSE_WIDTH; + ob_mouse->x1 = screenInfo->scroll_offset_x + _vm->_screen->getScreenWide() - SCROLL_MOUSE_WIDTH; ob_mouse->y1 = 0; - ob_mouse->x2 = _vm->_thisScreen.screen_wide - 1; - ob_mouse->y2 = _vm->_thisScreen.screen_deep - 1; + ob_mouse->x2 = screenInfo->screen_wide - 1; + ob_mouse->y2 = screenInfo->screen_deep - 1; ob_mouse->priority = 0; - if (_vm->_thisScreen.scroll_offset_x < _vm->_thisScreen.max_scroll_offset_x) { + if (screenInfo->scroll_offset_x < screenInfo->max_scroll_offset_x) { // not fully scrolled to the right ob_mouse->pointer = SCROLL_RIGHT_MOUSE_ID; } else { @@ -2405,19 +2334,19 @@ int32 Logic::fnColour(int32 *params) { // what colour? switch (params[0]) { case BLACK: - _vm->_graphics->setPalette(0, 1, black, RDPAL_INSTANT); + _vm->_screen->setPalette(0, 1, black, RDPAL_INSTANT); break; case WHITE: - _vm->_graphics->setPalette(0, 1, white, RDPAL_INSTANT); + _vm->_screen->setPalette(0, 1, white, RDPAL_INSTANT); break; case RED: - _vm->_graphics->setPalette(0, 1, red, RDPAL_INSTANT); + _vm->_screen->setPalette(0, 1, red, RDPAL_INSTANT); break; case GREEN: - _vm->_graphics->setPalette(0, 1, green, RDPAL_INSTANT); + _vm->_screen->setPalette(0, 1, green, RDPAL_INSTANT); break; case BLUE: - _vm->_graphics->setPalette(0, 1, blue, RDPAL_INSTANT); + _vm->_screen->setPalette(0, 1, blue, RDPAL_INSTANT); break; } #endif @@ -2450,25 +2379,25 @@ int32 Logic::fnFlash(int32 *params) { // what colour? switch (params[0]) { case WHITE: - _vm->_graphics->setPalette(0, 1, white, RDPAL_INSTANT); + _vm->_screen->setPalette(0, 1, white, RDPAL_INSTANT); break; case RED: - _vm->_graphics->setPalette(0, 1, red, RDPAL_INSTANT); + _vm->_screen->setPalette(0, 1, red, RDPAL_INSTANT); break; case GREEN: - _vm->_graphics->setPalette(0, 1, green, RDPAL_INSTANT); + _vm->_screen->setPalette(0, 1, green, RDPAL_INSTANT); break; case BLUE: - _vm->_graphics->setPalette(0, 1, blue, RDPAL_INSTANT); + _vm->_screen->setPalette(0, 1, blue, RDPAL_INSTANT); break; } // There used to be a busy-wait loop here, so I don't know how long // the delay was meant to be. Probably doesn't matter much. - _vm->_graphics->updateDisplay(); + _vm->_screen->updateDisplay(); _vm->_system->delayMillis(250); - _vm->_graphics->setPalette(0, 1, black, RDPAL_INSTANT); + _vm->_screen->setPalette(0, 1, black, RDPAL_INSTANT); #endif return IR_CONT; @@ -2736,14 +2665,14 @@ int32 Logic::fnPlaySequence(int32 *params) { // now clear the screen in case the Sequence was quitted (using ESC) // rather than fading down to black - _vm->_graphics->clearScene(); + _vm->_screen->clearScene(); // zero the entire palette in case we're about to fade up! byte pal[4 * 256]; memset(pal, 0, sizeof(pal)); - _vm->_graphics->setPalette(0, 256, pal, RDPAL_INSTANT); + _vm->_screen->setPalette(0, 256, pal, RDPAL_INSTANT); debug(5, "fnPlaySequence FINISHED"); return IR_CONT; @@ -2764,10 +2693,10 @@ int32 Logic::fnUnshadedSprite(int32 *params) { int32 Logic::fnFadeUp(int32 *params) { // params: none - _vm->_graphics->waitForFade(); + _vm->_screen->waitForFade(); - if (_vm->_graphics->getFadeStatus() == RDFADE_BLACK) - _vm->_graphics->fadeUp(); + if (_vm->_screen->getFadeStatus() == RDFADE_BLACK) + _vm->_screen->fadeUp(); return IR_CONT; } @@ -2785,7 +2714,7 @@ int32 Logic::fnDisplayMsg(int32 *params) { // +2 to skip the encoded text number in the first 2 chars; 3 is // duration in seconds - _vm->displayMsg(_vm->fetchTextLine(_vm->_resman->openResource(text_res), local_text) + 2, 3); + _vm->_screen->displayMsg(_vm->fetchTextLine(_vm->_resman->openResource(text_res), local_text) + 2, 3); _vm->_resman->closeResource(text_res); return IR_CONT; @@ -2793,14 +2722,9 @@ int32 Logic::fnDisplayMsg(int32 *params) { int32 Logic::fnSetObjectHeld(int32 *params) { // params: 0 luggage icon to set + uint32 res = (uint32) params[0]; - _vm->setLuggage(params[0]); - - _scriptVars[OBJECT_HELD] = params[0]; - _vm->_currentLuggageResource = params[0]; - - // mode locked - no menu available - _vm->_mouseModeLocked = true; + _vm->_mouse->setObjectHeld(res); return IR_CONT; } @@ -2824,6 +2748,8 @@ int32 Logic::fnResetGlobals(int32 *params) { // params: none + ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); + int32 size; uint32 *globals; @@ -2846,7 +2772,7 @@ int32 Logic::fnResetGlobals(int32 *params) { // - this is taken from fnInitBackground // switch on scrolling (2 means first time on screen) - _vm->_thisScreen.scroll_flag = 2; + screenInfo->scroll_flag = 2; return IR_CONT; } @@ -2855,7 +2781,7 @@ int32 Logic::fnSetPalette(int32 *params) { // params: 0 resource number of palette file, or 0 if it's to be // the palette from the current screen - _vm->setFullPalette(params[0]); + _vm->_screen->setFullPalette(params[0]); return IR_CONT; } @@ -2866,13 +2792,7 @@ int32 Logic::fnSetPalette(int32 *params) { int32 Logic::fnRegisterPointerText(int32 *params) { // params: 0 local id of text line to use as pointer text - assert(_vm->_curMouse < TOTAL_mouse_list); - - // current object id - used for checking pointer_text when mouse area - // registered (in fnRegisterMouse and fnRegisterFrame) - - _vm->_mouseList[_vm->_curMouse].id = _scriptVars[ID]; - _vm->_mouseList[_vm->_curMouse].pointer_text = params[0]; + _vm->_mouse->registerPointerText(params[0]); return IR_CONT; } @@ -2940,18 +2860,9 @@ int32 Logic::fnCheckPlayerActivity(int32 *params) { // params: 0 threshold delay in seconds, ie. what we want to // check the actual delay against - uint32 threshold = params[0] * 12; // in game cycles - - // if the actual delay is at or above the given threshold - if (_vm->_playerActivityDelay >= threshold) { - // reset activity delay counter, now that we've got a - // positive check - - _vm->_playerActivityDelay = 0; - _scriptVars[RESULT] = 1; - } else - _scriptVars[RESULT] = 0; + uint32 seconds = (uint32) params[0]; + _vm->_mouse->checkPlayerActivity(seconds); return IR_CONT; } @@ -2961,7 +2872,7 @@ int32 Logic::fnResetPlayerActivityDelay(int32 *params) { // params: none - _vm->_playerActivityDelay = 0; + _vm->_mouse->resetPlayerActivityDelay(); return IR_CONT; } @@ -3005,6 +2916,7 @@ struct CreditsLine { #define CREDITS_LINE_SPACING 20 int32 Logic::fnPlayCredits(int32 *params) { + ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); uint32 loopingMusicId = _vm->_sound->getLoopingMusicId(); // This function just quits the game if this is the playable demo, ie. @@ -3019,16 +2931,16 @@ int32 Logic::fnPlayCredits(int32 *params) { // Prepare for the credits by fading down, stoping the music, etc. - _vm->setMouse(0); + _vm->_mouse->setMouse(0); _vm->_sound->muteFx(true); _vm->_sound->muteSpeech(true); - _vm->_graphics->waitForFade(); - _vm->_graphics->fadeDown(); - _vm->_graphics->waitForFade(); + _vm->_screen->waitForFade(); + _vm->_screen->fadeDown(); + _vm->_screen->waitForFade(); - _vm->_graphics->closeMenuImmediately(); + _vm->_mouse->closeMenuImmediately(); // There are three files which I believe are involved in showing the // credits: @@ -3093,7 +3005,7 @@ int32 Logic::fnPlayCredits(int32 *params) { palette[14 * 4 + 3] = 0; } - _vm->_graphics->setPalette(0, 256, palette, RDPAL_INSTANT); + _vm->_screen->setPalette(0, 256, palette, RDPAL_INSTANT); // Read the credits text @@ -3206,8 +3118,8 @@ int32 Logic::fnPlayCredits(int32 *params) { pars[1] = FX_SPOT; fnPlayMusic(pars); - _vm->_graphics->clearScene(); - _vm->_graphics->fadeUp(0); + _vm->_screen->clearScene(); + _vm->_screen->fadeUp(0); spriteInfo.scale = 0; spriteInfo.scaledWidth = 0; @@ -3232,7 +3144,7 @@ int32 Logic::fnPlayCredits(int32 *params) { while (scrollPos < scrollSteps && !_vm->_quit) { bool foundStartLine = false; - _vm->_graphics->clearScene(); + _vm->_screen->clearScene(); for (i = startLine; i < lineCount; i++) { // Free any sprites that have scrolled off the screen @@ -3284,23 +3196,23 @@ int32 Logic::fnPlayCredits(int32 *params) { } if (spriteInfo.data) - _vm->_graphics->drawSprite(&spriteInfo); + _vm->_screen->drawSprite(&spriteInfo); } else break; } - _vm->_graphics->updateDisplay(); + _vm->_screen->updateDisplay(); KeyboardEvent *ke = _vm->keyboardEvent(); if (ke && ke->keycode == 27) { if (!abortCredits) { abortCredits = true; - _vm->_graphics->fadeDown(); + _vm->_screen->fadeDown(); } } - if (abortCredits && _vm->_graphics->getFadeStatus() == RDFADE_BLACK) + if (abortCredits && _vm->_screen->getFadeStatus() == RDFADE_BLACK) break; _vm->sleepUntil(musicStart + (musicLength * scrollPos) / scrollSteps); @@ -3325,7 +3237,7 @@ int32 Logic::fnPlayCredits(int32 *params) { // wait for it to really happen. while (_vm->_sound->musicTimeRemaining() && !_vm->_quit) { - _vm->_graphics->updateDisplay(false); + _vm->_screen->updateDisplay(false); _vm->_system->delayMillis(100); } } @@ -3343,13 +3255,13 @@ int32 Logic::fnPlayCredits(int32 *params) { } else fnStopMusic(NULL); - _vm->_thisScreen.new_palette = 99; + screenInfo->new_palette = 99; - if (!_vm->_mouseStatus || _choosing) - _vm->setMouse(NORMAL_MOUSE_ID); + if (!_vm->_mouse->getMouseStatus() || _choosing) + _vm->_mouse->setMouse(NORMAL_MOUSE_ID); if (_scriptVars[DEAD]) - _vm->buildSystemMenu(); + _vm->_mouse->buildSystemMenu(); return IR_CONT; } @@ -3357,24 +3269,24 @@ int32 Logic::fnPlayCredits(int32 *params) { int32 Logic::fnSetScrollSpeedNormal(int32 *params) { // params: none - _vm->_scrollFraction = 16; + _vm->_screen->setScrollFraction(16); return IR_CONT; } int32 Logic::fnSetScrollSpeedSlow(int32 *params) { // params: none - _vm->_scrollFraction = 32; + _vm->_screen->setScrollFraction(32); return IR_CONT; } -// called from speech scripts to remove the chooser bar when it's not +// Called from speech scripts to remove the chooser bar when it's not // appropriate to keep it displayed int32 Logic::fnRemoveChooser(int32 *params) { // params: none - _vm->_graphics->hideMenu(RDMENU_BOTTOM); + _vm->_mouse->hideMenu(RDMENU_BOTTOM); return IR_CONT; } @@ -3413,34 +3325,27 @@ int32 Logic::fnRestoreGame(int32 *params) { } int32 Logic::fnRefreshInventory(int32 *params) { - // called from 'menu_look_or_combine' script in 'menu_master' object + // Called from 'menu_look_or_combine' script in 'menu_master' object // to update the menu to display a combined object while George runs // voice-over. Note that 'object_held' must be set to the graphic of // the combined object // params: none - // can reset this now - _scriptVars[COMBINE_BASE] = 0; - - // so that the icon in 'object_held' is coloured while the rest are - // grey - _vm->_examiningMenuIcon = true; - _vm->buildMenu(); - _vm->_examiningMenuIcon = false; - + _vm->_mouse->refreshInventory(); return IR_CONT; } int32 Logic::fnChangeShadows(int32 *params) { // params: none + ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); // if last screen was using a shading mask (see below) - if (_vm->_thisScreen.mask_flag) { - uint32 rv = _vm->_graphics->closeLightMask(); + if (screenInfo->mask_flag) { + uint32 rv = _vm->_screen->closeLightMask(); if (rv) error("Driver Error %.8x", rv); - _vm->_thisScreen.mask_flag = false; + screenInfo->mask_flag = false; } return IR_CONT; diff --git a/sword2/icons.cpp b/sword2/icons.cpp index 7146743d8a..1182f0e220 100644 --- a/sword2/icons.cpp +++ b/sword2/icons.cpp @@ -24,12 +24,12 @@ #include "sword2/interpreter.h" #include "sword2/logic.h" #include "sword2/memory.h" +#include "sword2/mouse.h" #include "sword2/resman.h" -#include "sword2/driver/d_draw.h" namespace Sword2 { -void Sword2Engine::addMenuObject(MenuObject *obj) { +void Mouse::addMenuObject(MenuObject *obj) { assert(_totalTemp < TOTAL_engine_pockets); memcpy(&_tempList[_totalTemp], obj, sizeof(MenuObject)); _totalTemp++; @@ -39,7 +39,7 @@ void Sword2Engine::addMenuObject(MenuObject *obj) { * Create and start the inventory (bottom) menu */ -void Sword2Engine::buildMenu(void) { +void Mouse::buildMenu() { uint32 i, j; // Clear the temporary inventory list, since we are going to build a @@ -54,9 +54,9 @@ void Sword2Engine::buildMenu(void) { // register all carried menu objects. uint32 null_pc = 0; - char *menuScript = (char *) _resman->openResource(MENU_MASTER_OBJECT); - _logic->runScript(menuScript, menuScript, &null_pc); - _resman->closeResource(MENU_MASTER_OBJECT); + char *menuScript = (char *) _vm->_resman->openResource(MENU_MASTER_OBJECT); + _vm->_logic->runScript(menuScript, menuScript, &null_pc); + _vm->_resman->closeResource(MENU_MASTER_OBJECT); // Create a new master list based on the old master inventory list and // the new temporary inventory list. The purpose of all this is, as @@ -136,7 +136,7 @@ void Sword2Engine::buildMenu(void) { icon_coloured = (res != Logic::_scriptVars[OBJECT_HELD]); } - icon = _resman->openResource(res) + sizeof(StandardHeader); + icon = _vm->_resman->openResource(res) + sizeof(StandardHeader); // The coloured icon is stored directly after the // greyed out one. @@ -145,20 +145,20 @@ void Sword2Engine::buildMenu(void) { icon += (RDMENU_ICONWIDE * RDMENU_ICONDEEP); } - _graphics->setMenuIcon(RDMENU_BOTTOM, i, icon); + setMenuIcon(RDMENU_BOTTOM, i, icon); if (res) - _resman->closeResource(res); + _vm->_resman->closeResource(res); } - _graphics->showMenu(RDMENU_BOTTOM); + showMenu(RDMENU_BOTTOM); } /** * Build a fresh system (top) menu. */ -void Sword2Engine::buildSystemMenu(void) { +void Mouse::buildSystemMenu() { uint32 icon_list[5] = { OPTIONS_ICON, QUIT_ICON, @@ -171,7 +171,7 @@ void Sword2Engine::buildSystemMenu(void) { // rest will grey out. for (int i = 0; i < ARRAYSIZE(icon_list); i++) { - byte *icon = _resman->openResource(icon_list[i]) + sizeof(StandardHeader); + byte *icon = _vm->_resman->openResource(icon_list[i]) + sizeof(StandardHeader); // The only case when an icon is grayed is when the player // is dead. Then SAVE is not available. @@ -179,11 +179,11 @@ void Sword2Engine::buildSystemMenu(void) { if (!Logic::_scriptVars[DEAD] || icon_list[i] != SAVE_ICON) icon += (RDMENU_ICONWIDE * RDMENU_ICONDEEP); - _graphics->setMenuIcon(RDMENU_TOP, i, icon); - _resman->closeResource(icon_list[i]); + setMenuIcon(RDMENU_TOP, i, icon); + _vm->_resman->closeResource(icon_list[i]); } - _graphics->showMenu(RDMENU_TOP); + showMenu(RDMENU_TOP); } } // End of namespace Sword2 diff --git a/sword2/layers.cpp b/sword2/layers.cpp index 86debbd8c3..79b8cd9743 100644 --- a/sword2/layers.cpp +++ b/sword2/layers.cpp @@ -28,11 +28,9 @@ #include "common/stdafx.h" #include "sword2/sword2.h" -#include "sword2/interpreter.h" #include "sword2/logic.h" #include "sword2/resman.h" #include "sword2/sound.h" -#include "sword2/driver/d_draw.h" namespace Sword2 { @@ -42,30 +40,30 @@ namespace Sword2 { * @param new_palette 1 for new palette, otherwise 0 */ -int32 Sword2Engine::initBackground(int32 res, int32 new_palette) { +void Screen::initBackground(int32 res, int32 new_palette) { byte buf[NAME_LEN]; int i; assert(res); // The resources age every time a new room is entered. - _resman->passTime(); - _resman->expireOldResources(); + _vm->_resman->passTime(); + _vm->_resman->expireOldResources(); - _sound->clearFxQueue(); - _graphics->waitForFade(); + _vm->_sound->clearFxQueue(); + waitForFade(); - debug(1, "CHANGED TO LOCATION \"%s\"", fetchObjectName(res, buf)); + debug(1, "CHANGED TO LOCATION \"%s\"", _vm->fetchObjectName(res, buf)); // if last screen was using a shading mask (see below) if (_thisScreen.mask_flag) { - if (_graphics->closeLightMask() != RD_OK) + if (closeLightMask() != RD_OK) error("Could not close light mask"); } // Close the previous screen, if one is open if (_thisScreen.background_layer_id) - _graphics->closeBackgroundLayer(); + closeBackgroundLayer(); _thisScreen.background_layer_id = res; _thisScreen.new_palette = new_palette; @@ -74,8 +72,8 @@ int32 Sword2Engine::initBackground(int32 res, int32 new_palette) { // info/and set them up at the beginning of the sort list - why do it // each cycle - byte *file = _resman->openResource(_thisScreen.background_layer_id); - ScreenHeader *screen_head = fetchScreenHeader(file); + byte *file = _vm->_resman->openResource(_thisScreen.background_layer_id); + ScreenHeader *screen_head = _vm->fetchScreenHeader(file); // set number of special sort layers _thisScreen.number_of_layers = screen_head->noLayers; @@ -85,12 +83,12 @@ int32 Sword2Engine::initBackground(int32 res, int32 new_palette) { debug(2, "layers=%d width=%d depth=%d", screen_head->noLayers, screen_head->width, screen_head->height); // initialise the driver back buffer - _graphics->setLocationMetrics(screen_head->width, screen_head->height); + setLocationMetrics(screen_head->width, screen_head->height); for (i = 0; i < screen_head->noLayers; i++) { debug(3, "init layer %d", i); - LayerHeader *layer = fetchLayerHeader(file, i); + LayerHeader *layer = _vm->fetchLayerHeader(file, i); // Add the layer to the sort list. We only provide just enough // information so that it's clear that it's a layer, and where @@ -104,7 +102,7 @@ int32 Sword2Engine::initBackground(int32 res, int32 new_palette) { _thisScreen.scroll_offset_x = 0; _thisScreen.scroll_offset_y = 0; - if (screen_head->width > _graphics->_screenWide || screen_head->height > _graphics->_screenDeep) { + if (screen_head->width > _screenWide || screen_head->height > _screenDeep) { // The layer is larger than the physical screen. Switch on // scrolling. (2 means first time on screen) _thisScreen.scroll_flag = 2; @@ -115,14 +113,14 @@ int32 Sword2Engine::initBackground(int32 res, int32 new_palette) { // Calculate the maximum scroll offsets to prevent scrolling // off the edge. The minimum offsets are both 0. - _thisScreen.max_scroll_offset_x = screen_head->width - _graphics->_screenWide; - _thisScreen.max_scroll_offset_y = screen_head->height - (_graphics->_screenDeep - (RDMENU_MENUDEEP * 2)); + _thisScreen.max_scroll_offset_x = screen_head->width - _screenWide; + _thisScreen.max_scroll_offset_y = screen_head->height - (_screenDeep - (RDMENU_MENUDEEP * 2)); } else { // The later fits on the phyiscal screen. Switch off scrolling. _thisScreen.scroll_flag = 0; } - _graphics->resetRenderEngine(); + resetRenderEngine(); // These are the physical screen coords where the system will try to // maintain George's actual feet coords. @@ -146,10 +144,10 @@ int32 Sword2Engine::initBackground(int32 res, int32 new_palette) { spriteInfo.scaledHeight = 0; spriteInfo.type = 0; spriteInfo.blend = 0; - spriteInfo.data = fetchShadingMask(file); + spriteInfo.data = _vm->fetchShadingMask(file); spriteInfo.colourTable = 0; - if (_graphics->openLightMask(&spriteInfo) != RD_OK) + if (openLightMask(&spriteInfo) != RD_OK) error("Could not open light mask"); // so we know to close it later! (see above) @@ -163,26 +161,25 @@ int32 Sword2Engine::initBackground(int32 res, int32 new_palette) { for (i = 0; i < 2; i++) { if (screenLayerTable->bg_parallax[i]) - _graphics->initialiseBackgroundLayer(fetchBackgroundParallaxLayer(file, i)); + initialiseBackgroundLayer(_vm->fetchBackgroundParallaxLayer(file, i)); else - _graphics->initialiseBackgroundLayer(NULL); + initialiseBackgroundLayer(NULL); } // Normal backround layer - _graphics->initialiseBackgroundLayer(fetchBackgroundLayer(file)); + initialiseBackgroundLayer(_vm->fetchBackgroundLayer(file)); // Foreground parallax layers for (i = 0; i < 2; i++) { if (screenLayerTable->fg_parallax[i]) - _graphics->initialiseBackgroundLayer(fetchForegroundParallaxLayer(file, i)); + initialiseBackgroundLayer(_vm->fetchForegroundParallaxLayer(file, i)); else - _graphics->initialiseBackgroundLayer(NULL); + initialiseBackgroundLayer(NULL); } - _resman->closeResource(_thisScreen.background_layer_id); - return IR_CONT; + _vm->_resman->closeResource(_thisScreen.background_layer_id); } } // End of namespace Sword2 diff --git a/sword2/layers.h b/sword2/layers.h index 58edce52ce..3ffdf668b9 100644 --- a/sword2/layers.h +++ b/sword2/layers.h @@ -23,30 +23,6 @@ namespace Sword2 { -struct ScreenInfo { - uint16 scroll_offset_x; // Position x - uint16 scroll_offset_y; // Position y - uint16 max_scroll_offset_x; // Calc'ed in fnInitBackground - uint16 max_scroll_offset_y; - int16 player_feet_x; // Feet coordinates to use - cant just - int16 player_feet_y; // fetch the player compact anymore - int16 feet_x; // Special offset-to-player position - - int16 feet_y; // tweek as desired - always set in - // screen manager object startup - uint16 screen_wide; // Size of background layer - hence - uint16 screen_deep; // size of back buffer itself (Paul - // actually malloc's it) - uint32 background_layer_id; // Id of the normal background layer - // from the header of the main - // background layer - uint16 number_of_layers; - uint8 new_palette; // Set to non zero to start the - // palette held within layer file - // fading up after a build_display - uint8 scroll_flag; // Scroll mode 0 off 1 on - bool mask_flag; // Using shading mask -}; - } // End of namespace Sword2 #endif diff --git a/sword2/logic.cpp b/sword2/logic.cpp index db739c348f..2472c7f726 100644 --- a/sword2/logic.cpp +++ b/sword2/logic.cpp @@ -35,11 +35,10 @@ namespace Sword2 { Logic::Logic(Sword2Engine *vm) : - _vm(vm), _kills(0), _smackerLeadOut(0), _sequenceTextLines(0), - _speechTime(0), _animId(0), _speechAnimType(0), _leftClickDelay(0), - _rightClickDelay(0), _defaultResponseId(0), _officialTextNumber(0), - _speechTextBlocNo(0), - _choosing(false) { + _vm(vm), _kills(0), _smackerLeadIn(0), _smackerLeadOut(0), + _sequenceTextLines(0), _speechTime(0), _animId(0), _speechAnimType(0), + _leftClickDelay(0), _rightClickDelay(0), _defaultResponseId(0), + _officialTextNumber(0), _speechTextBlocNo(0), _choosing(false) { _scriptVars = NULL; memset(_subjectList, 0, sizeof(_subjectList)); memset(_eventList, 0, sizeof(_eventList)); diff --git a/sword2/logic.h b/sword2/logic.h index f535ac4581..a75d93a4b2 100644 --- a/sword2/logic.h +++ b/sword2/logic.h @@ -27,6 +27,8 @@ namespace Sword2 { +struct MovieTextObject; + #define MAX_events 10 // There won't be many, will there? Probably 2 at most i reckon diff --git a/sword2/maketext.cpp b/sword2/maketext.cpp index 8fec778383..aefccb4d86 100644 --- a/sword2/maketext.cpp +++ b/sword2/maketext.cpp @@ -43,7 +43,6 @@ #include "sword2/logic.h" #include "sword2/maketext.h" #include "sword2/resman.h" -#include "sword2/driver/d_draw.h" namespace Sword2 { @@ -476,7 +475,7 @@ void FontRenderer::printTextBlocs(void) { spriteInfo.data = _blocList[i].text_mem + sizeof(FrameHeader); spriteInfo.colourTable = 0; - uint32 rv = _vm->_graphics->drawSprite(&spriteInfo); + uint32 rv = _vm->_screen->drawSprite(&spriteInfo); if (rv) error("Driver Error %.8x in printTextBlocs", rv); } diff --git a/sword2/mouse.cpp b/sword2/mouse.cpp index c0062ba635..be8953c254 100644 --- a/sword2/mouse.cpp +++ b/sword2/mouse.cpp @@ -27,13 +27,13 @@ #include "sword2/logic.h" #include "sword2/maketext.h" #include "sword2/memory.h" +#include "sword2/mouse.h" #include "sword2/resman.h" #include "sword2/sound.h" -#include "sword2/driver/d_draw.h" namespace Sword2 { -// pointer resource id's +// Pointer resource id's enum { CROSHAIR = 18, @@ -55,19 +55,132 @@ enum { USE = 3100 }; +Mouse::Mouse(Sword2Engine *vm) { + _vm = vm; + + setPos(0, 0); + + _mouseTouching = 0; + _oldMouseTouching = 0; + _menuSelectedPos = 0; + _examiningMenuIcon = false; + _mousePointerRes = 0; + _mouseMode = 0; + _mouseStatus = false; + _mouseModeLocked = false; + _currentLuggageResource = 0; + _oldButton = 0; + _buttonClick = 0; + _pointerTextBlocNo = 0; + _playerActivityDelay = 0; + _realLuggageItem = 0; + + _mouseSprite = NULL; + _mouseAnim = NULL; + _luggageAnim = NULL; + + // For the menus + _totalTemp = 0; + memset(_tempList, 0, sizeof(_tempList)); + + _totalMasters = 0; + memset(_masterMenuList, 0, sizeof(_masterMenuList)); + memset(_mouseList, 0, sizeof(_mouseList)); + + _iconCount = 0; + + for (int i = 0; i < 2; i++) { + for (int j = 0; j < RDMENU_MAXPOCKETS; j++) { + _icons[i][j] = NULL; + _pocketStatus[i][j] = 0; + } + + _menuStatus[i] = RDMENU_HIDDEN; + } +} + +Mouse::~Mouse() { + free(_mouseAnim); + free(_luggageAnim); + for (int i = 0; i < 2; i++) + for (int j = 0; j < RDMENU_MAXPOCKETS; j++) + free(_icons[i][j]); +} + +void Mouse::getPos(int &x, int &y) { + x = _pos.x; + y = _pos.y; +} + +void Mouse::setPos(int x, int y) { + _pos.x = x; + _pos.y = y; +} + /** * Call at beginning of game loop */ -void Sword2Engine::resetMouseList(void) { +void Mouse::resetMouseList() { _curMouse = 1; } +void Mouse::registerMouse(ObjectMouse *ob_mouse, BuildUnit *build_unit) { + if (!ob_mouse->pointer) + return; + + assert(_curMouse < TOTAL_mouse_list); + + if (build_unit) { + _mouseList[_curMouse].x1 = build_unit->x; + _mouseList[_curMouse].y1 = build_unit->y; + _mouseList[_curMouse].x2 = build_unit->x + build_unit->scaled_width; + _mouseList[_curMouse].y2 = build_unit->y + build_unit->scaled_height; + } else { + _mouseList[_curMouse].x1 = ob_mouse->x1; + _mouseList[_curMouse].y1 = ob_mouse->y1; + _mouseList[_curMouse].x2 = ob_mouse->x2; + _mouseList[_curMouse].y2 = ob_mouse->y2; + } + + _mouseList[_curMouse].priority = ob_mouse->priority; + _mouseList[_curMouse].pointer = ob_mouse->pointer; + + // Check if pointer text field is set due to previous object using this + // slot (ie. not correct for this one) + + // If 'pointer_text' field is set, but the 'id' field isn't same is + // current id then we don't want this "left over" pointer text + + if (_mouseList[_curMouse].pointer_text && _mouseList[_curMouse].id != (int32) Logic::_scriptVars[ID]) + _mouseList[_curMouse].pointer_text = 0; + + // Get id from system variable 'id' which is correct for current object + _mouseList[_curMouse].id = Logic::_scriptVars[ID]; + + // Not using sprite as detection mask - this is only done from + // fnRegisterFrame() + _mouseList[_curMouse].anim_resource = 0; + _mouseList[_curMouse].anim_pc = 0; + + _curMouse++; +} + +void Mouse::registerPointerText(int32 text_id) { + assert(_curMouse < TOTAL_mouse_list); + + // current object id - used for checking pointer_text when mouse area + // registered (in fnRegisterMouse and fnRegisterFrame) + + _mouseList[_curMouse].id = Logic::_scriptVars[ID]; + _mouseList[_curMouse].pointer_text = text_id; +} + /** * This function is called every game cycle. */ -void Sword2Engine::mouseEngine(void) { +void Mouse::mouseEngine() { monitorPlayerActivity(); clearPointerText(); @@ -109,7 +222,7 @@ void Sword2Engine::mouseEngine(void) { systemMenuMouse(); break; case MOUSE_holding: - if (_mouseY < 400) { + if (_pos.y < 400) { _mouseMode = MOUSE_normal; debug(5, " releasing"); } @@ -120,7 +233,7 @@ void Sword2Engine::mouseEngine(void) { } #if RIGHT_CLICK_CLEARS_LUGGAGE -bool Sword2Engine::heldIsInInventory(void) { +bool Mouse::heldIsInInventory() { for (uint i = 0; i < _totalMasters; i++) { if ((uint32) _masterMenuList[i].icon_resource == Logic::_scriptVars[OBJECT_HELD]) return true; @@ -129,17 +242,17 @@ bool Sword2Engine::heldIsInInventory(void) { } #endif -int Sword2Engine::menuClick(int menu_items) { - if (_mouseX < RDMENU_ICONSTART) +int Mouse::menuClick(int menu_items) { + if (_pos.x < RDMENU_ICONSTART) return -1; - if (_mouseX > RDMENU_ICONSTART + menu_items * (RDMENU_ICONWIDE + RDMENU_ICONSPACING) - RDMENU_ICONSPACING) + if (_pos.x > RDMENU_ICONSTART + menu_items * (RDMENU_ICONWIDE + RDMENU_ICONSPACING) - RDMENU_ICONSPACING) return -1; - return (_mouseX - RDMENU_ICONSTART) / (RDMENU_ICONWIDE + RDMENU_ICONSPACING); + return (_pos.x - RDMENU_ICONSTART) / (RDMENU_ICONWIDE + RDMENU_ICONSPACING); } -void Sword2Engine::systemMenuMouse(void) { +void Mouse::systemMenuMouse(void) { uint32 safe_looping_music_id; MouseEvent *me; int hit; @@ -156,20 +269,20 @@ void Sword2Engine::systemMenuMouse(void) { // If the mouse is moved off the menu, close it. Unless the player is // dead, in which case the menu should always be visible. - if (_mouseY > 0 && !Logic::_scriptVars[DEAD]) { + if (_pos.y > 0 && !Logic::_scriptVars[DEAD]) { _mouseMode = MOUSE_normal; - _graphics->hideMenu(RDMENU_TOP); + hideMenu(RDMENU_TOP); return; } // Check if the user left-clicks anywhere in the menu area. - me = mouseEvent(); + me = _vm->mouseEvent(); if (!me || !(me->buttons & RD_LEFTBUTTONDOWN)) return; - if (_mouseY > 0) + if (_pos.y > 0) return; hit = menuClick(ARRAYSIZE(icon_list)); @@ -186,46 +299,46 @@ void Sword2Engine::systemMenuMouse(void) { for (int i = 0; i < ARRAYSIZE(icon_list); i++) { if (i != hit) { - icon = _resman->openResource(icon_list[i]) + sizeof(StandardHeader); - _graphics->setMenuIcon(RDMENU_TOP, i, icon); - _resman->closeResource(icon_list[i]); + icon = _vm->_resman->openResource(icon_list[i]) + sizeof(StandardHeader); + setMenuIcon(RDMENU_TOP, i, icon); + _vm->_resman->closeResource(icon_list[i]); } } - _sound->pauseFx(); + _vm->_sound->pauseFx(); // NB. Need to keep a safe copy of '_loopingMusicId' for savegame & for // playing when returning from control panels because control panel // music will overwrite it! - safe_looping_music_id = _sound->getLoopingMusicId(); + safe_looping_music_id = _vm->_sound->getLoopingMusicId(); pars[0] = 221; pars[1] = FX_LOOP; - _logic->fnPlayMusic(pars); + _vm->_logic->fnPlayMusic(pars); // HACK: Restore proper looping_music_id - _sound->setLoopingMusicId(safe_looping_music_id); + _vm->_sound->setLoopingMusicId(safe_looping_music_id); - _graphics->processMenu(); + processMenu(); // call the relevant screen switch (hit) { case 0: - _gui->optionControl(); + _vm->_gui->optionControl(); break; case 1: - _gui->quitControl(); + _vm->_gui->quitControl(); break; case 2: - _gui->saveControl(); + _vm->_gui->saveControl(); break; case 3: - _gui->restoreControl(); + _vm->_gui->restoreControl(); break; case 4: - _gui->restartControl(); + _vm->_gui->restartControl(); break; } @@ -233,7 +346,7 @@ void Sword2Engine::systemMenuMouse(void) { if (!Logic::_scriptVars[DEAD]) { _mouseMode = MOUSE_normal; - _graphics->hideMenu(RDMENU_TOP); + hideMenu(RDMENU_TOP); } else { setMouse(NORMAL_MOUSE_ID); buildSystemMenu(); @@ -241,35 +354,37 @@ void Sword2Engine::systemMenuMouse(void) { // Back to the game again - _graphics->processMenu(); + processMenu(); // Reset game palette, but not after a successful restore or restart! // See RestoreFromBuffer() in save_rest.cpp - if (_thisScreen.new_palette != 99) { + ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); + + if (screenInfo->new_palette != 99) { // 0 means put back game screen palette; see build_display.cpp - setFullPalette(0); + _vm->_screen->setFullPalette(0); // Stop the engine fading in the restored screens palette - _thisScreen.new_palette = 0; + screenInfo->new_palette = 0; } else - _thisScreen.new_palette = 1; + screenInfo->new_palette = 1; - _sound->unpauseFx(); + _vm->_sound->unpauseFx(); // If there was looping music before coming into the control panels // then restart it! NB. If a game has been restored the music will be // restarted twice, but this shouldn't cause any harm. - if (_sound->getLoopingMusicId()) { - pars[0] = _sound->getLoopingMusicId(); + if (_vm->_sound->getLoopingMusicId()) { + pars[0] = _vm->_sound->getLoopingMusicId(); pars[1] = FX_LOOP; - _logic->fnPlayMusic(pars); + _vm->_logic->fnPlayMusic(pars); } else - _logic->fnStopMusic(NULL); + _vm->_logic->fnStopMusic(NULL); } -void Sword2Engine::dragMouse(void) { +void Mouse::dragMouse(void) { byte buf1[NAME_LEN], buf2[NAME_LEN]; MouseEvent *me; int hit; @@ -278,9 +393,9 @@ void Sword2Engine::dragMouse(void) { // objects in the scene, so if the mouse moves off the inventory menu, // then close it. - if (_mouseY < 400) { + if (_pos.y < 400) { _mouseMode = MOUSE_normal; - _graphics->hideMenu(RDMENU_BOTTOM); + hideMenu(RDMENU_BOTTOM); return; } @@ -290,7 +405,7 @@ void Sword2Engine::dragMouse(void) { // Now do the normal click stuff - me = mouseEvent(); + me = _vm->mouseEvent(); if (!me) return; @@ -327,24 +442,25 @@ void Sword2Engine::dragMouse(void) { Logic::_scriptVars[RIGHT_BUTTON] = 0; // These might be required by the action script about to be run + ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); - Logic::_scriptVars[MOUSE_X] = _mouseX + _thisScreen.scroll_offset_x; - Logic::_scriptVars[MOUSE_Y] = _mouseY + _thisScreen.scroll_offset_y; + Logic::_scriptVars[MOUSE_X] = _pos.x + screenInfo->scroll_offset_x; + Logic::_scriptVars[MOUSE_Y] = _pos.y + screenInfo->scroll_offset_y; // For scripts to know what's been clicked. First used for // 'room_13_turning_script' in object 'biscuits_13' Logic::_scriptVars[CLICKED_ID] = _mouseTouching; - _logic->setPlayerActionEvent(CUR_PLAYER_ID, _mouseTouching); + _vm->_logic->setPlayerActionEvent(CUR_PLAYER_ID, _mouseTouching); debug(2, "Used \"%s\" on \"%s\"", - fetchObjectName(Logic::_scriptVars[OBJECT_HELD], buf1), - fetchObjectName(Logic::_scriptVars[CLICKED_ID], buf2)); + _vm->fetchObjectName(Logic::_scriptVars[OBJECT_HELD], buf1), + _vm->fetchObjectName(Logic::_scriptVars[CLICKED_ID], buf2)); // Hide menu - back to normal menu mode - _graphics->hideMenu(RDMENU_BOTTOM); + hideMenu(RDMENU_BOTTOM); _mouseMode = MOUSE_normal; return; @@ -372,16 +488,16 @@ void Sword2Engine::dragMouse(void) { // Otherwise, combine the two icons Logic::_scriptVars[COMBINE_BASE] = _masterMenuList[hit].icon_resource; - _logic->setPlayerActionEvent(CUR_PLAYER_ID, MENU_MASTER_OBJECT); + _vm->_logic->setPlayerActionEvent(CUR_PLAYER_ID, MENU_MASTER_OBJECT); // Turn off mouse now, to prevent player trying to click // elsewhere BUT leave the bottom menu open - noHuman(); + hideMouse(); debug(2, "Used \"%s\" on \"%s\"", - fetchObjectName(Logic::_scriptVars[OBJECT_HELD], buf1), - fetchObjectName(Logic::_scriptVars[COMBINE_BASE], buf2)); + _vm->fetchObjectName(Logic::_scriptVars[OBJECT_HELD], buf1), + _vm->fetchObjectName(Logic::_scriptVars[COMBINE_BASE], buf2)); } // Refresh the menu @@ -389,20 +505,20 @@ void Sword2Engine::dragMouse(void) { buildMenu(); } -void Sword2Engine::menuMouse(void) { +void Mouse::menuMouse() { byte buf[NAME_LEN]; MouseEvent *me; int hit; // If the mouse is moved off the menu, close it. - if (_mouseY < 400) { + if (_pos.y < 400) { _mouseMode = MOUSE_normal; - _graphics->hideMenu(RDMENU_BOTTOM); + hideMenu(RDMENU_BOTTOM); return; } - me = mouseEvent(); + me = _vm->mouseEvent(); if (!me) return; @@ -426,7 +542,7 @@ void Sword2Engine::menuMouse(void) { Logic::_scriptVars[EXIT_CLICK_ID] = 0; - _logic->setPlayerActionEvent(CUR_PLAYER_ID, MENU_MASTER_OBJECT); + _vm->_logic->setPlayerActionEvent(CUR_PLAYER_ID, MENU_MASTER_OBJECT); // Refresh the menu @@ -435,10 +551,10 @@ void Sword2Engine::menuMouse(void) { // Turn off mouse now, to prevent player trying to click // elsewhere BUT leave the bottom menu open - noHuman(); + hideMouse(); debug(2, "Right-click on \"%s\" icon", - fetchObjectName(Logic::_scriptVars[OBJECT_HELD], buf)); + _vm->fetchObjectName(Logic::_scriptVars[OBJECT_HELD], buf)); return; } @@ -466,11 +582,11 @@ void Sword2Engine::menuMouse(void) { setLuggage(_masterMenuList[hit].luggage_resource); debug(2, "Left-clicked on \"%s\" icon - switch to drag mode", - fetchObjectName(Logic::_scriptVars[OBJECT_HELD], buf)); + _vm->fetchObjectName(Logic::_scriptVars[OBJECT_HELD], buf)); } } -void Sword2Engine::normalMouse(void) { +void Mouse::normalMouse(void) { // The gane is playing and none of the menus are activated - but, we // need to check if a menu is to start. Note, won't have luggage @@ -480,7 +596,7 @@ void Sword2Engine::normalMouse(void) { // big-object menu lock situation, of if the player is dragging an // object. - if (_mouseY < 0 && !_mouseModeLocked && !Logic::_scriptVars[OBJECT_HELD]) { + if (_pos.y < 0 && !_mouseModeLocked && !Logic::_scriptVars[OBJECT_HELD]) { _mouseMode = MOUSE_system_menu; if (_mouseTouching) { @@ -499,7 +615,7 @@ void Sword2Engine::normalMouse(void) { // Check if the cursor has moved onto the inventory menu area. No // inventory in big-object menu lock situation, - if (_mouseY > 399 && !_mouseModeLocked) { + if (_pos.y > 399 && !_mouseModeLocked) { // If an object is being held, i.e. if the mouse cursor has a // luggage, go to drag mode instead of menu mode, but the menu // is still opened. @@ -532,7 +648,7 @@ void Sword2Engine::normalMouse(void) { mouseOnOff(); - me = mouseEvent(); + me = _vm->mouseEvent(); if (!me) return; @@ -542,27 +658,29 @@ void Sword2Engine::normalMouse(void) { // For debugging. We can draw a rectangle on the screen and see its // coordinates. This was probably used to help defining hit areas. - if (_debugger->_definingRectangles) { - if (_debugger->_draggingRectangle == 0) { + if (_vm->_debugger->_definingRectangles) { + ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); + + if (_vm->_debugger->_draggingRectangle == 0) { // Not yet dragging a rectangle, so need click to start if (button_down) { // set both (x1,y1) and (x2,y2) to this point - _debugger->_rectX1 = _debugger->_rectX2 = (uint32) _mouseX + _thisScreen.scroll_offset_x; - _debugger->_rectY1 = _debugger->_rectY2 = (uint32) _mouseY + _thisScreen.scroll_offset_y; - _debugger->_draggingRectangle = 1; + _vm->_debugger->_rectX1 = _vm->_debugger->_rectX2 = (uint32) _pos.x + screenInfo->scroll_offset_x; + _vm->_debugger->_rectY1 = _vm->_debugger->_rectY2 = (uint32) _pos.y + screenInfo->scroll_offset_y; + _vm->_debugger->_draggingRectangle = 1; } - } else if (_debugger->_draggingRectangle == 1) { + } else if (_vm->_debugger->_draggingRectangle == 1) { // currently dragging a rectangle - click means reset if (button_down) { // lock rectangle, so you can let go of mouse // to type in the coords - _debugger->_draggingRectangle = 2; + _vm->_debugger->_draggingRectangle = 2; } else { // drag rectangle - _debugger->_rectX2 = (uint32) _mouseX + _thisScreen.scroll_offset_x; - _debugger->_rectY2 = (uint32) _mouseY + _thisScreen.scroll_offset_y; + _vm->_debugger->_rectX2 = (uint32) _pos.x + screenInfo->scroll_offset_x; + _vm->_debugger->_rectY2 = (uint32) _pos.y + screenInfo->scroll_offset_y; } } else { // currently locked to avoid knocking out of place @@ -570,7 +688,7 @@ void Sword2Engine::normalMouse(void) { if (button_down) { // click means reset - back to start again - _debugger->_draggingRectangle = 0; + _vm->_debugger->_draggingRectangle = 0; } } @@ -622,17 +740,18 @@ void Sword2Engine::normalMouse(void) { } // These might be required by the action script about to be run + ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); - Logic::_scriptVars[MOUSE_X] = _mouseX + _thisScreen.scroll_offset_x; - Logic::_scriptVars[MOUSE_Y] = _mouseY + _thisScreen.scroll_offset_y; + Logic::_scriptVars[MOUSE_X] = _pos.x + screenInfo->scroll_offset_x; + Logic::_scriptVars[MOUSE_Y] = _pos.y + screenInfo->scroll_offset_y; if (_mouseTouching == Logic::_scriptVars[EXIT_CLICK_ID] && (me->buttons & RD_LEFTBUTTONDOWN)) { // It's the exit double click situation. Let the existing // interaction continue and start fading down. Switch the human // off too - _logic->fnNoHuman(NULL); - _logic->fnFadeDown(NULL); + noHuman(); + _vm->_logic->fnFadeDown(NULL); // Tell the walker @@ -669,24 +788,24 @@ void Sword2Engine::normalMouse(void) { if (_mouseTouching == 2773 && !Logic::_scriptVars[LEFT_BUTTON]) { warning("Working around elevator script bug"); } else - _logic->setPlayerActionEvent(CUR_PLAYER_ID, _mouseTouching); + _vm->_logic->setPlayerActionEvent(CUR_PLAYER_ID, _mouseTouching); byte buf1[NAME_LEN], buf2[NAME_LEN]; if (Logic::_scriptVars[OBJECT_HELD]) debug(2, "Used \"%s\" on \"%s\"", - fetchObjectName(Logic::_scriptVars[OBJECT_HELD], buf1), - fetchObjectName(Logic::_scriptVars[CLICKED_ID], buf2)); + _vm->fetchObjectName(Logic::_scriptVars[OBJECT_HELD], buf1), + _vm->fetchObjectName(Logic::_scriptVars[CLICKED_ID], buf2)); else if (Logic::_scriptVars[LEFT_BUTTON]) debug(2, "Left-clicked on \"%s\"", - fetchObjectName(Logic::_scriptVars[CLICKED_ID], buf1)); + _vm->fetchObjectName(Logic::_scriptVars[CLICKED_ID], buf1)); else // RIGHT BUTTON debug(2, "Right-clicked on \"%s\"", - fetchObjectName(Logic::_scriptVars[CLICKED_ID], buf1)); + _vm->fetchObjectName(Logic::_scriptVars[CLICKED_ID], buf1)); } } -void Sword2Engine::mouseOnOff(void) { +void Mouse::mouseOnOff() { // this handles the cursor graphic when moving on and off mouse areas // it also handles the luggage thingy @@ -698,7 +817,7 @@ void Sword2Engine::mouseOnOff(void) { // don't detect objects that are hidden behind the menu bars (ie. in // the scrolled-off areas of the screen) - if (_mouseY < 0 || _mouseY > 399) { + if (_pos.y < 0 || _pos.y > 399) { pointer_type = 0; _mouseTouching = 0; } else { @@ -743,7 +862,7 @@ void Sword2Engine::mouseOnOff(void) { } else { byte buf[NAME_LEN]; - error("ERROR: mouse.pointer==0 for object %d (%s) - update logic script!", _mouseTouching, fetchObjectName(_mouseTouching, buf)); + error("ERROR: mouse.pointer==0 for object %d (%s) - update logic script!", _mouseTouching, _vm->fetchObjectName(_mouseTouching, buf)); } } else if (_oldMouseTouching && !_mouseTouching) { // the cursor has moved off something - reset cursor to @@ -783,55 +902,66 @@ void Sword2Engine::mouseOnOff(void) { // screens } -void Sword2Engine::setMouse(uint32 res) { +void Mouse::setMouse(uint32 res) { // high level - whats the mouse - for the engine _mousePointerRes = res; if (res) { - byte *icon = _resman->openResource(res) + sizeof(StandardHeader); - uint32 len = _resman->fetchLen(res) - sizeof(StandardHeader); + byte *icon = _vm->_resman->openResource(res) + sizeof(StandardHeader); + uint32 len = _vm->_resman->fetchLen(res) - sizeof(StandardHeader); // don't pulse the normal pointer - just do the regular anim // loop if (res == NORMAL_MOUSE_ID) - _graphics->setMouseAnim(icon, len, RDMOUSE_NOFLASH); + setMouseAnim(icon, len, RDMOUSE_NOFLASH); else - _graphics->setMouseAnim(icon, len, RDMOUSE_FLASH); + setMouseAnim(icon, len, RDMOUSE_FLASH); - _resman->closeResource(res); + _vm->_resman->closeResource(res); } else { // blank cursor - _graphics->setMouseAnim(NULL, 0, 0); + setMouseAnim(NULL, 0, 0); } } -void Sword2Engine::setLuggage(uint32 res) { +void Mouse::setLuggage(uint32 res) { _realLuggageItem = res; if (res) { - byte *icon = _resman->openResource(res) + sizeof(StandardHeader); - uint32 len = _resman->fetchLen(res) - sizeof(StandardHeader); + byte *icon = _vm->_resman->openResource(res) + sizeof(StandardHeader); + uint32 len = _vm->_resman->fetchLen(res) - sizeof(StandardHeader); - _graphics->setLuggageAnim(icon, len); - _resman->closeResource(res); + setLuggageAnim(icon, len); + _vm->_resman->closeResource(res); } else - _graphics->setLuggageAnim(NULL, 0); + setLuggageAnim(NULL, 0); } -uint32 Sword2Engine::checkMouseList(void) { - // Number of priorities subject to implementation needs +void Mouse::setObjectHeld(uint32 res) { + setLuggage(res); + Logic::_scriptVars[OBJECT_HELD] = res; + _currentLuggageResource = res; + + // mode locked - no menu available + _mouseModeLocked = true; +} + +uint32 Mouse::checkMouseList() { + ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); + + // Number of priorities subject to implementation needs for (int priority = 0; priority < 10; priority++) { for (uint i = 1; i < _curMouse; i++) { // If the mouse pointer is over this // mouse-detection-box if (_mouseList[i].priority == priority && - _mouseX + _thisScreen.scroll_offset_x >= _mouseList[i].x1 && - _mouseX + _thisScreen.scroll_offset_x <= _mouseList[i].x2 && - _mouseY + _thisScreen.scroll_offset_y >= _mouseList[i].y1 && - _mouseY + _thisScreen.scroll_offset_y <= _mouseList[i].y2) { + _pos.x + screenInfo->scroll_offset_x >= _mouseList[i].x1 && + _pos.x + screenInfo->scroll_offset_x <= _mouseList[i].x2 && + _pos.y + screenInfo->scroll_offset_y >= _mouseList[i].y1 && + _pos.y + screenInfo->scroll_offset_y <= _mouseList[i].y2) { // Record id _mouseTouching = _mouseList[i].id; @@ -855,7 +985,7 @@ uint32 Sword2Engine::checkMouseList(void) { #define POINTER_TEXT_WIDTH 640 // just in case! #define POINTER_TEXT_PEN 184 // white -void Sword2Engine::createPointerText(uint32 text_id, uint32 pointer_res) { +void Mouse::createPointerText(uint32 text_id, uint32 pointer_res) { uint32 local_text; uint32 text_res; byte *text; @@ -863,7 +993,7 @@ void Sword2Engine::createPointerText(uint32 text_id, uint32 pointer_res) { int16 xOffset, yOffset; uint8 justification; - if (!_gui->_pointerTextSelected || !text_id) + if (!_vm->_gui->_pointerTextSelected || !text_id) return; // Check what the pointer is, to set offsets correctly for text @@ -993,30 +1123,30 @@ void Sword2Engine::createPointerText(uint32 text_id, uint32 pointer_res) { local_text = text_id & 0xffff; // open text file & get the line - text = fetchTextLine(_resman->openResource(text_res), local_text); + text = _vm->fetchTextLine(_vm->_resman->openResource(text_res), local_text); // 'text+2' to skip the first 2 bytes which form the // line reference number - _pointerTextBlocNo = _fontRenderer->buildNewBloc( - text + 2, _mouseX + xOffset, - _mouseY + yOffset, + _pointerTextBlocNo = _vm->_fontRenderer->buildNewBloc( + text + 2, _pos.x + xOffset, + _pos.y + yOffset, POINTER_TEXT_WIDTH, POINTER_TEXT_PEN, RDSPR_TRANS | RDSPR_DISPLAYALIGN, - _speechFontId, justification); + _vm->_speechFontId, justification); // now ok to close the text file - _resman->closeResource(text_res); + _vm->_resman->closeResource(text_res); } -void Sword2Engine::clearPointerText(void) { +void Mouse::clearPointerText() { if (_pointerTextBlocNo) { - _fontRenderer->killTextBloc(_pointerTextBlocNo); + _vm->_fontRenderer->killTextBloc(_pointerTextBlocNo); _pointerTextBlocNo = 0; } } -void Sword2Engine::noHuman(void) { +void Mouse::hideMouse() { // leaves the menus open // used by the system when clicking right on a menu item to examine // it and when combining objects @@ -1031,47 +1161,122 @@ void Sword2Engine::noHuman(void) { setLuggage(0); } -void Sword2Engine::registerMouse(ObjectMouse *ob_mouse) { - debug(5, "_curMouse = %d", _curMouse); +void Mouse::noHuman() { + hideMouse(); + clearPointerText(); - if (!ob_mouse->pointer) - return; + // Must be normal mouse situation or a largely neutral situation - + // special menus use hideMouse() - assert(_curMouse < TOTAL_mouse_list); + // Don't hide menu in conversations + if (Logic::_scriptVars[TALK_FLAG] == 0) + hideMenu(RDMENU_BOTTOM); - _mouseList[_curMouse].x1 = ob_mouse->x1; - _mouseList[_curMouse].y1 = ob_mouse->y1; - _mouseList[_curMouse].x2 = ob_mouse->x2; - _mouseList[_curMouse].y2 = ob_mouse->y2; + if (_mouseMode == MOUSE_system_menu) { + // Close menu + _mouseMode = MOUSE_normal; + hideMenu(RDMENU_TOP); + } +} - _mouseList[_curMouse].priority = ob_mouse->priority; - _mouseList[_curMouse].pointer = ob_mouse->pointer; +void Mouse::addHuman() { + // For logic scripts + Logic::_scriptVars[MOUSE_AVAILABLE] = 1; - // Check if pointer text field is set due to previous object using this - // slot (ie. not correct for this one) + if (_mouseStatus) { + // Force engine to choose a cursor + _mouseStatus = false; + _mouseTouching = 1; + } - // If 'pointer_text' field is set, but the 'id' field isn't same is - // current id, then we don't want this "left over" pointer text + // Clear this to reset no-second-click system + Logic::_scriptVars[CLICKED_ID] = 0; - if (_mouseList[_curMouse].pointer_text && _mouseList[_curMouse].id != (int32) Logic::_scriptVars[ID]) - _mouseList[_curMouse].pointer_text = 0; + // This is now done outside the OBJECT_HELD check in case it's set to + // zero before now! - // Get id from system variable 'id' which is correct for current object + // Unlock the mouse from possible large object lock situtations - see + // syphon in rm 3 - _mouseList[_curMouse].id = Logic::_scriptVars[ID]; + _mouseModeLocked = false; - // Not using sprite as mask - this is only done from fnRegisterFrame() + if (Logic::_scriptVars[OBJECT_HELD]) { + // Was dragging something around - need to clear this again + Logic::_scriptVars[OBJECT_HELD] = 0; - _mouseList[_curMouse].anim_resource = 0; - _mouseList[_curMouse].anim_pc = 0; + // And these may also need clearing, just in case + _examiningMenuIcon = false; + Logic::_scriptVars[COMBINE_BASE] = 0; - debug(5, "mouse id %d", _mouseList[_curMouse].id); - _curMouse++; + setLuggage(0); + } + + // If mouse is over menu area + if (_pos.y > 399) { + if (_mouseMode != MOUSE_holding) { + // VITAL - reset things & rebuild the menu + _mouseMode = MOUSE_normal; + } + setMouse(NORMAL_MOUSE_ID); + } + + // Enabled/disabled from console; status printed with on-screen debug + // info + + if (_vm->_debugger->_testingSnR) { + uint8 black[4] = { 0, 0, 0, 0 }; + uint8 white[4] = { 255, 255, 255, 0 }; + + // Testing logic scripts by simulating instant Save & Restore + + _vm->_screen->setPalette(0, 1, white, RDPAL_INSTANT); + + // Stops all fx & clears the queue - eg. when leaving a room + _vm->_sound->clearFxQueue(); + + // Trash all object resources so they load in fresh & restart + // their logic scripts + + _vm->_resman->killAllObjects(false); + + _vm->_screen->setPalette(0, 1, black, RDPAL_INSTANT); + } +} + +void Mouse::refreshInventory() { + // Can reset this now + Logic::_scriptVars[COMBINE_BASE] = 0; + + // Cause 'object_held' icon to be greyed. The rest are coloured. + _examiningMenuIcon = true; + buildMenu(); + _examiningMenuIcon = false; +} + +void Mouse::startConversation() { + if (Logic::_scriptVars[TALK_FLAG] == 0) { + // See fnChooser & speech scripts + Logic::_scriptVars[CHOOSER_COUNT_FLAG] = 0; + } + + noHuman(); +} + +void Mouse::endConversation() { + hideMenu(RDMENU_BOTTOM); + + if (_pos.y > 399) { + // Will wait for cursor to move off the bottom menu + _mouseMode = MOUSE_holding; + } + + // In case DC forgets + Logic::_scriptVars[TALK_FLAG] = 0; } -void Sword2Engine::monitorPlayerActivity(void) { +void Mouse::monitorPlayerActivity() { // if there is at least one mouse event outstanding - if (checkForMouseEvents()) { + if (_vm->checkForMouseEvents()) { // reset activity delay counter _playerActivityDelay = 0; } else { @@ -1080,4 +1285,33 @@ void Sword2Engine::monitorPlayerActivity(void) { } } +void Mouse::checkPlayerActivity(uint32 seconds) { + // Convert seconds to game cycles + uint32 threshold = seconds * 12; + + // If the actual delay is at or above the given threshold, reset the + // activity delay counter now that we've got a positive check. + + if (_playerActivityDelay >= threshold) { + _playerActivityDelay = 0; + Logic::_scriptVars[RESULT] = 1; + } else + Logic::_scriptVars[RESULT] = 0; +} + +void Mouse::pauseGame() { + // Make the mouse cursor normal. This is the only place where we are + // allowed to clear the luggage this way. + + clearPointerText(); + setLuggageAnim(NULL, 0); + setMouse(0); + setMouseTouching(1); +} + +void Mouse::unpauseGame() { + if (Logic::_scriptVars[OBJECT_HELD] && _realLuggageItem) + setLuggage(_realLuggageItem); +} + } // End of namespace Sword2 diff --git a/sword2/mouse.h b/sword2/mouse.h index be39df6c44..e304db086b 100644 --- a/sword2/mouse.h +++ b/sword2/mouse.h @@ -21,17 +21,30 @@ #ifndef MOUSE_H #define MOUSE_H -#define TOTAL_mouse_list 50 +#define TOTAL_mouse_list 50 namespace Sword2 { -enum { - MOUSE_normal = 0, // normal in game - MOUSE_menu = 1, // menu chooser - MOUSE_drag = 2, // dragging luggage - MOUSE_system_menu = 3, // system menu chooser - MOUSE_holding = 4 // special -}; +struct ObjectMouse; +struct BuildUnit; + +#if !defined(__GNUC__) + #pragma START_PACK_STRUCTS +#endif + +struct MouseAnim { + uint8 runTimeComp; // type of runtime compression used for the + // frame data + uint8 noAnimFrames; // number of frames in the anim + int8 xHotSpot; + int8 yHotSpot; + uint8 mousew; + uint8 mouseh; +} GCC_PACK; + +#if !defined(__GNUC__) + #pragma END_PACK_STRUCTS +#endif // The MOUSE_holding mode is entered when the conversation menu is closed, and // exited when the mouse cursor moves off that menu area. I don't know why yet. @@ -68,6 +81,136 @@ struct MouseUnit { int32 pointer_text; }; +class Mouse { +private: + Sword2Engine *_vm; + + Common::Point _pos; + + MouseUnit _mouseList[TOTAL_mouse_list]; + uint32 _curMouse; + + MenuObject _tempList[TOTAL_engine_pockets]; + uint32 _totalTemp; + + MenuObject _masterMenuList[TOTAL_engine_pockets]; + uint32 _totalMasters; + + uint8 _menuStatus[2]; + byte *_icons[2][RDMENU_MAXPOCKETS]; + uint8 _pocketStatus[2][RDMENU_MAXPOCKETS]; + + uint8 _iconCount; + + // If it's NORMAL_MOUSE_ID (ie. normal pointer) then it's over a floor + // area (or hidden hot-zone) + + uint32 _mousePointerRes; + + struct MouseAnim *_mouseAnim; + struct MouseAnim *_luggageAnim; + + uint8 _mouseFrame; + byte *_mouseSprite; + int32 *_mouseOffsets; + int32 *_luggageOffset; + + uint32 _mouseMode; + + bool _mouseStatus; // Human 0 on/1 off + bool _mouseModeLocked; // 0 not !0 mode cannot be changed from + // normal mouse to top menu (i.e. when + // carrying big objects) + uint32 _realLuggageItem; // Last minute for pause mode + uint32 _currentLuggageResource; + uint32 _oldButton; // For the re-click stuff - must be + // the same button you see + uint32 _buttonClick; + uint32 _pointerTextBlocNo; + uint32 _playerActivityDelay; // Player activity delay counter + + bool _examiningMenuIcon; + + // Set by checkMouseList() + uint32 _mouseTouching; + uint32 _oldMouseTouching; + + uint32 _menuSelectedPos; + + void decompressMouse(byte *decomp, byte *comp, int width, int height, int pitch, int xOff = 0, int yOff = 0); + + int32 setMouseAnim(byte *ma, int32 size, int32 mouseFlash); + int32 setLuggageAnim(byte *la, int32 size); + + void clearIconArea(int menu, int pocket, Common::Rect *r); + +public: + Mouse(Sword2Engine *vm); + ~Mouse(); + + void getPos(int &x, int &y); + void setPos(int x, int y); + + bool getMouseStatus() { return _mouseStatus; } + uint32 getMouseTouching() { return _mouseTouching; } + void setMouseTouching(uint32 touching) { _mouseTouching = touching; } + + void pauseGame(); + void unpauseGame(); + + void setMouse(uint32 res); + void setLuggage(uint32 res); + + void setObjectHeld(uint32 res); + + void resetMouseList(); + + void registerMouse(ObjectMouse *ob_mouse, BuildUnit *build_unit); + void registerPointerText(int32 text_id); + + void createPointerText(uint32 text_id, uint32 pointer_res); + void clearPointerText(); + + void drawMouse(); + int32 animateMouse(); + + void processMenu(); + + void addMenuObject(MenuObject *obj); + void buildMenu(); + void buildSystemMenu(); + + int32 showMenu(uint8 menu); + int32 hideMenu(uint8 menu); + int32 setMenuIcon(uint8 menu, uint8 pocket, byte *icon); + + void closeMenuImmediately(); + + void refreshInventory(); + + void startConversation(); + void endConversation(); + + void hideMouse(); + void noHuman(); + void addHuman(); + + void resetPlayerActivityDelay() { _playerActivityDelay = 0; } + void monitorPlayerActivity(); + void checkPlayerActivity(uint32 seconds); + + void mouseOnOff(); + uint32 checkMouseList(); + void mouseEngine(); + + void normalMouse(); + void menuMouse(); + void dragMouse(); + void systemMenuMouse(); + + int menuClick(int menu_items); +}; + } // End of namespace Sword2 #endif diff --git a/sword2/resman.cpp b/sword2/resman.cpp index 099e218721..bfb5a7c7af 100644 --- a/sword2/resman.cpp +++ b/sword2/resman.cpp @@ -28,7 +28,6 @@ #include "sword2/resman.h" #include "sword2/router.h" #include "sword2/sound.h" -#include "sword2/driver/d_draw.h" #define Debug_Printf _vm->_debugger->DebugPrintf @@ -870,7 +869,7 @@ void ResourceManager::getCd(int cd) { _vm->_sound->stopMusic(true); textRes = openResource(2283); - _vm->displayMsg(_vm->fetchTextLine(textRes, 5 + cd) + 2, 0); + _vm->_screen->displayMsg(_vm->fetchTextLine(textRes, 5 + cd) + 2, 0); closeResource(2283); // The original code probably determined automagically when the correct diff --git a/sword2/router.cpp b/sword2/router.cpp index 33b342c177..ef0b81f5a6 100644 --- a/sword2/router.cpp +++ b/sword2/router.cpp @@ -79,7 +79,6 @@ #include "sword2/logic.h" #include "sword2/resman.h" #include "sword2/router.h" -#include "sword2/driver/d_draw.h" namespace Sword2 { @@ -2367,7 +2366,7 @@ void Router::plotWalkGrid(void) { // lines for (i = 0; i < _nBars; i++) - _vm->_graphics->drawLine(_bars[i].x1, _bars[i].y1, _bars[i].x2, _bars[i].y2, 254); + _vm->_screen->drawLine(_bars[i].x1, _bars[i].y1, _bars[i].x2, _bars[i].y2, 254); // nodes @@ -2377,8 +2376,8 @@ void Router::plotWalkGrid(void) { } void Router::plotCross(int16 x, int16 y, uint8 colour) { - _vm->_graphics->drawLine(x - 1, y - 1, x + 1, y + 1, colour); - _vm->_graphics->drawLine(x + 1, y - 1, x - 1, y + 1, colour); + _vm->_screen->drawLine(x - 1, y - 1, x + 1, y + 1, colour); + _vm->_screen->drawLine(x + 1, y - 1, x - 1, y + 1, colour); } void Router::loadWalkGrid(void) { diff --git a/sword2/save_rest.cpp b/sword2/save_rest.cpp index d3bd0035ff..ea1b34f5c0 100644 --- a/sword2/save_rest.cpp +++ b/sword2/save_rest.cpp @@ -34,6 +34,7 @@ #include "sword2/interpreter.h" #include "sword2/logic.h" #include "sword2/memory.h" +#include "sword2/mouse.h" #include "sword2/resman.h" #include "sword2/sound.h" @@ -115,13 +116,14 @@ uint32 Sword2Engine::findBufferSize(void) { void Sword2Engine::fillSaveBuffer(byte *buffer, uint32 size, byte *desc) { // Set up the _saveGameHeader. Checksum gets filled in last of all. + ScreenInfo *screenInfo = _screen->getScreenInfo(); strcpy(_saveGameHeader.description, (char *) desc); _saveGameHeader.varLength = _resman->fetchLen(1); - _saveGameHeader.screenId = _thisScreen.background_layer_id; + _saveGameHeader.screenId = screenInfo->background_layer_id; _saveGameHeader.runListId = _logic->getRunList(); - _saveGameHeader.feet_x = _thisScreen.feet_x; - _saveGameHeader.feet_y = _thisScreen.feet_y; + _saveGameHeader.feet_x = screenInfo->feet_x; + _saveGameHeader.feet_y = screenInfo->feet_y; _saveGameHeader.music_id = _sound->getLoopingMusicId(); memcpy(&_saveGameHeader.player_hub, _resman->openResource(CUR_PLAYER_ID) + sizeof(StandardHeader), sizeof(ObjectHub)); @@ -205,7 +207,7 @@ uint32 Sword2Engine::restoreGame(uint16 slotNo) { // Force the game engine to pick a cursor. This appears to be needed // when using the -x command-line option to restore a game. - _mouseTouching = 1; + _mouse->setMouseTouching(1); return errorCode; } @@ -304,16 +306,18 @@ uint32 Sword2Engine::restoreFromBuffer(byte *buffer, uint32 size) { pars[1] = 1; _logic->fnInitBackground(pars); + ScreenInfo *screenInfo = _screen->getScreenInfo(); + // So palette not restored immediately after control panel - we want to // fade up instead! - _thisScreen.new_palette = 99; + screenInfo->new_palette = 99; // These need setting after the defaults get set in fnInitBackground. // Remember that these can change through the game, so need saving & // restoring too. - _thisScreen.feet_x = _saveGameHeader.feet_x; - _thisScreen.feet_y = _saveGameHeader.feet_y; + screenInfo->feet_x = _saveGameHeader.feet_x; + screenInfo->feet_y = _saveGameHeader.feet_y; // Start the new run list _logic->expressChangeSession(_saveGameHeader.runListId); @@ -321,15 +325,14 @@ uint32 Sword2Engine::restoreFromBuffer(byte *buffer, uint32 size) { // Force in the new scroll position, so unsightly scroll-catch-up does // not occur when screen first draws after returning from restore panel - // set '_thisScreen's record of player position - // - ready for setScrolling() + // Set the screen record of player position - ready for setScrolling() - _thisScreen.player_feet_x = _saveGameHeader.mega.feet_x; - _thisScreen.player_feet_y = _saveGameHeader.mega.feet_y; + screenInfo->player_feet_x = _saveGameHeader.mega.feet_x; + screenInfo->player_feet_y = _saveGameHeader.mega.feet_y; // if this screen is wide, recompute the scroll offsets now - if (_thisScreen.scroll_flag) - setScrolling(); + if (screenInfo->scroll_flag) + _screen->setScrolling(); // Any music required will be started after we've returned from // restoreControl() - see systemMenuMouse() in mouse.cpp! diff --git a/sword2/scroll.cpp b/sword2/scroll.cpp index 82fa0fa504..f1eb00fe9f 100644 --- a/sword2/scroll.cpp +++ b/sword2/scroll.cpp @@ -21,7 +21,6 @@ #include "common/stdafx.h" #include "sword2/sword2.h" #include "sword2/defs.h" -#include "sword2/interpreter.h" #include "sword2/logic.h" namespace Sword2 { @@ -30,11 +29,22 @@ namespace Sword2 { #define MAX_SCROLL_DISTANCE 8 /** + * Sets the scroll target position for the end of the game cycle. The driver + * will then automatically scroll as many times as it can to reach this + * position in the allotted time. + */ + +void Screen::setScrollTarget(int16 sx, int16 sy) { + _scrollXTarget = sx; + _scrollYTarget = sy; +} + +/** * If the room is larger than the physical screen, this function is called * every game cycle to update the scroll offsets. */ -void Sword2Engine::setScrolling(void) { +void Screen::setScrolling() { // Normally we aim to get George's feet at (320,250) from top left // of screen window // feet_x = 128 + 320 diff --git a/sword2/sound.cpp b/sword2/sound.cpp index 90e5f8a395..97155db266 100644 --- a/sword2/sound.cpp +++ b/sword2/sound.cpp @@ -82,6 +82,20 @@ Sound::~Sound() { } } +void Sound::setReverseStereo(bool reverse) { + if (reverse != _reverseStereo) { + _reverseStereo = reverse; + + for (int i = 0; i < FXQ_LENGTH; i++) { + if (!_fxQueue[i].resource) + continue; + + _fxQueue[i].pan = -_fxQueue[i].pan; + _vm->_mixer->setChannelBalance(_fxQueue[i].handle, _fxQueue[i].pan); + } + } +} + /** * Stop all sounds, close their resources and clear the FX queue. */ @@ -190,6 +204,9 @@ void Sound::queueFx(int32 res, int32 type, int32 delay, int32 volume, int32 pan) volume = (volume * SoundMixer::kMaxChannelVolume) / 16; pan = (pan * 127) / 16; + if (isReverseStereo()) + pan = -pan; + _fxQueue[i].resource = res; _fxQueue[i].data = data + sizeof(StandardHeader); _fxQueue[i].len = len; diff --git a/sword2/sound.h b/sword2/sound.h index 0d5c2371b5..64b441ff51 100644 --- a/sword2/sound.h +++ b/sword2/sound.h @@ -197,7 +197,7 @@ public: void clearFxQueue(); void processFxQueue(); - void setReverseStereo(bool reverse) { _reverseStereo = reverse; } + void setReverseStereo(bool reverse); bool isReverseStereo() const { return _reverseStereo; } void muteSpeech(bool mute); @@ -228,7 +228,7 @@ public: int32 playFx(FxQueueEntry *fx); int32 playFx(PlayingSoundHandle *handle, byte *data, uint32 len, uint8 vol, int8 pan, bool loop, SoundMixer::SoundType soundType); int32 stopFx(int32 i); - int32 setFxIdVolumePan(int32 id, int vol, int pan = -1); + int32 setFxIdVolumePan(int32 id, int vol, int pan = 255); int32 getSpeechStatus(); int32 amISpeaking(); diff --git a/sword2/speech.cpp b/sword2/speech.cpp index dcd3651a9e..abf0e67d85 100644 --- a/sword2/speech.cpp +++ b/sword2/speech.cpp @@ -30,7 +30,6 @@ #include "sword2/maketext.h" #include "sword2/memory.h" #include "sword2/resman.h" -#include "sword2/driver/d_draw.h" namespace Sword2 { @@ -126,8 +125,10 @@ void Logic::locateTalker(int32 *params) { // Adjust the text coords for RDSPR_DISPLAYALIGN - _textX -= _vm->_thisScreen.scroll_offset_x; - _textY -= _vm->_thisScreen.scroll_offset_y; + ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); + + _textX -= screenInfo->scroll_offset_x; + _textY -= screenInfo->scroll_offset_y; } /** diff --git a/sword2/sword2.cpp b/sword2/sword2.cpp index 9bc65fcb38..461401b8a7 100644 --- a/sword2/sword2.cpp +++ b/sword2/sword2.cpp @@ -36,9 +36,9 @@ #include "sword2/logic.h" #include "sword2/maketext.h" #include "sword2/memory.h" +#include "sword2/mouse.h" #include "sword2/resman.h" #include "sword2/sound.h" -#include "sword2/driver/d_draw.h" #ifdef _WIN32_WCE extern bool isSmartphone(void); @@ -121,60 +121,21 @@ Sword2Engine::Sword2Engine(GameDetector *detector, OSystem *syst) : Engine(syst) _bootParam = ConfMan.getInt("boot_param"); _saveSlot = ConfMan.getInt("save_slot"); - _debugger = NULL; - _graphics = NULL; + _memory = NULL; + _resman = NULL; _sound = NULL; - _gui = NULL; - _fontRenderer = NULL; + _screen = NULL; + _mouse = NULL; _logic = NULL; - _resman = NULL; - _memory = NULL; + _fontRenderer = NULL; + _gui = NULL; + _debugger = NULL; _keyboardEvent.pending = false; _mouseEvent.pending = false; - _lastPaletteRes = 0; - - _largestLayerArea = 0; - _largestSpriteArea = 0; - - strcpy(_largestLayerInfo, "largest layer: none registered"); - strcpy(_largestSpriteInfo, "largest sprite: none registered"); - - _fps = 0; - _cycleTime = 0; - _frameCount = 0; - _wantSfxDebug = false; - // For the menus - - _totalTemp = 0; - memset(_tempList, 0, sizeof(_tempList)); - - _totalMasters = 0; - memset(_masterMenuList, 0, sizeof(_masterMenuList)); - memset(&_thisScreen, 0, sizeof(_thisScreen)); - memset(_mouseList, 0, sizeof(_mouseList)); - - _mouseX = _mouseY = 0; - _mouseTouching = 0; - _oldMouseTouching = 0; - _menuSelectedPos = 0; - _examiningMenuIcon = false; - _mousePointerRes = 0; - _mouseMode = 0; - _mouseStatus = false; - _mouseModeLocked = false; - _currentLuggageResource = 0; - _oldButton = 0; - _buttonClick = 0; - _pointerTextBlocNo = 0; - _playerActivityDelay = 0; - _realLuggageItem = 0; - - _scrollFraction = 16; - #ifdef SWORD2_DEBUG _stepOneCycle = false; _renderSkip = false; @@ -190,10 +151,11 @@ Sword2Engine::Sword2Engine(GameDetector *detector, OSystem *syst) : Engine(syst) Sword2Engine::~Sword2Engine() { delete _debugger; - delete _graphics; delete _sound; delete _gui; delete _fontRenderer; + delete _screen; + delete _mouse; delete _logic; delete _resman; delete _memory; @@ -233,7 +195,7 @@ int Sword2Engine::init(GameDetector &detector) { _system->beginGFXTransaction(); initCommonGFX(detector); - _graphics = new Graphics(this, 640, 480); + _screen = new Screen(this, 640, 480); _system->endGFXTransaction(); // Create the debugger as early as possible (but not before the @@ -249,6 +211,7 @@ int Sword2Engine::init(GameDetector &detector) { _fontRenderer = new FontRenderer(this); _gui = new Gui(this); _sound = new Sound(this); + _mouse = new Mouse(this); // Setup mixer if (!_mixer->isReady()) @@ -278,7 +241,7 @@ int Sword2Engine::init(GameDetector &detector) { if (saveExists(_saveSlot)) restoreGame(_saveSlot); else { - setMouse(NORMAL_MOUSE_ID); + _mouse->setMouse(NORMAL_MOUSE_ID); if (!_gui->restoreControl()) startGame(); } @@ -286,7 +249,7 @@ int Sword2Engine::init(GameDetector &detector) { int32 pars[2] = { 221, FX_LOOP }; bool result; - setMouse(NORMAL_MOUSE_ID); + _mouse->setMouse(NORMAL_MOUSE_ID); _logic->fnPlayMusic(pars); result = _gui->startControl(); @@ -302,7 +265,7 @@ int Sword2Engine::init(GameDetector &detector) { } else startGame(); - _graphics->initialiseRenderCycle(); + _screen->initialiseRenderCycle(); return 0; } @@ -374,9 +337,9 @@ int Sword2Engine::go() { // display once every 4 game-cycles if (!_renderSkip || (_gameCycle % 4) == 0) - buildDisplay(); + _screen->buildDisplay(); #else - buildDisplay(); + _screen->buildDisplay(); #endif } @@ -433,8 +396,7 @@ void Sword2Engine::parseEvents() { break; case OSystem::EVENT_MOUSEMOVE: if (!(_eventFilter & RD_KEYDOWN)) { - _mouseX = event.mouse.x; - _mouseY = event.mouse.y - RDMENU_MENUDEEP; + _mouse->setPos(event.mouse.x, event.mouse.y - RDMENU_MENUDEEP); } break; case OSystem::EVENT_LBUTTONDOWN: @@ -493,8 +455,8 @@ void Sword2Engine::gameCycle() { // will fill thrm through fnRegisterFrame() and // fnRegisterMouse(). - resetRenderLists(); - resetMouseList(); + _screen->resetRenderLists(); + _mouse->resetMouseList(); // Keep going as long as new lists keep getting put in // - i.e. screen changes. @@ -505,10 +467,12 @@ void Sword2Engine::gameCycle() { } // If this screen is wide, recompute the scroll offsets every cycle - if (_thisScreen.scroll_flag) - setScrolling(); + ScreenInfo *screenInfo = _screen->getScreenInfo(); - mouseEngine(); + if (screenInfo->scroll_flag) + _screen->setScrolling(); + + _mouse->mouseEngine(); _sound->processFxQueue(); } @@ -551,26 +515,19 @@ void Sword2Engine::sleepUntil(uint32 time) { while (getMillis() < time) { // Make sure menu animations and fades don't suffer, but don't // redraw the entire scene. - _graphics->processMenu(); - _graphics->updateDisplay(false); + _mouse->processMenu(); + _screen->updateDisplay(false); _system->delayMillis(10); } } void Sword2Engine::pauseGame() { // Don't allow Pause while screen fading or while black - if (_graphics->getFadeStatus() != RDFADE_NONE) + if (_screen->getFadeStatus() != RDFADE_NONE) return; _sound->pauseAllSound(); - - // Make the mouse cursor normal. This is the only place where we are - // allowed to clear the luggage this way. - - clearPointerText(); - _graphics->setLuggageAnim(NULL, 0); - setMouse(0); - _mouseTouching = 1; + _mouse->pauseGame(); // If level at max, turn down because palette-matching won't work // when dimmed @@ -585,22 +542,20 @@ void Sword2Engine::pauseGame() { // dim the palette during the pause if (!_stepOneCycle) - _graphics->dimPalette(); + _screen->dimPalette(); #else - _graphics->dimPalette(); + _screen->dimPalette(); #endif _gamePaused = true; } void Sword2Engine::unpauseGame() { - if (Logic::_scriptVars[OBJECT_HELD] && _realLuggageItem) - setLuggage(_realLuggageItem); - + _mouse->unpauseGame(); _sound->unpauseAllSound(); // Put back game screen palette; see build_display.cpp - setFullPalette(-1); + _screen->setFullPalette(-1); // If graphics level at max, turn up again if (_graphicsLevelFudged) { @@ -611,8 +566,8 @@ void Sword2Engine::unpauseGame() { _gamePaused = false; // If mouse is about or we're in a chooser menu - if (!_mouseStatus || _logic->_choosing) - setMouse(NORMAL_MOUSE_ID); + if (!_mouse->getMouseStatus() || _logic->_choosing) + _mouse->setMouse(NORMAL_MOUSE_ID); } uint32 Sword2Engine::getMillis() { diff --git a/sword2/sword2.h b/sword2/sword2.h index c51202b447..8de53d64e4 100644 --- a/sword2/sword2.h +++ b/sword2/sword2.h @@ -36,8 +36,6 @@ #include "sword2/build_display.h" #include "sword2/header.h" #include "sword2/icons.h" -#include "sword2/layers.h" -#include "sword2/mouse.h" #include "sword2/object.h" #include "sword2/save_rest.h" @@ -56,6 +54,8 @@ enum { class MemoryManager; class ResourceManager; class Sound; +class Screen; +class Mouse; class Graphics; class Logic; class FontRenderer; @@ -96,67 +96,6 @@ private: uint32 _bootParam; int32 _saveSlot; - // structure filled out by each object to register its graphic printing - // requrements - - struct BuildUnit { - int16 x; - int16 y; - uint16 scaled_width; - uint16 scaled_height; - int16 sort_y; - uint32 anim_resource; - uint16 anim_pc; - - // Denotes a scaling sprite at print time - and holds the - // scaling value for the shrink routine - - uint16 scale; - - // Non-zero means this item is a layer - retrieve from - // background layer and send to special renderer - - uint16 layer_number; - - // True means we want this frame to be affected by the shading - // mask - - bool shadingFlag; - }; - - BuildUnit _bgp0List[MAX_bgp0_sprites]; - BuildUnit _bgp1List[MAX_bgp1_sprites]; - BuildUnit _backList[MAX_back_sprites]; - BuildUnit _sortList[MAX_sort_sprites]; - BuildUnit _foreList[MAX_fore_sprites]; - BuildUnit _fgp0List[MAX_fgp0_sprites]; - BuildUnit _fgp1List[MAX_fgp1_sprites]; - - // Holds the order of the sort list, i.e. the list stays static and we - // sort this array. - - uint16 _sortOrder[MAX_sort_sprites]; - - // Last palette used - so that we can restore the correct one after a - // pause (which dims the screen) and it's not always the main screen - // palette that we want, eg. during the eclipse - - // This flag gets set in startNewPalette() and setFullPalette() - - uint32 _lastPaletteRes; - - void drawBackPar0Frames(); - void drawBackPar1Frames(); - void drawBackFrames(); - void drawSortFrames(byte *file); - void drawForeFrames(); - void drawForePar0Frames(); - void drawForePar1Frames(); - - void startNewPalette(); - void processLayer(byte *file, uint32 layer_number); - void processImage(BuildUnit *build_unit); - void getPlayerStructures(); void putPlayerStructures(); @@ -168,12 +107,6 @@ private: void pauseGame(); void unpauseGame(); - MenuObject _tempList[TOTAL_engine_pockets]; - uint32 _totalTemp; - - MenuObject _masterMenuList[TOTAL_engine_pockets]; - uint32 _totalMasters; - uint32 _totalStartups; uint32 _totalScreenManagers; uint32 _startRes; @@ -208,7 +141,8 @@ public: MemoryManager *_memory; ResourceManager *_resman; Sound *_sound; - Graphics *_graphics; + Screen *_screen; + Mouse *_mouse; Logic *_logic; FontRenderer *_fontRenderer; Gui *_gui; @@ -221,9 +155,6 @@ public: uint32 _controlsFontId; uint32 _redFontId; - int16 _mouseX; - int16 _mouseY; - uint32 setEventFilter(uint32 filter); void parseEvents(); @@ -232,36 +163,6 @@ public: MouseEvent *mouseEvent(); KeyboardEvent *keyboardEvent(); - void resetRenderLists(); - void buildDisplay(); - void displayMsg(byte *text, int time); - void setFullPalette(int32 palRes); - - int32 registerFrame(int32 *params); - void registerFrame(int32 *params, BuildUnit *build_unit); - - // The debugger wants to access these - - uint32 _curBgp0; - uint32 _curBgp1; - uint32 _curBack; - uint32 _curSort; - uint32 _curFore; - uint32 _curFgp0; - uint32 _curFgp1; - - // Debugging stuff - - uint32 _largestLayerArea; - uint32 _largestSpriteArea; - char _largestLayerInfo[128]; - char _largestSpriteInfo[128]; - - // 'frames per second' counting stuff - uint32 _fps; - uint32 _cycleTime; - uint32 _frameCount; - bool _wantSfxDebug; int32 _gameCycle; @@ -271,74 +172,10 @@ public: bool _stepOneCycle; #endif - int32 initBackground(int32 res, int32 new_palette); - #if RIGHT_CLICK_CLEARS_LUGGAGE bool heldIsInInventory(); #endif - int menuClick(int menu_items); - - void addMenuObject(MenuObject *obj); - void buildMenu(); - void buildSystemMenu(); - - // _thisScreen describes the current back buffer and its in-game scroll - // positions, etc. - - ScreenInfo _thisScreen; - - uint32 _curMouse; - MouseUnit _mouseList[TOTAL_mouse_list]; - - // Set by checkMouseList() - uint32 _mouseTouching; - uint32 _oldMouseTouching; - - uint32 _menuSelectedPos; - - // If it's NORMAL_MOUSE_ID (ie. normal pointer) then it's over a floor - // area (or hidden hot-zone) - - uint32 _mousePointerRes; - - uint32 _mouseMode; - bool _examiningMenuIcon; - - bool _mouseStatus; // Human 0 on/1 off - bool _mouseModeLocked; // 0 not !0 mode cannot be changed from - // normal mouse to top menu (i.e. when - // carrying big objects) - uint32 _realLuggageItem; // Last minute for pause mode - uint32 _currentLuggageResource; - uint32 _oldButton; // For the re-click stuff - must be - // the same button you see - uint32 _buttonClick; - uint32 _pointerTextBlocNo; - uint32 _playerActivityDelay; // Player activity delay counter - - void resetMouseList(); - - void normalMouse(); - void menuMouse(); - void dragMouse(); - void systemMenuMouse(); - - void mouseOnOff(); - uint32 checkMouseList(); - void mouseEngine(); - - void setMouse(uint32 res); - void setLuggage(uint32 res); - - void clearPointerText(); - - void createPointerText(uint32 text_id, uint32 pointer_res); - void monitorPlayerActivity(); - void noHuman(); - - void registerMouse(ObjectMouse *ob_mouse); - byte *fetchPalette(byte *screenFile); ScreenHeader *fetchScreenHeader(byte *screenFile); LayerHeader *fetchLayerHeader(byte *screenFile, uint16 layerNo); @@ -395,10 +232,6 @@ public: uint32 restoreFromBuffer(byte *buffer, uint32 size); uint32 findBufferSize(); - uint8 _scrollFraction; - - void setScrolling(); - bool _gamePaused; bool _graphicsLevelFudged; diff --git a/sword2/walker.cpp b/sword2/walker.cpp index d0238b4df7..bf284f402e 100644 --- a/sword2/walker.cpp +++ b/sword2/walker.cpp @@ -31,7 +31,6 @@ #include "sword2/memory.h" #include "sword2/resman.h" #include "sword2/router.h" -#include "sword2/driver/d_draw.h" namespace Sword2 { |