Files
scummvm-cursorfix/engines/m4/wscript/ws_hal.cpp
2026-02-02 04:50:13 +01:00

660 lines
20 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 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/savefile.h"
#include "common/textconsole.h"
#include "m4/wscript/ws_hal.h"
#include "m4/wscript/wst_regs.h"
#include "m4/core/errors.h"
#include "m4/core/imath.h"
#include "m4/dbg/debug.h"
#include "m4/graphics/gr_sprite.h"
#include "m4/graphics/rend.h"
#include "m4/gui/gui_vmng.h"
#include "m4/vars.h"
#include "m4/m4.h"
namespace M4 {
bool ws_InitHAL() {
_GWS(deadRectList) = nullptr;
return true;
}
void ws_KillHAL() {
vmng_DisposeRectList(&_GWS(deadRectList));
}
void ws_DumpMachine(machine *m, Common::WriteStream *logFile) {
int32 i;
double tempFloat;
if (!m || !logFile)
return;
// Print out the machine name, hash, and physical address
logFile->writeString(Common::String::format("Machine Name: %s\n\tHash: %d\n\tAddress: %p\n\n", m->machName, m->myHash, (void *)m));
// If we have an anim8 for this machine
if (m->myAnim8) {
Anim8 *myAnim8 = m->myAnim8;
// Print out the anim8 hash, and physical address
logFile->writeString(Common::String::format("Sequence Hash: %d\n\tAddress: %p\n\n", myAnim8->sequHash, (void *)myAnim8));
// And if this anim8 has registers
if (myAnim8->myRegs) {
frac16 *myRegs = myAnim8->myRegs;
logFile->writeString("Registers:\n");
// Loop through the main set of registers, and dump out the contents
for (i = 0; i < IDX_COUNT; i++) {
tempFloat = (float)(myRegs[i] >> 16) + (float)((float)(myRegs[i] & 0xffff) / (float)65536);
logFile->writeString(Common::String::format("\t%d\t%s:\t\t%.2f\t\t0x%08" PRIxPTR "\n", i, myRegLabels[i], tempFloat, myRegs[i]));
}
// If the anim8 has extra local regs
if (myAnim8->numLocalVars > 0) {
for (i = IDX_COUNT; i < IDX_COUNT + myAnim8->numLocalVars; i++) {
tempFloat = (float)(myRegs[i] >> 16) + (float)((float)(myRegs[i] & 0xffff) / (float)65536);
logFile->writeString(Common::String::format("\t%d\tlocal.%d:\t\t%.2f\t\t0x%08" PRIxPTR "\n", i, i - IDX_COUNT, tempFloat, myRegs[i]));
}
}
logFile->writeString(Common::String::format("\n"));
}
// If this anim8 has a CCB
if (myAnim8->myCCB) {
CCB *myCCB = myAnim8->myCCB;
logFile->writeString(Common::String::format("Sprite Series Name: %s\tAddress:%p\tFlags0x%08x\n", myCCB->seriesName, (void *)myCCB, myCCB->flags));
logFile->writeString(Common::String::format("\tCurrent Location: (%d, %d), (%d, %d)\n", myCCB->currLocation->x1, myCCB->currLocation->y1,
myCCB->currLocation->x2, myCCB->currLocation->y2));
logFile->writeString(Common::String::format("\tNew Location: (%d, %d), (%d, %d)\n", myCCB->newLocation->x1, myCCB->newLocation->y1,
myCCB->newLocation->x2, myCCB->newLocation->y2));
logFile->writeString(Common::String::format("\tscale: %d\n", myCCB->scaleX));
logFile->writeString(Common::String::format("\tlayer: %d\n", myCCB->layer));
}
}
}
void ws_Error(machine *m, int32 errorType, trigraph errorCode, const char *errMsg) {
char description[MAX_STRING_SIZE];
// Find the error description
error_look_up(errorCode, description);
// Open the logFile
Common::OutSaveFile *logFile = g_system->getSavefileManager()->openForSaving("ws_mach.log");
// Give the WS debugger a chance to indicate the error to the apps programmer
dbg_WSError(logFile, m, errorType, description, errMsg, _GWS(pcOffsetOld));
// Dump out the machine to the logFile
ws_DumpMachine(m, logFile);
// Close the logFile
if (logFile)
f_io_close(logFile);
// Now we fatal abort
error_show(FL, errorCode, errMsg);
}
void ws_LogErrorMsg(const char *filename, uint32 line, const char *fmt, ...) {
va_list argPtr;
va_start(argPtr, fmt);
const Common::String msg = Common::String::vformat(fmt, argPtr);
va_end(argPtr);
error("%s", msg.c_str());
}
machine *kernel_timer_callback(int32 ticks, int16 trigger, MessageCB callMe) {
_GWS(ws_globals)[GLB_TEMP_1] = (frac16)(ticks << 16);
_GWS(ws_globals)[GLB_TEMP_2] = (frac16)trigger;
return (TriggerMachineByHash(1, nullptr, -1, -1, callMe, false, "timer callback"));
}
static void drawSprite(CCB *myCCB, Anim8 *myAnim8, Buffer *halScrnBuf, Buffer *screenCodeBuff,
uint8 *myPalette, uint8 *ICT) {
// Temporary var to prevent excessive dereferences
M4sprite *source = myCCB->source;
if (!(myCCB->flags & CCB_DISC_STREAM)) {
// Make sure the sprite is still in memory
if (!source->sourceHandle || !*(source->sourceHandle)) {
ws_LogErrorMsg(FL, "Sprite series is no longer in memory.");
ws_Error(myAnim8->myMachine, ERR_INTERNAL, 0x02ff, "Error during ws_DoDisplay()");
}
// Lock the sprite handle
HLock(source->sourceHandle);
source->data = (uint8 *)((intptr)*(source->sourceHandle) + source->sourceOffset);
}
assert(myCCB->currLocation);
Buffer Destination;
DrawRequest dr;
Destination.w = source->w;
Destination.h = source->h;
Destination.stride = source->w;
Destination.encoding = (myPalette && ICT) ? source->encoding : source->encoding & 0x7f;
Destination.data = source->data;
dr.Src = &Destination;
dr.Dest = halScrnBuf;
dr.x = myCCB->currLocation->x1;
dr.y = myCCB->currLocation->y1;
dr.scaleX = myCCB->scaleX;
dr.scaleY = myCCB->scaleY;
dr.depthCode = screenCodeBuff->data;
dr.Pal = myPalette;
dr.ICT = ICT;
dr.srcDepth = myCCB->layer >> 8;
// And draw the sprite
gr_sprite_draw(&dr);
myCCB->flags &= ~CCB_REDRAW;
if (!(myCCB->flags & CCB_DISC_STREAM))
// Unlock the sprite's handle
HUnLock(source->sourceHandle);
}
void ws_DoDisplay(Buffer *background, int16 *depth_table, Buffer *screenCodeBuff,
uint8 *myPalette, uint8 *ICT, bool updateVideo) {
if (!background)
error("ws_DoDisplay : background not set");
CCB *myCCB;
RectList *myRect;
RectList *drawRectList;
int32 status;
int32 restoreBgndX1, restoreBgndY1, restoreBgndX2, restoreBgndY2;
M4Rect *currRect;
bool breakFlag;
ScreenContext *myScreen = vmng_screen_find(_G(gameDrawBuff), &status);
if ((myScreen == nullptr) || (status != SCRN_ACTIVE)) {
return;
}
Buffer *halScrnBuf = _G(gameDrawBuff)->get_buffer();
const int32 scrnX1 = myScreen->x1;
const int32 scrnY1 = myScreen->y1;
const bool greyMode = krn_GetGreyMode();
// Initialize the drawRectList to the deadRectList
drawRectList = _GWS(deadRectList);
_GWS(deadRectList) = nullptr;
// Now we loop back to front and set up a list of drawing areas
Anim8 *myAnim8 = _GWS(myCruncher)->backLayerAnim8;
while (myAnim8) {
myCCB = myAnim8->myCCB;
if (myCCB && myCCB->source && (!(myCCB->flags & CCB_NO_DRAW)) && (myCCB->flags & CCB_REDRAW)) {
currRect = myCCB->currLocation;
M4Rect *newRect = myCCB->newLocation;
if (!(myCCB->flags & CCB_STREAM) && (!greyMode || !(myCCB->source->encoding & 0x80))) {
vmng_AddRectToRectList(&drawRectList, currRect->x1, currRect->y1,
currRect->x2, currRect->y2);
if ((!greyMode && (myCCB->source->encoding & 0x80)) ||
(greyMode && !(myCCB->source->encoding & 0x80))) {
vmng_AddRectToRectList(&drawRectList, newRect->x1, newRect->y1,
newRect->x2, newRect->y2);
}
}
// Copy over rect
*currRect = *newRect;
}
myAnim8 = myAnim8->infront;
}
// The drawRectList now contains all the areas of the screen that need the background updated
// Update the background behind the current rect list - if we are in greyMode, we do this later
if (!greyMode && background->data) {
myRect = drawRectList;
while (myRect) {
restoreBgndX1 = imath_max(myRect->x1, 0);
restoreBgndY1 = imath_max(myRect->y1, 0);
restoreBgndX2 = imath_min(myRect->x2, background->w - 1);
restoreBgndY2 = imath_min(myRect->y2, background->h - 1);
gr_buffer_rect_copy(background, halScrnBuf, restoreBgndX1, restoreBgndY1,
restoreBgndX2 - restoreBgndX1 + 1, restoreBgndY2 - restoreBgndY1 + 1);
myRect = myRect->next;
}
}
// Further iteration to set up drawing rects
myAnim8 = _GWS(myCruncher)->backLayerAnim8;
while (myAnim8) {
myCCB = myAnim8->myCCB;
if (myCCB && myCCB->source && !(myCCB->flags & CCB_NO_DRAW) && (myCCB->flags & CCB_REDRAW)) {
if (!(myCCB->source->encoding & 0x80) || (myCCB->flags & CCB_STREAM)) {
currRect = myCCB->currLocation;
vmng_AddRectToRectList(&drawRectList, currRect->x1, currRect->y1,
currRect->x2, currRect->y2);
}
}
myAnim8 = myAnim8->infront;
}
// Handle merging intersecting draw rects
do {
// Presume we'll be able to break
breakFlag = true;
// Iterate through the rects
myAnim8 = _GWS(myCruncher)->backLayerAnim8;
while (myAnim8) {
myCCB = myAnim8->myCCB;
if (myCCB && myCCB->source && !(myCCB->flags & (CCB_NO_DRAW | CCB_REDRAW))) {
currRect = myCCB->currLocation;
if (vmng_RectIntersectsRectList(drawRectList, currRect->x1, currRect->y1,
currRect->x2, currRect->y2)) {
vmng_AddRectToRectList(&drawRectList, currRect->x1, currRect->y1,
currRect->x2, currRect->y2);
myCCB->flags |= CCB_REDRAW;
if (greyMode || (myCCB->source->encoding & 0x80))
breakFlag = false;
if (!greyMode && (myCCB->source->encoding & 0x80)) {
restoreBgndX1 = imath_max(currRect->x1, 0);
restoreBgndY1 = imath_max(currRect->y1, 0);
restoreBgndX2 = imath_min(currRect->x2, background->w - 1);
restoreBgndY2 = imath_min(currRect->y2, background->h - 1);
gr_buffer_rect_copy(background, halScrnBuf, restoreBgndX1, restoreBgndY1,
restoreBgndX2 - restoreBgndX1 + 1, restoreBgndY2 - restoreBgndY1 + 1);
}
}
}
myAnim8 = myAnim8->infront;
}
} while (!breakFlag);
// Handle update background rect area
if (greyMode && background->data) {
myRect = drawRectList;
while (myRect) {
restoreBgndX1 = imath_max(myRect->x1, 0);
restoreBgndY1 = imath_max(myRect->y1, 0);
restoreBgndX2 = imath_min(myRect->x2, background->w - 1);
restoreBgndY2 = imath_min(myRect->y2, background->h - 1);
gr_buffer_rect_copy(background, halScrnBuf, restoreBgndX1, restoreBgndY1,
restoreBgndX2 - restoreBgndX1 + 1, restoreBgndY2 - restoreBgndY1 + 1);
myRect = myRect->next;
}
}
// Now we loop back to front and update the area of each sprite that intersects the update list,
// or simply draw the sprite if it has been marked for redraw
myAnim8 = _GWS(myCruncher)->backLayerAnim8;
while (myAnim8) {
myCCB = myAnim8->myCCB;
if (myCCB && myCCB->source && (!(myCCB->flags & CCB_NO_DRAW))) {
if ((myCCB->flags & CCB_REDRAW) && (!greyMode || !(myCCB->source->encoding & 0x80))) {
// Draw the sprite
drawSprite(myCCB, myAnim8, halScrnBuf, screenCodeBuff, myPalette, ICT);
}
}
myAnim8 = myAnim8->infront;
}
myRect = drawRectList;
while (myRect) {
if (updateVideo) {
if (greyMode) {
krn_UpdateGreyArea(halScrnBuf, scrnX1, scrnY1, myRect->x1, myRect->y1, myRect->x2, myRect->y2);
}
RestoreScreens(scrnX1 + myRect->x1, scrnY1 + myRect->y1, scrnX1 + myRect->x2, scrnY1 + myRect->y2);
}
myRect = myRect->next;
}
_G(gameDrawBuff)->release();
// Turf the drawRectList
vmng_DisposeRectList(&drawRectList);
}
void ws_hal_RefreshWoodscriptBuffer(cruncher *myCruncher, Buffer *background,
int16 *depth_table, Buffer *screenCodes, uint8 *myPalette, uint8 *ICT) {
Buffer drawSpriteBuff;
DrawRequest spriteDrawReq;
if (!background || !background->data)
return;
term_message("Refresh");
// Restore the background
Buffer *halScrnBuf = _G(gameDrawBuff)->get_buffer();
gr_buffer_rect_copy(background, halScrnBuf, 0, 0, halScrnBuf->w, halScrnBuf->h);
// Now draw all the sprites that are not hidden
Anim8 *myAnim8 = myCruncher->backLayerAnim8;
while (myAnim8) {
CCB *myCCB = myAnim8->myCCB;
if (myCCB && (myCCB->source != nullptr) && (!(myCCB->flags & CCB_SKIP)) && (!(myCCB->flags & CCB_HIDE))) {
if (!(myCCB->flags & CCB_DISC_STREAM)) {
// Make sure the series is still in memory
if ((!myCCB->source->sourceHandle) || (!*(myCCB->source->sourceHandle))) {
ws_LogErrorMsg(FL, "Sprite series is no longer in memory.");
ws_Error(myAnim8->myMachine, ERR_INTERNAL, 0x02ff,
"Error discovered during ws_hal_RefreshWoodscriptBuffer()");
}
// Lock the sprite handle
HLock(myCCB->source->sourceHandle);
myCCB->source->data = (uint8 *)((intptr)*(myCCB->source->sourceHandle) +
myCCB->source->sourceOffset);
}
// Prepare a sprite for drawing, as in ws_DoDisplay
drawSpriteBuff.w = myCCB->source->w;
drawSpriteBuff.h = myCCB->source->h;
drawSpriteBuff.stride = myCCB->source->w;
if (!myPalette || !ICT)
drawSpriteBuff.encoding = (uint8)(myCCB->source->encoding & 0x7f);
else
drawSpriteBuff.encoding = (uint8)myCCB->source->encoding;
drawSpriteBuff.data = myCCB->source->data;
if (!depth_table || !screenCodes || !screenCodes->data) {
spriteDrawReq.srcDepth = 0;
spriteDrawReq.depthCode = nullptr;
} else {
spriteDrawReq.srcDepth = (uint8)(myCCB->layer >> 8);
spriteDrawReq.depthCode = screenCodes->data;
}
spriteDrawReq.Src = (Buffer *)&drawSpriteBuff;
spriteDrawReq.Dest = halScrnBuf;
spriteDrawReq.x = myCCB->currLocation->x1;
spriteDrawReq.y = myCCB->currLocation->y1;
spriteDrawReq.scaleX = myCCB->scaleX;
spriteDrawReq.scaleY = myCCB->scaleY;
spriteDrawReq.Pal = myPalette;
spriteDrawReq.ICT = ICT;
gr_sprite_draw(&spriteDrawReq);
myCCB->flags &= ~CCB_REDRAW;
if (!(myCCB->flags & CCB_DISC_STREAM)) {
// Unlock the handle
HUnLock(myCCB->source->sourceHandle);
}
}
myAnim8 = myAnim8->infront;
}
_G(gameDrawBuff)->release();
}
void GetBezCoeffs(frac16 *ctrlPoints, frac16 *coeffs) {
const frac16 x0 = ctrlPoints[0];
const frac16 x0mult3 = (x0 << 1) + x0;
const frac16 x1mult3 = (ctrlPoints[2] << 1) + ctrlPoints[2];
const frac16 x1mult6 = x1mult3 << 1;
const frac16 x2mult3 = (ctrlPoints[4] << 1) + ctrlPoints[4];
const frac16 x3 = ctrlPoints[6];
const frac16 y0 = ctrlPoints[1];
const frac16 y0mult3 = (y0 << 1) + y0;
const frac16 y1mult3 = (ctrlPoints[3] << 1) + ctrlPoints[3];
const frac16 y1mult6 = y1mult3 << 1;
const frac16 y2mult3 = (ctrlPoints[5] << 1) + ctrlPoints[5];
const frac16 y3 = ctrlPoints[7];
coeffs[0] = -(int)x0 + x1mult3 - x2mult3 + x3;
coeffs[2] = x0mult3 - x1mult6 + x2mult3;
coeffs[4] = -(int)x0mult3 + x1mult3;
coeffs[6] = x0;
coeffs[1] = -(int)y0 + y1mult3 - y2mult3 + y3;
coeffs[3] = y0mult3 - y1mult6 + y2mult3;
coeffs[5] = -(int)y0mult3 + y1mult3;
coeffs[7] = y0;
return;
}
void GetBezPoint(frac16 *x, frac16 *y, frac16 *coeffs, frac16 tVal) {
*x = coeffs[6] +
MulSF16(tVal, (coeffs[4] +
MulSF16(tVal, (coeffs[2] +
MulSF16(tVal, coeffs[0])))));
*y = coeffs[7] +
MulSF16(tVal, (coeffs[5] +
MulSF16(tVal, (coeffs[3] +
MulSF16(tVal, coeffs[1])))));
}
bool InitCCB(CCB *myCCB) {
myCCB->flags = CCB_SKIP;
myCCB->source = nullptr;
if ((myCCB->currLocation = (M4Rect *)mem_alloc(sizeof(M4Rect), "Rectangle")) == nullptr) {
return false;
}
myCCB->currLocation->x1 = -1;
myCCB->currLocation->y1 = -1;
myCCB->currLocation->x2 = -1;
myCCB->currLocation->y2 = -1;
if ((myCCB->newLocation = (M4Rect *)mem_alloc(sizeof(M4Rect), "Rectangle")) == nullptr) {
return false;
}
myCCB->newLocation->x1 = -1;
myCCB->newLocation->y1 = -1;
myCCB->newLocation->x2 = -1;
myCCB->newLocation->y2 = -1;
myCCB->maxArea = nullptr;
myCCB->scaleX = 0;
myCCB->scaleY = 0;
myCCB->layer = 0;
myCCB->streamSSHeader = nullptr;
myCCB->streamSpriteSource = nullptr;
myCCB->myStream = nullptr;
myCCB->seriesName = nullptr;
return true;
}
void HideCCB(CCB *myCCB) {
if (!myCCB)
return;
myCCB->flags |= CCB_HIDE;
if ((myCCB->flags & CCB_STREAM) && myCCB->maxArea) {
vmng_AddRectToRectList(&_GWS(deadRectList), myCCB->maxArea->x1, myCCB->maxArea->y1, myCCB->maxArea->x2, myCCB->maxArea->y2);
mem_free(myCCB->maxArea);
myCCB->maxArea = nullptr;
} else {
vmng_AddRectToRectList(&_GWS(deadRectList), myCCB->currLocation->x1, myCCB->currLocation->y1, myCCB->currLocation->x2, myCCB->currLocation->y2);
}
}
void ShowCCB(CCB *myCCB) {
if (!myCCB)
return;
myCCB->flags &= ~CCB_HIDE;
}
void MoveCCB(CCB *myCCB, frac16 deltaX, frac16 deltaY) {
if (!myCCB || !myCCB->source) {
error_show(FL, 'WSIC');
}
myCCB->newLocation->x1 = myCCB->currLocation->x1 + (deltaX >> 16);
myCCB->newLocation->y1 = myCCB->currLocation->y1 + (deltaY >> 16);
myCCB->newLocation->x2 = myCCB->currLocation->x2 + (deltaX >> 16);
myCCB->newLocation->y2 = myCCB->currLocation->y2 + (deltaY >> 16);
if (myCCB->flags & CCB_STREAM) {
if (!myCCB->maxArea) {
if ((myCCB->maxArea = (M4Rect *)mem_alloc(sizeof(M4Rect), "Rectangle")) == nullptr) {
error_show(FL, 'OOM!');
}
myCCB->maxArea->x1 = myCCB->newLocation->x1;
myCCB->maxArea->y1 = myCCB->newLocation->y1;
myCCB->maxArea->x2 = myCCB->newLocation->x2;
myCCB->maxArea->y2 = myCCB->newLocation->y2;
} else {
myCCB->maxArea->x1 = imath_min(myCCB->maxArea->x1, myCCB->newLocation->x1);
myCCB->maxArea->y1 = imath_min(myCCB->maxArea->y1, myCCB->newLocation->y1);
myCCB->maxArea->x2 = imath_max(myCCB->maxArea->x2, myCCB->newLocation->x2);
myCCB->maxArea->y2 = imath_max(myCCB->maxArea->y2, myCCB->newLocation->y2);
}
}
if ((myCCB->source->w != 0) && (myCCB->source->h != 0)) {
myCCB->flags |= CCB_REDRAW;
}
}
void KillCCB(CCB *myCCB, bool restoreFlag) {
if (!myCCB) {
error_show(FL, 'WSIC');
}
if (restoreFlag && (!(myCCB->flags & CCB_SKIP)) && (!(myCCB->flags & CCB_HIDE))) {
if ((myCCB->flags & CCB_STREAM) && myCCB->maxArea) {
vmng_AddRectToRectList(&_GWS(deadRectList), myCCB->maxArea->x1, myCCB->maxArea->y1,
myCCB->maxArea->x2, myCCB->maxArea->y2);
} else {
vmng_AddRectToRectList(&_GWS(deadRectList), myCCB->currLocation->x1, myCCB->currLocation->y1,
myCCB->currLocation->x2, myCCB->currLocation->y2);
}
}
if (myCCB->flags & CCB_DISC_STREAM) {
ws_CloseSSstream(myCCB);
}
if (myCCB->currLocation) {
mem_free(myCCB->currLocation);
}
if (myCCB->newLocation) {
mem_free(myCCB->newLocation);
}
if (myCCB->maxArea) {
mem_free(myCCB->maxArea);
}
if (myCCB->source) {
mem_free(myCCB->source);
}
mem_free(myCCB);
}
void Cel_msr(Anim8 *myAnim8) {
if (!myAnim8) {
error_show(FL, 'WSAI');
}
CCB *myCCB = myAnim8->myCCB;
if ((!myCCB) || (!myCCB->source)) {
error_show(FL, 'WSIC');
}
if ((myCCB->source->w == 0) || (myCCB->source->h == 0)) {
return;
}
frac16 *myRegs = myAnim8->myRegs;
if (!myRegs) {
error_show(FL, 'WSAI');
}
const int32 scaler = FixedMul(myRegs[IDX_S], 100 << 16) >> 16;
myCCB->scaleX = myRegs[IDX_W] < 0 ? -scaler : scaler;
myCCB->scaleY = scaler;
GetUpdateRectangle(myRegs[IDX_X] >> 16, myRegs[IDX_Y] >> 16, myCCB->source->xOffset, myCCB->source->yOffset,
myCCB->scaleX, myCCB->scaleY, myCCB->source->w, myCCB->source->h, myCCB->newLocation);
if (myCCB->flags & CCB_STREAM) {
if (!myCCB->maxArea) {
if ((myCCB->maxArea = (M4Rect *)mem_alloc(sizeof(M4Rect), "Rectangle")) == nullptr) {
error_show(FL, 'OOM!');
}
myCCB->maxArea->x1 = myCCB->newLocation->x1;
myCCB->maxArea->y1 = myCCB->newLocation->y1;
myCCB->maxArea->x2 = myCCB->newLocation->x2;
myCCB->maxArea->y2 = myCCB->newLocation->y2;
} else {
myCCB->maxArea->x1 = imath_min(myCCB->maxArea->x1, myCCB->newLocation->x1);
myCCB->maxArea->y1 = imath_min(myCCB->maxArea->y1, myCCB->newLocation->y1);
myCCB->maxArea->x2 = imath_max(myCCB->maxArea->x2, myCCB->newLocation->x2);
myCCB->maxArea->y2 = imath_max(myCCB->maxArea->y2, myCCB->newLocation->y2);
}
} else {
vmng_AddRectToRectList(&_GWS(deadRectList), myCCB->currLocation->x1, myCCB->currLocation->y1,
myCCB->currLocation->x2, myCCB->currLocation->y2);
}
myAnim8->flags &= ~(TAG_MAP_CEL | TAG_MOVE_CEL);
myCCB->layer = imath_max(0, myAnim8->myLayer);
myCCB->flags &= ~CCB_SKIP;
myCCB->flags |= CCB_REDRAW;
return;
}
void ws_OverrideCrunchTime(machine *m) {
if ((!m) || (!m->myAnim8)) {
return;
}
m->myAnim8->switchTime = 0;
}
} // End of namespace M4