diff options
Diffstat (limited to 'sword2')
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 { |