Initial commit
This commit is contained in:
362
engines/m4/gui/gui_vmng_screen.cpp
Normal file
362
engines/m4/gui/gui_vmng_screen.cpp
Normal file
@@ -0,0 +1,362 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/system.h"
|
||||
#include "common/rect.h"
|
||||
#include "graphics/surface.h"
|
||||
#include "m4/gui/gui_vmng_screen.h"
|
||||
#include "m4/gui/gui_vmng.h"
|
||||
#include "m4/vars.h"
|
||||
|
||||
namespace M4 {
|
||||
|
||||
static void vmng_black_out_video(int32 x1, int32 y1, int32 x2, int32 y2);
|
||||
static bool MoveScreen(ScreenContext *myScreen, int32 parmX, int32 parmY, bool deltaMove);
|
||||
|
||||
bool GetScreenCoords(void *scrnContent, int32 *x1, int32 *y1, int32 *x2, int32 *y2) {
|
||||
ScreenContext *myScreen = vmng_screen_find(scrnContent, nullptr);
|
||||
if (myScreen == nullptr)
|
||||
return false;
|
||||
|
||||
if (x1)
|
||||
*x1 = myScreen->x1;
|
||||
if (y1)
|
||||
*y1 = myScreen->y1;
|
||||
if (x2)
|
||||
*x2 = myScreen->x2;
|
||||
if (y2)
|
||||
*y2 = myScreen->y2;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RestoreScreens(int32 updateX1, int32 updateY1, int32 updateX2, int32 updateY2) {
|
||||
RectList *updateRectList, *scrnUpdateList, *tempRect;
|
||||
|
||||
if (!_G(vmng_Initted) || _G(system_shutting_down)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clip to screen
|
||||
if (updateX1 < MIN_VIDEO_X)
|
||||
updateX1 = MIN_VIDEO_X;
|
||||
if (updateY1 < MIN_VIDEO_Y)
|
||||
updateY1 = MIN_VIDEO_Y;
|
||||
if (updateX2 > MAX_VIDEO_X)
|
||||
updateX2 = MAX_VIDEO_X;
|
||||
if (updateY2 > MAX_VIDEO_Y)
|
||||
updateY2 = MAX_VIDEO_Y;
|
||||
|
||||
// Throw away inside out rectangles
|
||||
if ((updateX2 < updateX1) || (updateY2 < updateY1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a master updateRectList - when this list is empty, the screen has been redrawn
|
||||
updateRectList = vmng_CreateNewRect(updateX1, updateY1, updateX2, updateY2);
|
||||
|
||||
// First loop through the screens back to front, drawing only the transparent screens
|
||||
ScreenContext *myScreen = _G(backScreen);
|
||||
|
||||
while (myScreen && updateRectList) {
|
||||
// We only draw transparent screens on the first pass
|
||||
if ((myScreen->scrnFlags & SF_TRANSPARENT) && myScreen->redraw) {
|
||||
// Duplicate the updateRectList
|
||||
scrnUpdateList = vmng_DuplicateRectList(updateRectList);
|
||||
|
||||
// Now clip the scrnUpdateList with the coordinates of myScreen, see if there is anything visible
|
||||
vmng_ClipRectList(&scrnUpdateList, myScreen->x1, myScreen->y1, myScreen->x2, myScreen->y2);
|
||||
|
||||
// Now remove the rects of all screens blocking the scrnUpdateList
|
||||
ScreenContext *tempScreen = myScreen->infront;
|
||||
|
||||
while (scrnUpdateList && tempScreen) {
|
||||
vmng_RemoveRectFromRectList(&scrnUpdateList, tempScreen->x1, tempScreen->y1, tempScreen->x2, tempScreen->y2);
|
||||
tempScreen = tempScreen->infront;
|
||||
}
|
||||
|
||||
// If there is anything left of the scrnUpdateList, redraw it
|
||||
if (scrnUpdateList) {
|
||||
(myScreen->redraw)((void *)myScreen, (void *)scrnUpdateList, nullptr, 0, 0);
|
||||
|
||||
// Now remove all the updated rects from the updateRectList
|
||||
tempRect = scrnUpdateList;
|
||||
while (tempRect && updateRectList) {
|
||||
vmng_RemoveRectFromRectList(&updateRectList, tempRect->x1, tempRect->y1, tempRect->x2, tempRect->y2);
|
||||
tempRect = tempRect->next;
|
||||
}
|
||||
|
||||
// Now turf the scrnUpdateList
|
||||
vmng_DisposeRectList(&scrnUpdateList);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the next screen
|
||||
myScreen = myScreen->infront;
|
||||
}
|
||||
|
||||
// Now, draw from front to back the non-transparent screens. This way, we can detect when the entire update region has been
|
||||
// filled, however, if one transparent screen is infront of another, the back transparent screen must be drawn first.
|
||||
myScreen = _G(frontScreen);
|
||||
while (myScreen && updateRectList) {
|
||||
// Make sure it isn't a transparent screen
|
||||
if (!(myScreen->scrnFlags & SF_TRANSPARENT) && myScreen->redraw) {
|
||||
// Duplicate the updateRectList
|
||||
scrnUpdateList = vmng_DuplicateRectList(updateRectList);
|
||||
// Now clip the scrnUpdateList with the coordinates of myScreen, see what has to be redrawn
|
||||
vmng_ClipRectList(&scrnUpdateList, myScreen->x1, myScreen->y1, myScreen->x2, myScreen->y2);
|
||||
|
||||
// If there is anything visible, redraw it
|
||||
if (scrnUpdateList) {
|
||||
myScreen->redraw((void *)myScreen, (void *)scrnUpdateList, nullptr, 0, 0);
|
||||
|
||||
// Now remove all the updated rects from the updateRectList
|
||||
tempRect = scrnUpdateList;
|
||||
while (tempRect && updateRectList) {
|
||||
vmng_RemoveRectFromRectList(&updateRectList, tempRect->x1, tempRect->y1, tempRect->x2, tempRect->y2);
|
||||
tempRect = tempRect->next;
|
||||
}
|
||||
|
||||
// Now turf the scrnUpdateList
|
||||
vmng_DisposeRectList(&scrnUpdateList);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the next screen
|
||||
myScreen = myScreen->behind;
|
||||
}
|
||||
|
||||
// Now, if there is anything left, it should be filled in with black
|
||||
if (updateRectList) {
|
||||
tempRect = updateRectList;
|
||||
while (tempRect) {
|
||||
vmng_black_out_video(tempRect->x1, tempRect->y1, tempRect->x2, tempRect->y2);
|
||||
tempRect = tempRect->next;
|
||||
}
|
||||
|
||||
// Now turf the updateRectList
|
||||
vmng_DisposeRectList(&updateRectList);
|
||||
}
|
||||
}
|
||||
|
||||
void RestoreScreensInContext(int32 x1, int32 y1, int32 x2, int32 y2, ScreenContext *myScreen) {
|
||||
//verify the gui has been initted
|
||||
if (!_G(vmng_Initted)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//verify parameters
|
||||
ScreenContext *tempScreen = _G(frontScreen);
|
||||
while (tempScreen && (tempScreen != myScreen)) {
|
||||
tempScreen = tempScreen->behind;
|
||||
}
|
||||
if (!tempScreen) {
|
||||
return;
|
||||
}
|
||||
|
||||
//now restore screens
|
||||
x1 += myScreen->x1;
|
||||
y1 += myScreen->y1;
|
||||
x2 += myScreen->x1;
|
||||
y2 += myScreen->y1;
|
||||
|
||||
//restore video
|
||||
RestoreScreens(x1, y1, x2, y2);
|
||||
}
|
||||
|
||||
bool ResizeScreen(void *scrnContent, int32 newW, int32 newH) {
|
||||
if ((newW <= 0) || (newH <= 0))
|
||||
return false;
|
||||
|
||||
int32 status;
|
||||
ScreenContext *myScreen = vmng_screen_find(scrnContent, &status);
|
||||
if (myScreen == nullptr)
|
||||
return false;
|
||||
|
||||
const int32 oldX2 = myScreen->x2;
|
||||
myScreen->x2 = myScreen->x1 + newW - 1;
|
||||
|
||||
if (myScreen->x2 < oldX2) {
|
||||
RestoreScreens(myScreen->x2 + 1, myScreen->y1, oldX2, myScreen->y2);
|
||||
}
|
||||
|
||||
const int32 oldY2 = myScreen->y2;
|
||||
myScreen->y2 = myScreen->y1 + newH - 1;
|
||||
|
||||
if (myScreen->y2 < oldY2) {
|
||||
RestoreScreens(myScreen->x1, myScreen->y2 + 1, myScreen->x2, oldY2);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void vmng_black_out_video(int32 x1, int32 y1, int32 x2, int32 y2) {
|
||||
Common::Rect r(x1, y1, x2 + 1, y2 + 1);
|
||||
g_system->fillScreen(r, 0);
|
||||
}
|
||||
|
||||
bool AddScreenHotkey(void *scrnContent, int32 myKey, HotkeyCB callback) {
|
||||
ScreenContext *myScreen = vmng_screen_find(scrnContent, nullptr);
|
||||
if (myScreen == nullptr)
|
||||
return false;
|
||||
|
||||
Hotkey *myHotkey = (Hotkey *)mem_alloc(sizeof(Hotkey), "hotkey");
|
||||
if (myHotkey == nullptr)
|
||||
return false;
|
||||
|
||||
myHotkey->myKey = myKey;
|
||||
myHotkey->callback = callback;
|
||||
myHotkey->next = myScreen->scrnHotkeys;
|
||||
myScreen->scrnHotkeys = myHotkey;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RemoveScreenHotkey(void *scrnContent, int32 myKey) {
|
||||
ScreenContext *myScreen = vmng_screen_find(scrnContent, nullptr);
|
||||
if (myScreen == nullptr)
|
||||
return false;
|
||||
|
||||
Hotkey *myHotkey = myScreen->scrnHotkeys;
|
||||
|
||||
if (myHotkey->myKey == myKey) {
|
||||
myScreen->scrnHotkeys = myHotkey->next;
|
||||
mem_free(myHotkey);
|
||||
|
||||
} else {
|
||||
while (myHotkey->next && (myHotkey->next->myKey != myKey)) {
|
||||
myHotkey = myHotkey->next;
|
||||
}
|
||||
if (myHotkey->next) {
|
||||
Hotkey *tempHotkey = myHotkey->next;
|
||||
myHotkey->next = tempHotkey->next;
|
||||
mem_free(tempHotkey);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MoveScreenAbs(ScreenContext *myScreen, int32 parmX, int32 parmY) {
|
||||
return MoveScreen(myScreen, parmX, parmY, false);
|
||||
}
|
||||
|
||||
bool MoveScreenDelta(ScreenContext *myScreen, int32 parmX, int32 parmY) {
|
||||
return MoveScreen(myScreen, parmX, parmY, true);
|
||||
}
|
||||
|
||||
bool MoveScreenDelta(int32 parmX, int32 parmY) {
|
||||
return MoveScreen(_G(game_buff_ptr), parmX, parmY, true);
|
||||
}
|
||||
|
||||
void vmng_screen_to_back(void *scrnContent) {
|
||||
ScreenContext *myScreen = ExtractScreen(scrnContent, SCRN_ANY);
|
||||
if (myScreen == nullptr) return;
|
||||
if (!_G(backScreen)) {
|
||||
myScreen->infront = nullptr;
|
||||
myScreen->behind = nullptr;
|
||||
_G(frontScreen) = myScreen;
|
||||
_G(backScreen) = myScreen;
|
||||
} else {
|
||||
ScreenContext *tempScreen = _G(backScreen);
|
||||
while (tempScreen &&
|
||||
((tempScreen->scrnFlags & SF_LAYER) < (myScreen->scrnFlags & SF_LAYER))) {
|
||||
tempScreen = tempScreen->infront;
|
||||
}
|
||||
if (!tempScreen) {
|
||||
myScreen->infront = nullptr;
|
||||
myScreen->behind = _G(frontScreen);
|
||||
_G(frontScreen)->infront = myScreen;
|
||||
_G(frontScreen) = myScreen;
|
||||
} else if (tempScreen == _G(backScreen)) {
|
||||
myScreen->infront = _G(backScreen);
|
||||
myScreen->behind = nullptr;
|
||||
_G(backScreen)->behind = myScreen;
|
||||
_G(backScreen) = myScreen;
|
||||
} else {
|
||||
myScreen->infront = tempScreen;
|
||||
myScreen->behind = tempScreen->behind;
|
||||
tempScreen->behind = myScreen;
|
||||
myScreen->behind->infront = myScreen;
|
||||
}
|
||||
}
|
||||
|
||||
RestoreScreens(myScreen->x1, myScreen->y1, myScreen->x2, myScreen->y2);
|
||||
}
|
||||
|
||||
static bool MoveScreen(ScreenContext *myScreen, int32 parmX, int32 parmY, bool deltaMove) {
|
||||
if (!_G(vmng_Initted))
|
||||
return false;
|
||||
|
||||
const int32 origX1 = myScreen->x1;
|
||||
const int32 origY1 = myScreen->y1;
|
||||
const int32 origX2 = myScreen->x2;
|
||||
const int32 origY2 = myScreen->y2;
|
||||
|
||||
if (!deltaMove) {
|
||||
parmX -= origX1;
|
||||
parmY -= origY1;
|
||||
}
|
||||
if (!(myScreen->scrnFlags & SF_OFFSCRN)) {
|
||||
if ((myScreen->x2 + parmX) > MAX_VIDEO_X)
|
||||
parmX = MAX_VIDEO_X - myScreen->x2;
|
||||
else if ((myScreen->x1 + parmX) < 0)
|
||||
parmX = -myScreen->x1;
|
||||
if ((myScreen->y2 + parmY) > MAX_VIDEO_Y)
|
||||
parmY = MAX_VIDEO_Y - myScreen->y2;
|
||||
else if ((myScreen->y1 + parmY) < 0)
|
||||
parmY = -myScreen->y1;
|
||||
}
|
||||
|
||||
if (!(parmX || parmY))
|
||||
return false;
|
||||
|
||||
myScreen->x1 += parmX;
|
||||
myScreen->y1 += parmY;
|
||||
myScreen->x2 += parmX;
|
||||
myScreen->y2 += parmY;
|
||||
|
||||
if (parmY > 0) {
|
||||
RestoreScreens(origX1, origY1, origX2, myScreen->y1 - 1);
|
||||
if (parmX > 0) {
|
||||
RestoreScreens(origX1, myScreen->y1, myScreen->x1 - 1, origY2);
|
||||
} else if (parmX < 0) {
|
||||
RestoreScreens(myScreen->x2 + 1, myScreen->y1, origX2, origY2);
|
||||
}
|
||||
} else if (parmY < 0) {
|
||||
RestoreScreens(origX1, myScreen->y2 + 1, origX2, origY2);
|
||||
if (parmX > 0) {
|
||||
RestoreScreens(origX1, origY1, myScreen->x1 - 1, myScreen->y2);
|
||||
} else if (parmX < 0) {
|
||||
RestoreScreens(myScreen->x2 + 1, origY1, origX2, myScreen->y2);
|
||||
}
|
||||
} else if (parmX > 0) {
|
||||
RestoreScreens(origX1, origY1, myScreen->x1 - 1, origY2);
|
||||
} else {
|
||||
RestoreScreens(myScreen->x2 + 1, origY1, origX2, origY2);
|
||||
}
|
||||
|
||||
RestoreScreens(myScreen->x1, myScreen->y1, myScreen->x2, myScreen->y2);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace M4
|
||||
Reference in New Issue
Block a user