M4: Implementing lots of wscript and dependencies

Oh, soooo many dependencies.
This commit is contained in:
Paul Gilbert 2023-07-09 17:01:55 -07:00 committed by Eugene Sandulenko
parent f9490f9b91
commit fd4e2883b1
41 changed files with 6321 additions and 251 deletions

View File

@ -50,4 +50,14 @@ void player_set_commands_allowed(bool t_or_f) {
}
}
void game_pause(bool flag) {
if (flag) {
_G(kernel).pause = true;
PauseEngines();
} else {
_G(kernel).pause = false;
UnpauseEngines();
}
}
} // End of namespace M4

View File

@ -30,6 +30,7 @@ namespace M4 {
extern bool kernel_section_startup();
extern void player_set_commands_allowed(bool t_or_f);
extern void game_pause(bool flag);
} // End of namespace M4

View File

@ -19,12 +19,16 @@
*
*/
#include "common/str.h"
#include "common/file.h"
#include "common/textconsole.h"
#include "m4/core/errors.h"
namespace M4 {
inline static bool quadchar_equals_string(uint32 code, const Common::String &str) {
return READ_BE_UINT32(str.c_str()) == code;
}
void error_show(const char *filename, uint32 line, quadchar errorcode, const char *fmt, ...) {
va_list va;
va_start(va, fmt);
@ -38,4 +42,33 @@ void error_show(const char *filename, uint32 line, quadchar errorcode) {
error_show(filename, line, errorcode, "No extra description");
}
void error_look_up(quadchar errorcode, char *result_string) {
Common::File f;
*result_string = '\0';
if (!f.open(ERROR_FILE))
return;
Common::String buffer;
while (!f.eos()) {
buffer = f.readString();
const char *mark = buffer.c_str() + 1;
if (quadchar_equals_string(errorcode, buffer) || quadchar_equals_string(errorcode, mark)) {
const char *src = (const char *)buffer.c_str() + 5;
int16 count = 0;
do {
*result_string++ = *src;
++count;
} while (*src++ && (count < MAX_STRING_LEN));
break;
}
}
}
} // namespace M4

View File

@ -27,9 +27,11 @@
namespace M4 {
#define FL __FILE__,__LINE__
#define ERROR_FILE "error.m4"
extern void error_show(const char *filename, uint32 line, quadchar errorcode, const char *fmt, ...);
extern void error_show(const char *filename, uint32 line, quadchar errorcode);
extern void error_look_up(quadchar errorcode, char *result_string);
} // namespace M4

View File

@ -76,7 +76,6 @@ enum {
};
constexpr int GLB_SHARED_VARS = 256;
constexpr int GLOB_COUNT = 39;
struct GlobalVars : public Common::Array<int32> {
void syncGame(Common::Serializer &s);

View File

@ -117,6 +117,21 @@ frac16 SqrtF16(frac16 n) {
return (frac16)r;
}
#define DIV_128_PI 0x28be61
frac16 ArcTan(frac16 x, frac16 y) {
double floatX, floatY, result;
frac16 fracResult;
floatX = (float)(x >> 16) + (float)((float)(x & 0xffff) / (float)65536);
floatY = (float)(y >> 16) + (float)((float)(y & 0xffff) / (float)65536);
result = atan2(floatY, floatX);
fracResult = (((int32)(floor(result))) << 16) + (int32)(floor((result - floor(result)) * 65536));
fracResult = MulSF16(fracResult, DIV_128_PI);
if (fracResult < 0) fracResult += 0x1000000;
return fracResult;
}
uint16 HighWord(uint32 n) {
return (uint16)(n >> 16);
}

View File

@ -56,7 +56,7 @@ frac16 imath_ranged_rand16(frac16 a, frac16 b);
frac16 dist2d(int32 x1, int32 y1, int32 x2, int32 y2);
frac16 SqrtF16(frac16 n);
//frac16 ArcTan(frac16 x, frac16 y);
frac16 ArcTan(frac16 x, frac16 y);
uint16 HighWord(uint32 n);
uint16 LowWord(uint32 n);

51
engines/m4/dbg/dbg_defs.h Normal file
View File

@ -0,0 +1,51 @@
/* 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/>.
*
*/
#ifndef M4_DBG_DBG_DEFS_H
#define M4_DBG_DBG_DEFS_H
#include "m4/m4_types.h"
#include "m4/dbg/dbg_defs.h"
#include "m4/gui/gui_dialog.h"
#include "m4/wscript/ws_machine.h"
namespace M4 {
struct DBGSequSR {
DBGSequSR *next;
int32 prevSequHash;
int32 returnOffset;
};
struct DBGWatch {
DBGWatch *next;
DBGWatch *prev;
machine *m;
Dialog *d;
bool moreInfo;
bool machStep;
int32 sequHash;
bool sequStep;
};
} // namespace M4
#endif

View File

@ -0,0 +1,67 @@
/* 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 "m4/dbg/dbg_wscript.h"
namespace M4 {
bool dbg_ws_init(bool showTheScreen, Font *useThisFont, frac16 *theGlobals) {
return true;
}
void dbg_ws_shutdown() {
// No implementation
}
void dbg_ws_update() {
// No implementation
}
void dbg_LaunchSequence(Anim8 *myAnim8) {
// No implementation
}
void dbg_DebugWSMach(machine *m, bool debug) {
// No implementation
}
void dbg_DebugNextCycle() {
// No implementation
}
void dbg_RemoveWSMach(machine *m) {
// No implementation
}
void dbg_SetCurrMachInstr(machine *m, int32 pcOffset) {
// No implementation
}
void dbg_SetCurrSequInstr(Anim8 *myAnim8, int32 compareCCR) {
// No implementation
}
void dbg_WSError(Common::WriteStream *logFile, machine *m, int32 errorType,
const char *errDesc, const char *errMsg, int32 pcOffset) {
// No implementation
}
} // namespace M4

View File

@ -0,0 +1,48 @@
/* 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/>.
*
*/
#ifndef M4_DBG_DBG_WSCRIPT_H
#define M4_DBG_DBG_WSCRIPT_H
#include "common/stream.h"
#include "m4/m4_types.h"
#include "m4/dbg/dbg_defs.h"
#include "m4/graphics/gr_font.h"
#include "m4/wscript/ws_machine.h"
namespace M4 {
extern bool dbg_ws_init(bool showTheScreen, Font *useThisFont, frac16 *theGlobals);
extern void dbg_ws_shutdown();
extern void dbg_ws_update();
extern void dbg_LaunchSequence(Anim8 *myAnim8);
extern void dbg_DebugWSMach(machine *m, bool debug);
extern void dbg_DebugNextCycle();
extern void dbg_RemoveWSMach(machine *m);
extern void dbg_SetCurrMachInstr(machine *m, int32 pcOffset);
extern void dbg_SetCurrSequInstr(Anim8 *myAnim8, int32 compareCCR);
extern void dbg_WSError(Common::WriteStream *logFile, machine *m, int32 errorType,
const char *errDesc, const char *errMsg, int32 pcOffset);
} // namespace M4
#endif

27
engines/m4/dbg/debug.h Normal file
View File

@ -0,0 +1,27 @@
/* 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/>.
*
*/
#ifndef M4_DBG_DEBUG_H
#define M4_DBG_DEBUG_H
#include "m4/dbg/dbg_wscript.h"
#endif

View File

@ -20,15 +20,13 @@
*/
#include "m4/fileio/fstream.h"
#include "m4/core/errors.h"
#include "m4/core/imath.h"
#include "m4/vars.h"
namespace M4 {
bool f_stream_Init() {
_G(firstStream) = nullptr;
_G(lastStream) = nullptr;
return true;
}
#define STR_STRMREQ "stream request"
StreamFile::StreamFile(const Common::String &filename) {
if (!_file.open(filename))
@ -43,7 +41,7 @@ bool StreamFile::seek(uint32 n) {
return _file.seek(n);
}
bool StreamFile::seek_ahead(uint32 n) {
bool StreamFile::seek_ahead(int32 n) {
return _file.skip(n);
}
@ -51,4 +49,537 @@ uint32 StreamFile::get_pos() {
return _file.pos();
}
bool f_stream_Init() {
_G(firstStream) = nullptr;
_G(lastStream) = nullptr;
return true;
}
void f_stream_Shutdown(void) {
strmRequest *myStream;
// Loop through the list, closing all stream requests, which also deallocs the request
myStream = _G(firstStream);
while (myStream) {
_G(firstStream) = _G(firstStream)->next;
f_stream_Close(myStream);
myStream = _G(firstStream);
}
}
strmRequest *f_stream_Open(StreamFile *srcFile, int32 fileOffset, int32 strmMinBuffSize, int32 strmBuffSize,
int32 numBlocksToRead, int32 *blockSizeArray, int32 initialRead, bool wrapStream) {
strmRequest *newStream;
int32 bytesRead, i, bytesToRead;
bool finished;
void *bufferHandle;
int32 memAvail;
const int32 PADDING = 256;
// Parameter verification
if (!srcFile) {
error_show(FL, 'FSF!');
}
if (strmMinBuffSize < 0) {
error_show(FL, 'FSF1', "neg min buffsize: %ld", strmMinBuffSize);
}
// Allocate a new stream request struct
if ((newStream = (strmRequest *)mem_alloc(sizeof(strmRequest), STR_STRMREQ)) == nullptr) {
error_show(FL, 'OOM!', "%ld", sizeof(strmRequest));
return nullptr;
}
// Try to get memory
newStream->strmHandle = NewHandle(strmBuffSize, "stream buff");
if (newStream->strmHandle) {
goto got_mem;
}
// Maximize available memory
MaxMem((Size *)&memAvail); // param on PC is max mem avail in one block
// try to get requested size
if (memAvail >= strmBuffSize) {
/*
if ((newStream->strmBuff = (uint8*)mem_alloc(strmBuffSize, STR_STRMBUFF)) != nullptr) {
goto got_mem;
}
*/
// try to get memory
newStream->strmHandle = NewHandle(strmBuffSize, "stream buff");
if (newStream->strmHandle) {
goto got_mem;
}
}
// try to get what's left if it's enough
// get a compromise between free and requested.
// if we get it all, system gets unstable...
if (memAvail > strmMinBuffSize) {
int32 alloc_me = ((memAvail - strmMinBuffSize) / 2) + strmMinBuffSize;
/*
if ((newStream->strmBuff = (uint8*)mem_alloc(alloc_me, STR_STRMBUFF)) != nullptr) {
strmBuffSize = alloc_me;
goto got_mem;
}
*/
// try to get memory
newStream->strmHandle = NewHandle(alloc_me, "stream buff");
if (newStream->strmHandle) {
strmBuffSize = alloc_me;
goto got_mem;
}
}
// sorry, bud.
error_show(FL, 'FSOM', "want: %ld, have: %ld", strmMinBuffSize, memAvail);
got_mem:
//lock the buffer - to be locked until the stream is closed
HLock(newStream->strmHandle);
newStream->strmBuff = (uint8 *) * (newStream->strmHandle);
// Initialize the stream request
newStream->strmSize = strmBuffSize;
newStream->strmHead = newStream->strmBuff;
newStream->strmTail = newStream->strmBuff;
newStream->endStrmBuff = newStream->strmBuff + strmBuffSize;
newStream->strmWrap = newStream->endStrmBuff;
newStream->strmLastRead = newStream->endStrmBuff;
newStream->numBlocksToRead = numBlocksToRead;
newStream->blockSizeArray = blockSizeArray;
newStream->wrapStream = wrapStream;
newStream->srcFile = srcFile;
// If the streaming should begin part way into the file, seek to the beginning of where to start streaming
if (fileOffset > 0) {
// If (fseek(newStream->srcFile, fileOffset, SEEK_SET) != 0) {
if (!newStream->srcFile->seek(fileOffset)) {
delete newStream->srcFile;
mem_free(newStream);
return nullptr;
}
}
// Check if we are to initially read the stream
if (initialRead > 0) {
// If the blockSizeArray exists, then initialRead is the number of blocks to read
if (newStream->blockSizeArray) {
// Calculate the total number of bytes to read in initially
initialRead = (int32)imath_min(initialRead, numBlocksToRead);
finished = false;
bytesToRead = 0;
i = 0;
while ((i < initialRead) && (!finished)) {
if ((bytesToRead + blockSizeArray[i]) <= strmBuffSize) {
bytesToRead += blockSizeArray[i];
i++;
} else {
finished = true;
}
}
// Update the blockSizeArray, and numBlocksToRead entries. We plan to read in "i" blocks so far.
newStream->numBlocksToRead -= i;
newStream->blockSizeArray += i;
}
// Else the initialRead refers to the number of bytes to initially read
else {
//bounds check the initialRead and set the nextReadSize field
bytesToRead = (int32)imath_min(initialRead, strmBuffSize);
newStream->nextReadSize = bytesToRead;
}
// Make sure we still have something to read
if (bytesToRead > 0) {
// Read in the initial bytes to read
//bytesRead = fread((void*)newStream->strmHead, 1, bytesToRead, newStream->srcFile);
bufferHandle = newStream->strmHead;
bytesRead = newStream->srcFile->read((Handle)&bufferHandle, bytesToRead);
//did we actually read that many? If not, close the file
if (bytesRead < bytesToRead) {
delete newStream->srcFile;
newStream->srcFile = nullptr;
}
// Update the strmHead pointer
newStream->strmHead += bytesRead;
}
}
//link the stream request into the list of requests
newStream->prev = nullptr;
newStream->next = _G(firstStream);
if (_G(firstStream)) {
_G(firstStream)->prev = newStream;
} else {
_G(lastStream) = newStream;
}
_G(firstStream) = newStream;
// Return the stream request
return newStream;
}
static bool UnwrapStream(strmRequest *myStream) {
int32 bytesToMove = 0, bytesAvail;
uint8 *tempBuff;
// Using tempBuff as a flag to determine whether data needs to be temporarily stored
tempBuff = nullptr;
// Since strmTail is never allowed to be equal to strmWrap if it is > strmHead, there must be a
// Non-zero amount of data at the end which we must move.
//Therefore, we may have to temporarily store anything at the beginning of the buffer
if (myStream->strmHead > myStream->strmBuff) {
// Calculate how many bytes to store and copy to a temporary buffer
bytesToMove = (int32)myStream->strmHead - (int32)myStream->strmBuff;
if ((tempBuff = (uint8 *)mem_alloc(bytesToMove, "stream temp buff")) == nullptr)
error_show(FL, 'OOM!', "UnwrapStream() failed - temp buff avail: %ld", bytesToMove);
memcpy(tempBuff, myStream->strmBuff, bytesToMove);
}
// Move the data at the end of the buffer to the beginning and reset the strmWrap pointer
bytesAvail = (int32)myStream->strmWrap - (int32)myStream->strmTail;
memmove(myStream->strmBuff, myStream->strmTail, bytesAvail);
myStream->strmTail = myStream->strmBuff;
myStream->strmHead = (uint8 *)((int32)(myStream->strmTail) + bytesAvail);
myStream->strmWrap = myStream->endStrmBuff;
// Now check if we temporarily store data. if so, copy it back to the stream and turf the temp buffer
if (tempBuff) {
memcpy(myStream->strmHead, tempBuff, bytesToMove);
myStream->strmHead += bytesToMove;
mem_free(tempBuff);
}
return true;
}
void f_stream_DumpPreviouslyRead(strmRequest *myStream) {
// This is used to allow the f_stream_Process() function to overwrite the stream buffer space where
// the previously read data was stored. ie. If you call f_stream_Read(), and then make a copy,
// you wouldn't care if the data in the stream buffer was overwritten, so call this procedure.
if (myStream) {
myStream->strmLastRead = myStream->strmTail;
if (myStream->strmTail == myStream->strmHead) {
myStream->strmTail = myStream->strmBuff;
myStream->strmHead = myStream->strmBuff;
}
}
}
int32 f_stream_Read(strmRequest *myStream, uint8 **dest, int32 numBytes) {
int32 bytesAvail, bytesNeeded, bytesRead;
void *bufferHandle;
// Parameter verification
if (!myStream)
error_show(FL, 'FSIS', "f_stream_Read() failed - invalid stream request");
if ((numBytes <= 0) || (numBytes >= myStream->strmSize))
error_show(FL, 'FSR!', "%ld stream size %ld", numBytes, myStream->strmSize);
// If the stream tail is > the stream head, and the number of bytes at the end of the buffer is < numBytes
// we must unwrap the stream, moving the data at the end of the buffer to the beginning, and slide the beginning down
if ((myStream->strmTail > myStream->strmHead) && (((int32)myStream->strmWrap - (int32)myStream->strmTail) < numBytes)) {
UnwrapStream(myStream);
}
// Now either the strmHead is >= the strmTail, or there is enough data at the end of the buffer to fulfill numBytes
// Calculate the number of bytes available
if (myStream->strmTail <= myStream->strmHead) {
bytesAvail = (int32)(myStream->strmHead - myStream->strmTail);
} else {
// No extra data is available at the beginning of the stream buffer, since we "unwrapped" the stream
bytesAvail = (int32)(myStream->strmWrap - myStream->strmTail);
}
// Now check and see if we have enough bytes available
if (bytesAvail >= numBytes) {
// Set the destination pointer
*dest = (uint8 *)myStream->strmTail;
myStream->strmLastRead = myStream->strmTail;
// Update the strmTail pointer
myStream->strmTail += numBytes;
// If there is no data left at the end of the stream buffer, reset the strmTail and strmWrap pointers
if (myStream->strmTail == myStream->strmWrap) {
myStream->strmTail = myStream->strmBuff;
myStream->strmWrap = myStream->endStrmBuff;
}
return numBytes;
} else {
// Else we will have to read more data from disc
// If this has happened, since we "unwrapped" the stream buff, we can guarantee that strmTail < strmHead
// Calculate how much more must be read in
bytesNeeded = numBytes - bytesAvail;
// Make sure we have enough room at the end of the buffer to accommodate
if ((int32)(myStream->endStrmBuff - myStream->strmHead) < bytesNeeded) {
// We need to memmove the contents of the stream to the beginning of the buff to allow
// F_stream_read() to return a pointer to a contiguous block
// Move the data to the beginning of the stream buffer, and reset the head and tail pointers
memmove((void *)myStream->strmBuff, myStream->strmTail, bytesAvail);
myStream->strmTail = myStream->strmBuff;
myStream->strmHead = (uint8 *)((int32)myStream->strmTail + bytesAvail);
}
// If the client is using a blockSizeArray, hopefully bytesNeeded will be equal to the next blockSize
if (myStream->blockSizeArray && (*myStream->blockSizeArray == bytesNeeded) && (myStream->numBlocksToRead > 0)) {
myStream->blockSizeArray++;
myStream->numBlocksToRead--;
} else {
// Otherwise we just trashed the whole point of using a calculated blockSizeArray
myStream->blockSizeArray = nullptr;
myStream->numBlocksToRead = -1;
myStream->nextReadSize = numBytes;
}
// Read in the bytesNeeded
bufferHandle = myStream->strmHead;
bytesRead = myStream->srcFile->read((Handle)&bufferHandle, bytesNeeded);
if (bytesRead < bytesNeeded) {
// If we could not read that much in, close the srcFile
delete myStream->srcFile;
myStream->srcFile = nullptr;
}
// Set the destination pointer and update the stream pointers
*dest = (uint8 *)myStream->strmTail;
myStream->strmLastRead = myStream->strmTail;
myStream->strmHead += bytesRead;
myStream->strmTail = myStream->strmHead;
// Return the number of bytes successfully available
return (bytesRead + bytesAvail);
}
}
void f_stream_Close(strmRequest *myStream) {
// Parameter verification
if (!myStream) {
return;
}
// Close the stream and throw out the stream buffer
if (myStream->srcFile) {
delete myStream->srcFile;
}
// Kill the stream buffer
HUnLock(myStream->strmHandle);
DisposeHandle(myStream->strmHandle);
myStream->strmBuff = nullptr;
// Remove the stream request from the list of requests
if (myStream->next) {
myStream->next->prev = myStream->prev;
} else {
_G(lastStream) = myStream->prev;
}
if (myStream->prev) {
myStream->prev->next = myStream->next;
} else {
_G(firstStream) = myStream->next;
}
// Final, turf the stream request
mem_free(myStream);
}
void f_stream_Process(int32 numToProcess) {
strmRequest *myStream, *firstProcessStream;
int32 buffEndBytesAvail = 0, buffStartBytesAvail = 0;
int32 bytesRead, bytesAvail, nextReadSize;
bool buffWrap, useBlockSizeArray;
void *bufferHandle;
// No sense wasting time if there are no stream requests to process
if (!_G(firstStream)) {
return;
}
// Loop through until either the end of the list of requests, or we've serviced the "numToProcess"
firstProcessStream = _G(firstStream);
myStream = _G(firstStream);
while (myStream && (numToProcess > 0)) {
// Make sure we still have an open srcFile
if (myStream->srcFile && (myStream->numBlocksToRead != 0)) {
buffWrap = false;
useBlockSizeArray = false;
// Calculate the amount of empty space in the stream buff
// If all the empty space in the stream buff is between the head and the lastRead...
if (myStream->strmLastRead >= myStream->strmHead) {
bytesAvail = (int32)myStream->strmLastRead - (int32)myStream->strmHead;
// strmTail and strmHead can never equal unless the buffer is completely empty, therefore,
// make sure the amout of bytes available won't cause strmHead to become equal to strmTail
if ((bytesAvail > 0) && (myStream->strmLastRead == myStream->strmTail)) {
bytesAvail--;
}
} else {
// Else all the empty space is wrapped around the end of the buffer
buffWrap = true;
// Calculate how much space is available at the start and at the end of the buffer
buffEndBytesAvail = (int32)myStream->endStrmBuff - (int32)myStream->strmHead;
buffStartBytesAvail = (int32)myStream->strmLastRead - (int32)myStream->strmBuff;
// As above, ensure strmHead won't become equal to strmTail
if ((buffStartBytesAvail > 0) && (myStream->strmLastRead == myStream->strmTail)) {
buffStartBytesAvail--;
}
// Calculate the total bytes available
bytesAvail = buffEndBytesAvail + buffStartBytesAvail;
}
// Now find the number of bytes to read - either from the blockSizeArray...
if (myStream->blockSizeArray) {
useBlockSizeArray = true;
nextReadSize = *myStream->blockSizeArray;
} else {
// ...or directly from the nextReadSize field of the stream request
nextReadSize = myStream->nextReadSize;
}
// See if we can simply read the next chunk into the strmHead, without worrying about "wrapping" the buffer
if ((buffWrap && (buffEndBytesAvail >= nextReadSize)) ||
((!buffWrap) && (bytesAvail >= nextReadSize))) {
// Read the bytes into the stream buffer
bufferHandle = myStream->strmHead;
bytesRead = myStream->srcFile->read((Handle)&bufferHandle, nextReadSize);
// If we could not read that much in, close the srcFile
if (bytesRead < nextReadSize) {
delete myStream->srcFile;
myStream->srcFile = nullptr;
}
// Update the stream head
myStream->strmHead += bytesRead;
// Update the blockSizeArray pointer if necessary
if (useBlockSizeArray) {
myStream->blockSizeArray++;
myStream->numBlocksToRead--;
}
} else if (buffWrap) {
// Else if the empty space is wrapped, we may still be able to store the next data chunk, otherwise no more room
// See if we can wrap the next data chunk around
if (!myStream->wrapStream) {
// No wrapping allowed, so do we have room for it at the beginning of the stream
if (buffStartBytesAvail >= nextReadSize) {
//we can read it in at the beginning, so set the strmWrap pointer
myStream->strmWrap = myStream->strmHead;
// Read the bytes into the stream buffer
//bytesRead = (int32)fread((void*)myStream->strmBuff, 1, nextReadSize, myStream->srcFile);
bufferHandle = myStream->strmBuff;
bytesRead = myStream->srcFile->read((Handle)&bufferHandle, nextReadSize);
// If we could not read that much in, close the srcFile
if (bytesRead < nextReadSize) {
delete myStream->srcFile;
myStream->srcFile = nullptr;
}
// Update the stream head
myStream->strmHead = (uint8 *)((int32)myStream->strmBuff + bytesRead);
// Update the blockSizeArray pointer if necessary
if (useBlockSizeArray) {
myStream->blockSizeArray++;
myStream->numBlocksToRead--;
}
}
} else if (bytesAvail >= nextReadSize) {
// Else we might have to read in part at the end, and part at the beginning of the stream buffer
// Read into the end of the stream buffer
if (buffEndBytesAvail > 0) {
// Read into the end of the buffer
bufferHandle = myStream->strmHead;
bytesRead = (int32)myStream->srcFile->read((Handle)&bufferHandle, buffEndBytesAvail);
// If we could not read that much in, close the srcFile and update the head pointer
if (bytesRead < buffEndBytesAvail) {
delete myStream->srcFile;
myStream->srcFile = nullptr;
myStream->strmHead += bytesRead;
}
}
// Make sure we didn't close the srcFile in the last read
if (myStream->srcFile) {
// Read into the beginning of the buffer
bufferHandle = myStream->strmBuff;
bytesRead = myStream->srcFile->read((Handle)&bufferHandle, nextReadSize - buffEndBytesAvail);
// If we could not read that much in, close the srcFile
if (bytesRead < (nextReadSize - buffEndBytesAvail)) {
delete myStream->srcFile;
myStream->srcFile = nullptr;
}
// Update the head pointer
myStream->strmHead = (uint8 *)((int32)myStream->strmBuff + bytesRead);
// Update the blockSizeArray pointer if necessary
if (useBlockSizeArray) {
myStream->blockSizeArray++;
myStream->numBlocksToRead--;
}
}
}
}
}
// If we were able, we serviced the above stream request. Get the next request and decriment the counter
myStream = myStream->next;
numToProcess--;
}
// See if we ran out of processes or if the counter ran out
if (myStream) {
// This implies the counter ran out. Move the front of the list to myStream->prev to the end of the list
myStream->prev->next = nullptr;
_G(lastStream)->next = _G(firstStream);
_G(firstStream)->prev = _G(lastStream);
_G(lastStream) = myStream->prev;
myStream->prev = nullptr;
_G(firstStream) = myStream;
}
}
} // namespace M4

View File

@ -23,6 +23,7 @@
#define M4_FILEIO_FSTREAM_H
#include "common/file.h"
#include "m4/mem/reloc.h"
#include "m4/m4_types.h"
namespace M4 {
@ -36,7 +37,7 @@ public:
int32 read(Handle bufferHandle, int32 n);
bool seek(uint32 n);
bool seek_ahead(uint32 n);
bool seek_ahead(int32 n);
uint32 get_pos();
};
@ -45,7 +46,7 @@ struct strmRequest {
strmRequest *prev;
StreamFile *srcFile;
int32 strmSize;
Handle strmHandle;
MemHandle strmHandle;
uint8 *strmBuff;
uint8 *endStrmBuff;
uint8 *strmHead;
@ -59,6 +60,13 @@ struct strmRequest {
};
extern bool f_stream_Init();
extern void f_stream_Shutdown();
extern strmRequest *f_stream_Open(StreamFile *srcFile, int32 fileOffset, int32 strmMinBuffSize, int32 strmBuffSize,
int32 numBlocksToRead, int32 *blockSizeArray, int32 initialRead, bool wrapStream);
extern int32 f_stream_Read(strmRequest *myStream, uint8 **dest, int32 numBytes);
extern void f_stream_Close(strmRequest *myStream);
extern void f_stream_Process(int32 numToProcess);
} // namespace M4

View File

@ -47,4 +47,10 @@ bool series_show_frame(int32 spriteHash, int32 index, Buffer *destBuff, int32 x,
return series_draw_sprite(spriteHash, index, destBuff, x, y);
}
machine *series_play_xy(char *seriesName, int32 loopCount, uint32 flags,
int32 x, int32 y, int32 s, int32 layer, int32 frameRate, int16 triggerNum) {
error("TODO: series_play_xy");
return nullptr;
}
} // namespace M4

View File

@ -27,6 +27,12 @@
namespace M4 {
constexpr uint32 FORWARD = 0;
constexpr uint32 PINGPONG = 1;
constexpr uint32 BACKWARD = 2;
constexpr uint32 STICK = 4;
constexpr uint32 NO_TOSS = 8;
extern int32 series_load(const char *seriesName, int32 assetIndex, RGB8 *myPal);
extern void series_unload(int32 assetIndex);
extern bool series_draw_sprite(int32 spriteHash, int32 index, Buffer *destBuff, int32 x, int32 y);

View File

@ -19,20 +19,501 @@
*
*/
#include "m4/m4_types.h"
#include "m4/adv_r/adv_control.h"
#include "m4/core/errors.h"
#include "m4/core/imath.h"
#include "m4/events/keys.h"
#include "m4/graphics/krn_pal.h"
#include "m4/graphics/gr_pal.h"
#include "m4/graphics/gr_series.h"
#include "m4/gui/gui_sys.h"
#include "m4/gui/gui_vmng.h"
#include "m4/vars.h"
namespace M4 {
void krn_ChangeBufferLuminance(Buffer *target, int32 percent) {
int32 x, y, r, g, b, i;
uint8 *inverse_palette, pixel, *tempPtr;
frac16 fracPercent;
RGB8 *pal;
uint8 luminancePal[256];
#define _GP(X) _G(krnPal)._##X
//paremeter verification
#define BACKGROUND_HEIGHT (int32)639
#define GREY_START 32
#define NUM_GREYS 32 // gotta have 32 greys to fade to (hardcoded algorithm)
#define GREY_END GREY_START+NUM_GREYS
#define FREE_START GREY_END+1
#define FREE_END 255
#define NUM_FREE FREE_END-(FREE_START)+1
static void krn_pal_game_task() {
int32 status;
ScreenContext *game_buff_ptr = vmng_screen_find(_G(gameDrawBuff), &status);
if (!game_buff_ptr)
error_show(FL, 'BUF!');
CycleEngines(_G(game_bgBuff)->get_buffer(), &(_G(currentSceneDef).depth_table[0]),
_G(screenCodeBuff), (uint8 *)&_G(master_palette)[0], _G(inverse_pal)->get_ptr(), true);
_G(inverse_pal)->release();
_G(game_bgBuff)->release();
_G(digi).task();
_G(midi).task();
gui_system_event_handler();
f_stream_Process(2);
}
static int32 screen_height(Buffer *grey_screen) {
return imath_min(BACKGROUND_HEIGHT + _G(kernel).letter_box_y, grey_screen->h);
}
static void grey_fade(RGB8 *pal, int32 to_from_flag, int32 from, int32 to, int32 steps, int32 delay) {
int i;
#ifdef TODO
int j;
clock_t begin_time;
RGB8 *working = (RGB8 *)mem_alloc(sizeof(RGB8) * 256, STR_FADEPAL);
// perform the fade
for (i = 1; i < steps; i++) {
for (j = from; j <= to; j++) {
if (to_from_flag == TO_GREY) { // fade to grey from full color
working[j].r = (Byte)((int)pal[j].r + ((((int)_GP(fadeToMe)[j].r - (int)pal[j].r) * i) / steps));
working[j].g = (Byte)((int)pal[j].g + ((((int)_GP(fadeToMe)[j].g - (int)pal[j].g) * i) / steps));
working[j].b = (Byte)((int)pal[j].b + ((((int)_GP(fadeToMe)[j].b - (int)pal[j].b) * i) / steps));
} else if (to_from_flag == TO_COLOR) { // fade from grey to full color
working[j].r = (Byte)((int)_GP(fadeToMe)[j].r + ((((int)pal[j].r - (int)_GP(fadeToMe)[j].r) * i) / steps));
working[j].g = (Byte)((int)_GP(fadeToMe)[j].g + ((((int)pal[j].g - (int)_GP(fadeToMe)[j].g) * i) / steps));
working[j].b = (Byte)((int)_GP(fadeToMe)[j].b + ((((int)pal[j].b - (int)_GP(fadeToMe)[j].b) * i) / steps));
} else { //fade from grey to black
working[j].r = (Byte)((int)_GP(fadeToMe)[j].r - ((((int)_GP(fadeToMe)[j].r) * i) / steps));
working[j].g = (Byte)((int)_GP(fadeToMe)[j].g - ((((int)_GP(fadeToMe)[j].g) * i) / steps));
working[j].b = (Byte)((int)_GP(fadeToMe)[j].b - ((((int)_GP(fadeToMe)[j].b) * i) / steps));
}
}
gr_pal_set_range(working, from, to - from + 1); ///set pal 21-255
// Time delay of "delay" milliseconds
begin_time = clock();
while ((((clock() - begin_time) * 1000) / CLOCKS_PER_SEC) < delay)
krn_pal_game_task();
}
#else
error("TODO: grey_fade");
#endif
// Eliminate round off error
if (to_from_flag == TO_GREY) {
gr_pal_set_range(_GP(fadeToMe), from, to - from + 1); ///set pal 21-255
} else if (to_from_flag == TO_COLOR) {
gr_pal_set_range(pal, from, to - from + 1); ///set pal 21-255
} else {
for (i = from; i <= to; i++) {
pal[i].r = pal[i].g = pal[i].b = 0;
}
gr_pal_set_range(pal, from, to - from + 1); ///set pal 21-255
}
#ifdef TODO
mem_free(working);
#endif
}
// screen is the currently displayed screen
// screenPicture is the data to restore the screen with
// note: color 0 doesn't fade.
static void create_luminance_map(RGB8 *pal) {
for (int i = GREY_START; i <= FREE_END; i++) {
Byte luminance = (Byte)((pal[i].r + pal[i].g + pal[i].b) / 3);
_GP(fadeToMe)[i].g = (Byte)imath_min(255, luminance); // MattP new green screen!
_GP(fadeToMe)[i].r = _GP(fadeToMe)[i].b = 0;
}
}
static HotkeyCB remember_esc_key;
// finds the best macthes for the in the greys in the grey ramp range using the free range greys
// used to map greys out of the grey ramp area, and then again to map the grey ramp out of the grey ramp area!
static void make_translation_table(RGB8 *pal) {
int32 i, j, bestMatch, minDist;
for (i = 0; i < NUM_GREYS; i++) {
bestMatch = FREE_START; // assume the first of the free indexes is best match to start with
minDist = 255; // assume that it's really far away to start with
if (!(i & 0x3ff)) {
digi_read_another_chunk();
midi_loop();
}
// look for best match in the free indexes for the greys in GREY_START-GREY_END range (we need these available)
int32 matchGrey = pal[GREY_START + i].g; // MattP use green instead of red cause we're having a green screen
for (j = FREE_START; j <= FREE_END; j++) {
int32 tryGrey = pal[j].g;
if (imath_abs(tryGrey - matchGrey) < minDist) {
minDist = imath_abs(tryGrey - matchGrey);
bestMatch = j;
}
if (minDist == 0)
break; // no need to continue searching if we found a perfect match
}
_GP(translation)[i] = (uint8)bestMatch;
}
}
void krn_fade_to_grey(RGB8 *pal, int32 steps, int32 delay) {
int32 i, j, bestMatch, minDist;
uint8 *tempPtr;
if (_G(kernel).fading_to_grey) {
return;
}
_G(kernel).fading_to_grey = true;
Buffer *grey_screen = _G(gameDrawBuff)->get_buffer();
_GP(fadeToMe) = (RGB8 *)mem_alloc(sizeof(RGB8) * 256, STR_FADEPAL);
_GP(trick) = (RGB8 *)mem_alloc(sizeof(RGB8) * 256, STR_FADEPAL);
_GP(picPal) = (RGB8 *)mem_alloc(sizeof(RGB8) * 256, STR_FADEPAL);
memcpy(_GP(picPal), pal, sizeof(RGB8) * 256);
create_luminance_map(pal);
grey_fade(pal, TO_GREY, 21, 255, steps, delay);
// make _GP(translation) table
// to translate colors using entries 59-255 into 21-58 range
for (i = 0; i < 64; i++) {
bestMatch = 63;
minDist = 255;
if (!(i & 0x3ff)) {
_G(digi).task();
_G(midi).task();
}
for (j = 59; j <= 255; j++) {
if (imath_abs((_GP(fadeToMe)[j].r >> 2) - i) < minDist) {
minDist = imath_abs((_GP(fadeToMe)[j].r >> 2) - i);
bestMatch = j;
}
if (minDist == 0)
break; // no need to continue searching if we found a perfect match
}
_GP(translation)[i] = (uint8)bestMatch;
}
// palette now grey scale. Remap any pixels which are in the range 21-58 to the range 53-255
// because we need to use those palette entries soon
tempPtr = grey_screen->data;
// note: this loop should be y0 to y1, x0 to x1, not a stride*h loop.
for (i = 0; i < (grey_screen->stride * grey_screen->h); i++) {
if ((*tempPtr >= GREY_START) && (*tempPtr <= GREY_END)) {
// must move the pixel index to the best match in FREE_START-FREE_END range with _GP(translation) table
*tempPtr = _GP(translation)[*tempPtr - GREY_START];
}
tempPtr++;
if (!(i & 0x3ff)) {
_G(digi).task();
_G(midi).task();
}
}
RestoreScreens(MIN_VIDEO_X, MIN_VIDEO_Y, MAX_VIDEO_X, MAX_VIDEO_Y);
// make new trickPal with grey-scale ramp entries and load it into VGA registers
memcpy(_GP(trick), _GP(fadeToMe), sizeof(RGB8) * 256); // MattP _GP(trick) pal is the greyed version plus the grey ramp overlayed on top
int8 grey_step = 256 / NUM_GREYS;
int8 grey_ramp = 0;
for (i = GREY_START; i <= GREY_END; i++) {
// _GP(trick)[i].r = _GP(trick)[i].g = _GP(trick)[i].b = (Byte) (grey_ramp); old grey ramp
_GP(trick)[i].g = (Byte)(grey_ramp); // MattP new green screen
_GP(trick)[i].r = _GP(trick)[i].b = 0;
grey_ramp += grey_step;
}
gr_pal_set_range(_GP(trick), GREY_START, NUM_GREYS); ///set pal GREY_START-GREY_END
remap_buffer_with_luminance_map(grey_screen, 0, 0, grey_screen->W - 1, screen_height(grey_screen) - 1);
_G(gameDrawBuff)->release();
RestoreScreens(MIN_VIDEO_X, MIN_VIDEO_Y, MAX_VIDEO_X, MAX_VIDEO_Y);
}
void krn_fade_from_grey(RGB8 *pal, int32 steps, int32 delay, int32 fadeType) {
uint8 *tempPtr;
int32 i;
if (!_G(kernel).fading_to_grey) {
return;
}
// Get the screen
Buffer *grey_screen = _G(gameDrawBuff)->get_buffer();
// load original faded greys into the free indexes (no pixels have these indexs yet)
gr_pal_set_range(_GP(fadeToMe), FREE_START, NUM_FREE); // Load _GP(fadeToMe) colors into VGA
make_translation_table(_GP(trick)); // Mattp this is used in fade_to_grey too!
// for every pixel in the screen, move any pixel in the GREY_START-GREY_END range out in to the free range
tempPtr = grey_screen->data;
// note: this loop should be y0 to y1, x0 to x1, not a stride*h loop.
for (i = 0; i < (grey_screen->stride * grey_screen->h); ++i) {
if (!(i & 0x3ff)) {
_G(digi).task();
_G(midi).task();
}
// if the pixel is within the GREY range, move it to where the _GP(translation) table says
if ((*tempPtr >= GREY_START) && (*tempPtr <= GREY_END)) {
*tempPtr = _GP(translation)[*tempPtr - GREY_START];
}
tempPtr++;
}
// Term_message ("remaped indexes out of grey ramp");
RestoreScreens(MIN_VIDEO_X, MIN_VIDEO_Y, MAX_VIDEO_X, MAX_VIDEO_Y);
// Term_message ("setting grey ramp indexes back to picture greys");
gr_pal_set_range(_GP(fadeToMe), GREY_START, NUM_GREYS); // get the rest of the original re-luminance colors
//recopy screenPicture to screen to restore original pixels
krn_UnsetGreyVideoMode();
RestoreScreens(0, 0, MAX_VIDEO_X, MAX_VIDEO_Y);
memcpy(pal, _GP(picPal), sizeof(RGB8) * 256);
ws_RefreshWoodscriptBuffer(_G(game_bgBuff)->get_buffer(), &(_G(currentSceneDef).depth_table[0]), _G(screenCodeBuff),
(uint8 *)&_G(master_palette)[0], _G(inverse_pal)->get_ptr());
_G(game_bgBuff)->release();
_G(inverse_pal)->release();
RestoreScreens(MIN_VIDEO_X, MIN_VIDEO_Y, MAX_VIDEO_X, MAX_VIDEO_Y);
grey_fade(pal, fadeType, GREY_START, FREE_END, steps, delay);
mem_free((char *)_GP(trick));
mem_free((char *)_GP(fadeToMe));
mem_free((char *)_GP(picPal));
_G(kernel).fading_to_grey = false;
_G(gameDrawBuff)->release();
gr_pal_set(_G(master_palette));
}
bool examining_inventory_object = false;
void kernel_examine_inventory_object(char *picName, RGB8 *pal, int steps, int delay,
int32 x, int32 y, int32 triggerNum, char *digi_name, int32 digi_trigger) {
remember_esc_key = GetSystemHotkey(KEY_ESCAPE);
RemoveSystemHotkey(KEY_ESCAPE);
interface_hide();
_GP(exam_saved_hotspots) = _G(currentSceneDef).hotspots;
_G(currentSceneDef).hotspots = NULL;
_GP(myFadeTrigger) = kernel_trigger_create(triggerNum);
krn_fade_to_grey(pal, steps, delay);
_GP(seriesHash) = series_load(picName, -1, pal); // Preload sprite so we can unload it
gr_pal_set_range(pal, FREE_START, 197); // Set that series colors into VGA
RestoreScreens(MIN_VIDEO_X, MIN_VIDEO_Y, MAX_VIDEO_X, MAX_VIDEO_Y);
Buffer *grey_screen = _G(gameDrawBuff)->get_buffer();
krn_SetGreyVideoMode(
// Grey rectangle
0, 0, MAX_VIDEO_X, screen_height(grey_screen) + _G(kernel).letter_box_y,
// Color rectangle
x, y, x + ws_get_sprite_width(_GP(seriesHash), 0) - 1, y + ws_get_sprite_height(_GP(seriesHash), 0) - 1);
_G(gameDrawBuff)->release();
// Play the sprite series as a loop
int32 status;
ScreenContext *game_buff_ptr = vmng_screen_find(_G(gameDrawBuff), &status);
_GP(seriesAnim8) = series_play_xy(picName, -1, FORWARD,
x - game_buff_ptr->x1, y - game_buff_ptr->y1, 100, 0, 7, -1);
if (digi_name) {
digi_play(digi_name, 1, 255, digi_trigger);
}
player_set_commands_allowed(true);
CycleEngines(_G(game_bgBuff)->get_buffer(), &(_G(currentSceneDef).depth_table[0]),
_G(screenCodeBuff), (uint8 *)&_G(master_palette)[0], _G(inverse_pal)->get_ptr(), true);
game_pause(true);
_G(inverse_pal)->release();
_G(game_bgBuff)->release();
PauseEngines();
}
void kernel_unexamine_inventory_object(RGB8 *pal, int steps, int delay) {
if (!_GP(seriesAnim8) || _GP(seriesHash) < 0)
return;
player_set_commands_allowed(false);
game_pause(false);
UnpauseEngines();
TerminateMachine(_GP(seriesAnim8));
series_unload(_GP(seriesHash));
_GP(seriesAnim8) = NULL;
_GP(seriesHash) = 0;
Buffer *grey_screen = _G(gameDrawBuff)->get_buffer();
krn_SetGreyVideoMode(0, 0, MAX_VIDEO_X, screen_height(grey_screen) + _G(kernel).letter_box_y, -1, -1, -1, -1);
_G(gameDrawBuff)->release();
krn_pal_game_task();
krn_fade_from_grey(pal, steps, delay, TO_COLOR);
krn_pal_game_task();
// set in kernel_examine_inventory_object (above)
kernel_trigger_dispatch(_GP(myFadeTrigger));
// gr_pal_set(master_palette);
RestoreScreens(0, 0, MAX_VIDEO_X, MAX_VIDEO_Y);
_G(currentSceneDef).hotspots = _GP(exam_saved_hotspots);
interface_show();
AddSystemHotkey(KEY_ESCAPE, remember_esc_key);
}
// This is an inplace remap
// _GP(fadeToMe) must already have been set up to correspond to the image on the screen
void remap_buffer_with_luminance_map(Buffer *src, int32 x1, int32 y1, int32 x2, int32 y2) {
uint8 *ptr;
int32 x, y;
if ((!src) || (!src->data)) return;
if ((x2 - x1 < 0) || (y2 - y1 < 0)) return;
if (x2 - x1 + 1 > src->W) x2 = src->W - 1;
if (y2 - y1 + 1 > src->h) y2 = src->h - 1;
x2 -= x1;
y2 -= y1;
for (y = 0; y <= y2; y++) {
ptr = &src->data[(y + y1) * src->stride + x1];
for (x = 0; x <= x2; x++) // for each pixel in row
// remap the greyed out pixel to the closest grey in GREY_START to GREY_END range
// shift right 3, takes a 255 value and makes it out of 32 (the number of greys in reduced grey ramp)
ptr[x] = (uint8)(GREY_START + (_GP(fadeToMe)[ptr[x]].g >> 3)); // MattP use green instead of red cause we're having a green screen
if (!(y & 0xff)) {
_G(digi).task();
_G(midi).task();
}
}
}
void krn_SetGreyVideoMode(int32 grey_x1, int32 grey_y1, int32 grey_x2, int32 grey_y2, int32 color_x1, int32 color_y1, int32 color_x2, int32 color_y2) {
_GP(greyAreaX1) = grey_x1;
_GP(greyAreaY1) = grey_y1;
_GP(greyAreaX2) = grey_x2;
_GP(greyAreaY2) = grey_y2;
_GP(colorAreaX1) = color_x1;
_GP(colorAreaY1) = color_y1;
_GP(colorAreaX2) = color_x2;
_GP(colorAreaY2) = color_y2;
_GP(greyVideoMode) = true;
}
void krn_UnsetGreyVideoMode() {
_GP(greyAreaX1) = -1;
_GP(greyAreaY1) = -1;
_GP(greyAreaX2) = -1;
_GP(greyAreaY2) = -1;
_GP(colorAreaX1) = -1;
_GP(colorAreaY1) = -1;
_GP(colorAreaX2) = -1;
_GP(colorAreaY2) = -1;
_GP(greyVideoMode) = false;
}
bool krn_GetGreyMode() {
return _GP(greyVideoMode);
}
void krn_UpdateGreyArea(Buffer *greyOutThisBuffer, int32 scrnX, int32 scrnY, int32 greyX1, int32 greyY1, int32 greyX2, int32 greyY2) {
bool finished;
int32 x1, y1, x2, y2;
if ((!_GP(greyVideoMode)) || (!greyOutThisBuffer) || (!greyOutThisBuffer->data)) {
return;
}
x1 = imath_max(greyX1 + scrnX, _GP(greyAreaX1));
y1 = imath_max(greyY1 + scrnY, _GP(greyAreaY1));
x2 = imath_min(greyX2 + scrnX, _GP(greyAreaX2));
y2 = imath_min(greyY2 + scrnY, _GP(greyAreaY2));
if ((x1 > x2) || (y1 > y2)) return;
finished = false;
if (!finished) {
if (y1 < _GP(colorAreaY1)) {
remap_buffer_with_luminance_map(greyOutThisBuffer,
x1 - scrnX, y1 - scrnY, x2 - scrnX, imath_min(y2, _GP(colorAreaY1) - 1) - scrnY);
y1 = imath_min(y2, _GP(colorAreaY1));
if (y1 >= y2) finished = true;
}
}
if (!finished) {
if (y2 > _GP(colorAreaY2)) {
remap_buffer_with_luminance_map(greyOutThisBuffer,
x1 - scrnX, imath_max(y1, _GP(colorAreaY2) + 1) - scrnY, x2 - scrnX, y2 - scrnY);
y2 = imath_max(y1, _GP(colorAreaY2));
if (y1 >= y2) finished = true;
}
}
if (!finished) {
if (x1 < _GP(colorAreaX1)) {
remap_buffer_with_luminance_map(greyOutThisBuffer,
x1 - scrnX, y1 - scrnY, imath_min(x2, _GP(colorAreaX1) - 1) - scrnX, y2 - scrnY);
x1 = imath_min(x2, _GP(colorAreaX1));
if (x1 >= x2) finished = true;
}
}
if (!finished) {
if (x2 > _GP(colorAreaX2)) {
remap_buffer_with_luminance_map(greyOutThisBuffer,
imath_max(x1, _GP(colorAreaX2) + 1) - scrnX, y1 - scrnY, x2 - scrnX, y2 - scrnY);
}
}
}
void krn_ChangeBufferLuminance(Buffer *target, int32 percent) {
int32 x, y, r, g, b, i;
uint8 *inverse_palette, pixel, *tempPtr;
frac16 fracPercent;
RGB8 *pal;
uint8 luminancePal[256];
// Paremeter verification
if ((!target) || (!target->data)) {
return;
}
@ -46,17 +527,17 @@ void krn_ChangeBufferLuminance(Buffer *target, int32 percent) {
return;
}
//calculate the frac16 form of the percent
// Calculate the frac16 form of the percent
fracPercent = (percent * 255) / 100;
//get the palette and the inverse palette
// Get the palette and the inverse palette
pal = &_G(master_palette)[0];
inverse_palette = _G(inverse_pal)->get_ptr();
if ((!pal) || (!inverse_palette)) {
return;
}
//calculate the luminance Pal table
// Calculate the luminance Pal table
for (i = 0; i < 256; i++) {
r = ((((pal[i].r * fracPercent) >> 10) >> 1)) & 0x1f;
g = ((((pal[i].g * fracPercent) >> 10) >> 1)) & 0x1f;
@ -64,8 +545,8 @@ void krn_ChangeBufferLuminance(Buffer *target, int32 percent) {
luminancePal[i] = inverse_palette[(r << 10) + (g << 5) + b];
}
// note: this loop should be y0 to y1, x0 to x1, not a stride*h loop.
//loop through every pixel replacing it with the index into the luminance table
// Note: this loop should be y0 to y1, x0 to x1, not a stride*h loop.
// Loop through every pixel replacing it with the index into the luminance table
tempPtr = target->data;
for (y = 0; y < target->h; y++) {
for (x = 0; x < target->stride; x++) {
@ -78,4 +559,340 @@ void krn_ChangeBufferLuminance(Buffer *target, int32 percent) {
_G(inverse_pal)->release();
}
static void pal_fade_callback(frac16 myMessage) {
_G(pal_fade_in_progress) = false;
kernel_trigger_dispatch((uint32)myMessage);
}
void pal_fade_init(RGB8 *origPalette, int32 firstPalEntry, int32 lastPalEntry,
int32 targetPercent, int32 numTicks, uint32 triggerNum) {
if ((!origPalette) || (firstPalEntry < 0) || (lastPalEntry > 255) || (firstPalEntry > lastPalEntry))
return;
if ((targetPercent < 0) || (targetPercent > 100))
return;
_GP(myFadeReq) = true;
_GP(myFadeFinished) = false;
_GP(myFadeStartTime) = timer_read_60();
_GP(myFadeEndDelayTime) = timer_read_60();
_GP(myFadeStartIndex) = firstPalEntry;
_GP(myFadeEndIndex) = lastPalEntry;
_GP(myFadeEndTime) = _GP(myFadeStartTime) + numTicks;
_GP(myFadeTrigger) = kernel_trigger_create(triggerNum);
_GP(myFadeStartPercentFrac) = _GP(myFadeCurrPercentFrac);
_GP(myFadePercentFrac) = DivSF16(targetPercent << 16, 0x640000);
// Disable_end_user_hot_keys();
_G(pal_fade_in_progress) = true;
}
static void pal_fade_update(RGB8 *origPalette) {
int32 i, currTime;
frac16 tempFrac, tempFrac2;
currTime = timer_read_60();
if (currTime >= _GP(myFadeEndDelayTime)) { // If the delay has expired, fade more
if (currTime >= _GP(myFadeEndTime)) {
tempFrac2 = _GP(myFadePercentFrac);
_GP(myFadeStartPercentFrac) = _GP(myFadePercentFrac);
_GP(myFadeFinished) = true;
} else if (currTime <= _GP(myFadeStartTime)) return;
else {
tempFrac = DivSF16((currTime - _GP(myFadeStartTime)) << 16, (_GP(myFadeEndTime) - _GP(myFadeStartTime)) << 16);
tempFrac2 = MulSF16(tempFrac, _GP(myFadePercentFrac) - _GP(myFadeStartPercentFrac)) + _GP(myFadeStartPercentFrac);
}
_GP(myFadeCurrPercentFrac) = tempFrac2;
for (i = _GP(myFadeStartIndex); i <= _GP(myFadeEndIndex); i++) {
_GP(myFXPalette)[i].r = (Byte)(MulSF16(origPalette[i].r << 16, tempFrac2) >> 16);
_GP(myFXPalette)[i].g = (Byte)(MulSF16(origPalette[i].g << 16, tempFrac2) >> 16);
_GP(myFXPalette)[i].b = (Byte)(MulSF16(origPalette[i].b << 16, tempFrac2) >> 16);
}
// Recalculate the end delay time again
_GP(myFadeEndDelayTime) = currTime + _GP(myFadeDelayTicks); // Recalculate the end delay time again
// Must reresh the DAC
_GP(myFadeDACrefresh) = true;
}
}
void clear_DAC() {
RGB8 color;
color.r = color.b = color.g = 0;
for (int i = 0; i < 256; i++)
gr_pal_set_entry(i, &color);
}
void pal_fade_set_start(RGB8 *origPalette, int32 percent) {
pal_fade_init(origPalette, _G(kernel).first_fade, 255, percent, 0, (uint)-1);
pal_fade_update(origPalette);
pal_fx_update();
}
static void pal_cycle_callback(frac16 myMessage) {
kernel_trigger_dispatch((uint32)myMessage);
}
void pal_cycle_init(int32 firstPalEntry, int32 lastPalEntry,
int32 delayTicks, int32 totalTicks, uint32 triggerNum) {
if ((firstPalEntry < 0) || (lastPalEntry > 255) || (firstPalEntry > lastPalEntry)) {
// This should generate an error
return;
}
if (delayTicks <= 0) {
// This should generate an error (Nick debug plarg MattP)
return;
}
_GP(myCycleReq) = true;
_GP(myCycleFinished) = false;
_GP(myCycleDelayTicks) = delayTicks;
_GP(myCycleStartTime) = timer_read_60();
_GP(myCycleEndDelayTime) = timer_read_60();
_GP(myCycleStartIndex) = firstPalEntry;
_GP(myCycleEndIndex) = lastPalEntry;
_GP(myCycleTrigger) = kernel_trigger_create(triggerNum); // Returned when _GP(myCycleEndTime) is reached
if (totalTicks > 0) { // If totalTicks > 0, calculate end time
_GP(myCycleEndTime) = _GP(myCycleStartTime) + totalTicks;
_GP(myCycleNeverStopCycling) = false;
} else if (totalTicks < 0) { // If totalTicks < 0, never stop the cycling
_GP(myCycleNeverStopCycling) = true;
} else { // If totalTicks is 0, stop cycling now
_GP(myCycleReq) = false;
_GP(myCycleFinished) = true;
}
}
bool pal_cycle_active() {
return _GP(myCycleReq);
}
void pal_cycle_stop() {
_GP(myCycleReq) = false;
}
void pal_cycle_resume() {
_GP(myCycleReq) = true;
}
static void pal_cycle_update() {
int32 i, currTime;
RGB8 firstColour;
currTime = timer_read_60(); // Get current time
if (_GP(myCycleNeverStopCycling) == false) { // If there is an end time to get to...
if (currTime >= _GP(myCycleEndTime)) { // See if we have reached it
_GP(myCycleFinished) = true; // Mark cycling as finished
return; // Return
}
} else {
// See if we should colour cycle right now
if (currTime >= _GP(myCycleEndDelayTime)) { // If the delay has expired, colour cycle
// Cycle the master palette
firstColour.r = _G(master_palette)[_GP(myCycleStartIndex)].r; // Remember first colour
firstColour.g = _G(master_palette)[_GP(myCycleStartIndex)].g;
firstColour.b = _G(master_palette)[_GP(myCycleStartIndex)].b;
for (i = _GP(myCycleStartIndex); i < _GP(myCycleEndIndex); ++i) { // Shift colours down one in palette
_G(master_palette)[i].r = _G(master_palette)[i + 1].r;
_G(master_palette)[i].g = _G(master_palette)[i + 1].g;
_G(master_palette)[i].b = _G(master_palette)[i + 1].b;
}
_G(master_palette)[_GP(myCycleEndIndex)].r = firstColour.r; // Set last colour to the first colour
_G(master_palette)[_GP(myCycleEndIndex)].g = firstColour.g;
_G(master_palette)[_GP(myCycleEndIndex)].b = firstColour.b;
// Then cycle the FX palette
firstColour.r = _GP(myFXPalette)[_GP(myCycleStartIndex)].r; // Remember first colour
firstColour.g = _GP(myFXPalette)[_GP(myCycleStartIndex)].g;
firstColour.b = _GP(myFXPalette)[_GP(myCycleStartIndex)].b;
for (i = _GP(myCycleStartIndex); i < _GP(myCycleEndIndex); ++i) { // Shift colours down one in palette
_GP(myFXPalette)[i].r = _GP(myFXPalette)[i + 1].r;
_GP(myFXPalette)[i].g = _GP(myFXPalette)[i + 1].g;
_GP(myFXPalette)[i].b = _GP(myFXPalette)[i + 1].b;
}
_GP(myFXPalette)[_GP(myCycleEndIndex)].r = firstColour.r; // Set last colour to the first colour
_GP(myFXPalette)[_GP(myCycleEndIndex)].g = firstColour.g;
_GP(myFXPalette)[_GP(myCycleEndIndex)].b = firstColour.b;
// Recalculate the end delay time again
_GP(myCycleEndDelayTime) = currTime + _GP(myCycleDelayTicks); // Recalculate the end delay time again
// must reresh the DAC
_GP(myCycleDACrefresh) = true;
}
}
}
// pal_fx_update() is called each game loop
//
void pal_fx_update() {
int32 startA = 0, endA = 0, startB = 0, endB = 0, startDAC = 0, endDAC = 0;
if (!_GP(myCycleReq) && !_GP(myFadeReq))
// Crap out quickly if no effects required
return;
// Perform any effect required and track index ranges
if (_GP(myCycleReq)) {
pal_cycle_update(); // Do the cycling (cycles master_palette and _GP(myFXPalette))
if (_GP(myCycleDACrefresh)) { // If it needs the DAC to be refreshed,
startA = _GP(myCycleStartIndex); // remember the range
endA = _GP(myCycleEndIndex);
_GP(myCycleDACrefresh) = false;
}
}
if (_GP(myFadeReq)) {
pal_fade_update(&_G(master_palette)[0]); // Do the fading (sets myFXPalette to faded master_palette)
if (_GP(myFadeDACrefresh)) { // If it needs the DAC to be refreshed,
startB = _GP(myFadeStartIndex); // remember the range
endB = _GP(myFadeEndIndex);
_GP(myFadeDACrefresh) = false;
}
}
// Check ranges to perform minimum calls of gr_pal_set_range() (to minimize snow on monitor due to OUT instructions)
if (endA < startB || endB < startA) { // if A and B ranges don't overlap
if (!(startA == 0 && endA == 0)) // if this is not the degenerate case (just the transparent color)
gr_pal_set_range(&_GP(myFXPalette)[0], startA, endA - startA + 1); // set A range of the DAC
if (!(startB == 0 && endB == 0)) // if this is not the degenerate case (just the transparent color)
gr_pal_set_range(&_GP(myFXPalette)[0], startB, endB - startB + 1); // set B range of the DAC
} else {
// They overlap, so find the extent of the overlap
(startA < startB) ? (startDAC = startA) : (startDAC = startB); // which start is less
(endA > endB) ? (endDAC = endA) : (endDAC = endB); // which end is more
if (!(startDAC == 0 && endDAC == 0)) // if this is not the degenerate case (just the transparent color)
gr_pal_set_range(&_GP(myFXPalette)[0], startDAC, endDAC - startDAC + 1); // set the whole range of the DAC
}
// Turn off flags and call callbacks if effects are finished
if (_GP(myFadeReq) && _GP(myFadeFinished)) {
_GP(myFadeReq) = false;
pal_fade_callback(_GP(myFadeTrigger));
}
if (_GP(myCycleReq) && _GP(myCycleFinished)) {
_GP(myCycleReq) = false;
pal_cycle_callback(_GP(myCycleTrigger));
}
}
//==========================================================================================
//
// DAC_tint_effect() is used to effect the screen colours (not the master palette) temporarily
// until something else updates the DAC e.g. refresh_DAC()
//
void DAC_tint_range(RGB8 *tintColor, int32 percent, int32 firstPalEntry, int32 lastPalEntry, bool transparent) {
int32 i;
int32 r, g, b, dr, dg, db;
RGB8 color, targetColor;
int32 percent_r, percent_g, percent_b;
if ((firstPalEntry < 0) || (lastPalEntry > 255) || (firstPalEntry > lastPalEntry)) {
// this should generate an error (Nick debug plarg MattP)
term_message("*** palette index error");
return;
}
term_message("Colour tint DAC to: %d %d %d, %d percent, range (%d - %d)",
tintColor->r, tintColor->g, tintColor->b, percent, firstPalEntry, lastPalEntry); // debug
percent = DivSF16(percent << 16, 100 << 16); // convert percent to frac16 format
targetColor.r = tintColor->r;
targetColor.g = tintColor->g;
targetColor.b = tintColor->b;
term_message("Doing palette.....");
if (!transparent) {
for (i = firstPalEntry; i <= lastPalEntry; ++i) {
// calculate deltas for RGB's and put them in frac16 format
dr = (targetColor.r - _G(master_palette)[i].r) << 16;
dg = (targetColor.g - _G(master_palette)[i].g) << 16;
db = (targetColor.b - _G(master_palette)[i].b) << 16;
// new = orig + (delta * percent)
r = _G(master_palette)[i].r + (MulSF16(percent, dr) >> 16);
g = _G(master_palette)[i].g + (MulSF16(percent, dg) >> 16);
b = _G(master_palette)[i].b + (MulSF16(percent, db) >> 16);
// check for under/overflow
if (r > 255) r = 255; if (r < 0) r = 0;
if (g > 255) g = 255; if (g < 0) g = 0;
if (b > 255) b = 255; if (b < 0) b = 0;
color.r = (byte)r;
color.g = (byte)g;
color.b = (byte)b;
gr_pal_set_entry(i, &color); // set the new colour to the DAC
}
} else {
// This is for filtering colors. For example, a completely red filter
// (255, 0, 0) will block out the blue and green parts of the palette.
// 50% of the same filter will block out only 50% of the blue and
// green, but leaving all of the rest blue.
for (i = firstPalEntry; i <= lastPalEntry; ++i) {
// Converting rgb to a frac16 ( << 16) dividing by 256 ( >> 8)
// (the range of the palette values)
percent_r = (targetColor.r) << 8;
percent_g = (targetColor.g) << 8;
percent_b = (targetColor.b) << 8;
// This is the difference between the color and the full effect
// of the filter at 100%, as a frac16.
dr = (_G(master_palette)[i].r << 16) - (MulSF16(percent_r, _G(master_palette)[i].r << 16));
dg = (_G(master_palette)[i].g << 16) - (MulSF16(percent_g, _G(master_palette)[i].g << 16));
db = (_G(master_palette)[i].b << 16) - (MulSF16(percent_b, _G(master_palette)[i].b << 16));
// Scaling the effect to the right percentage. This is a frac16.
dr = MulSF16(dr, percent);
dg = MulSF16(dg, percent);
db = MulSF16(db, percent);
// Subtract the result to palette.
r = (_G(master_palette)[i].r - (dr >> 16));
g = (_G(master_palette)[i].g - (dg >> 16));
b = (_G(master_palette)[i].b - (db >> 16));
// check for under/overflow
if (r > 255) r = 255; if (r < 0) r = 0;
if (g > 255) g = 255; if (g < 0) g = 0;
if (b > 255) b = 255; if (b < 0) b = 0;
color.r = (byte)r;
color.g = (byte)g;
color.b = (byte)b;
gr_pal_set_entry(i, &color); // Set new colors to DAC.
}
}
}
void DAC_restore() {
term_message("DAC restored");//debug
gr_pal_set_range(&_G(master_palette)[0], 0, 256);
}
} // namespace M4

View File

@ -23,9 +23,85 @@
#define M4_GRAPHICS_KRN_PAL_H
#include "m4/m4_types.h"
#include "m4/adv_r/adv_hotspot.h"
#include "m4/wscript/ws_machine.h"
namespace M4 {
#define TO_GREY (int32)0
#define TO_COLOR (int32)1
#define TO_BLACK (int32)2
struct KernelPal_Globals {
RGB8 _myFXPalette[256];
bool _myCycleReq = false;
bool _myCycleFinished = true;
bool _myCycleDACrefresh = false;
int32 _myCycleDelayTicks = 6; // 10 times a second
int32 _myCycleStartTime = 0;
int32 _myCycleEndTime = 0;
int32 _myCycleEndDelayTime = 0;
int32 _myCycleStartIndex;
int32 _myCycleEndIndex;
uint32 _myCycleTrigger = 0;
int32 _myCycleNeverStopCycling = false;
bool _myFadeReq = false;
bool _myFadeFinished = true;
bool _myFadeDACrefresh = false;
int32 _myFadeDelayTicks = 3; // 20 times a second
int32 _myFadeStartTime = 0;
int32 _myFadeEndTime = 0;
int32 _myFadeEndDelayTime = 0;
int32 _myFadeStartIndex = 0;
int32 _myFadeEndIndex = 0;
uint32 _myFadeTrigger = 0;
frac16 _myFadeStartPercentFrac = 0x10000;
frac16 _myFadeCurrPercentFrac = 0x10000;
frac16 _myFadePercentFrac = 0;
HotSpotRec *_exam_saved_hotspots = nullptr;
RGB8 *_fadeToMe = nullptr;
RGB8 *_trick = nullptr;
RGB8 *_picPal = nullptr;
int32 _seriesHash = 0;
machine *_seriesAnim8 = nullptr;
uint8 _translation[32]; // Only 32 greys in ramp
int32 _colorAreaX1 = -1;
int32 _colorAreaY1 = -1;
int32 _colorAreaX2 = -1;
int32 _colorAreaY2 = -1;
int32 _greyAreaX1 = -1;
int32 _greyAreaY1 = -1;
int32 _greyAreaX2 = -1;
int32 _greyAreaY2 = -1;
bool _greyVideoMode = false;
};
extern void pal_fade_set_start(RGB8 *origPalette, int32 percent);
extern void pal_fade_init(RGB8 *origPalette, int32 firstPalEntry, int32 lastPalEntry, int32 targetPercent, int32 numTicks, uint32 triggerNum);
extern void pal_cycle_init(int32 firstPalEntry, int32 lastPalEntry, int32 delayTicks, int32 totalTicks, uint32 triggerNum);
extern bool pal_cycle_active(); // Returns true if color cycling is on
extern void pal_cycle_stop(); // Stops color cycling
extern void pal_cycle_resume(); // Starts color cycling
extern void pal_fx_update(); // Handles fading and cycling MattP
extern void kernel_examine_inventory_object(char *picName, RGB8 *pal, int steps, int delay,
int32 x, int32 y, int32 triggerNum, char *digi_name, int32 digi_trigger);
extern void kernel_unexamine_inventory_object(RGB8 *pal, int steps, int delay);
extern void remap_buffer_with_luminance_map(Buffer *src, int32 x1, int32 y1, int32 x2, int32 y2);
extern void krn_SetGreyVideoMode(int32 grey_x1, int32 grey_y1, int32 grey_x2, int32 grey_y2, int32 color_x1, int32 color_y1, int32 color_x2, int32 color_y2);
extern void krn_UnsetGreyVideoMode(void);
extern bool krn_GetGreyMode(void);
extern void krn_UpdateGreyArea(Buffer *greyOutThisBuffer, int32 scrnX, int32 scrnY,
int32 greyX1, int32 greyY1, int32 greyX2, int32 greyY2);
extern void krn_ChangeBufferLuminance(Buffer *target, int32 percent);
} // namespace M4

View File

@ -0,0 +1,35 @@
/* 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/textconsole.h"
#include "m4/graphics/rend.h"
namespace M4 {
void GetUpdateRectangle(int32 x, int32 y, int32 hot_x, int32 hot_y, int32 scale_x, int32 scale_y, int32 Width, int32 Height, M4Rect *UpdateRect) {
error("TODO: GetUpdateRectangle");
}
void render_sprite_to_8BBM(RendGrBuff *Destination, DrawRequestX *dr, RendCell *Frame, M4Rect *ClipRectangle, M4Rect *UpdateRect) {
error("TODO: render_sprite_to_8BBM");
}
} // namespace M4

View File

@ -0,0 +1,68 @@
/* 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/>.
*
*/
#ifndef M4_GRAPHICS_REND_H
#define M4_GRAPHICS_REND_H
#include "m4/m4_types.h"
#include "m4/gui/gui.h"
namespace M4 {
struct RGBcolor {
uint8 b, g, r;
};
struct RendGrBuff {
uint32 Width;
uint32 Height;
void *PixMap;
};
struct DrawRequestX {
int32 x; // X position relative to GrBuff(0, 0)
int32 y; // Y position relative to GrBuff(0, 0)
int32 scale_x; // X scale factor (can be negative for reverse draw)
int32 scale_y; // Y scale factor (can't be negative)
uint8 *depth_map; // Depth code array for destination (doesn't care if srcDepth is 0)
RGBcolor *Pal; // Palette for shadow draw (doesn't care if SHADOW bit is not set in Src.encoding)
uint8 *ICT; // Inverse Color Table (doesn't care if SHADOW bit is not set in Src.encoding)
uint8 depth; // Depth code for source (0 if no depth processing)
};
struct RendCell {
uint32 Pack;
uint32 Stream;
long hot_x;
long hot_y;
uint32 Width;
uint32 Height;
uint32 Comp;
uint32 Reserved[8];
uint8 *data;
};
extern void GetUpdateRectangle(int32 x, int32 y, int32 hot_x, int32 hot_y, int32 scale_x, int32 scale_y, int32 Width, int32 Height, M4Rect *UpdateRect);
extern void render_sprite_to_8BBM(RendGrBuff *Destination, DrawRequestX *dr, RendCell *Frame, M4Rect *ClipRectangle, M4Rect *UpdateRect);
} // namespace M4
#endif

View File

@ -29,8 +29,8 @@
namespace M4 {
struct M4sprite {
struct M4sprite *next;
struct M4sprite *prev;
M4sprite *next;
M4sprite *prev;
int32 x;
int32 y;
int32 w;
@ -39,7 +39,7 @@ struct M4sprite {
int32 yOffset;
uint8 encoding;
uint8 *data;
Handle sourceHandle;
MemHandle sourceHandle;
int32 sourceOffset;
};
@ -60,7 +60,7 @@ struct RectList {
};
struct matte {
struct matte *nextMatte;
matte *nextMatte;
void *myScreen;
int32 x1;
int32 y1;

View File

@ -26,6 +26,8 @@
namespace M4 {
#define MAX_STRING_SIZE 144
#define MAX_STRING_LEN 144
#define MAX_FILENAME_SIZE 144
#define MIN_VIDEO_X 0
#define MIN_VIDEO_Y 0

View File

@ -51,4 +51,8 @@ void DisposeHandle(MemHandle handle) {
free(handle);
}
uint32 MaxMem(Size *growBytes) {
return 7999999;
}
} // namespace M4

View File

@ -28,6 +28,7 @@
namespace M4 {
typedef void **MemHandle;
typedef int32 Size;
inline void HLock(Handle h) {}
inline void HUnLock(Handle h) {}
@ -42,6 +43,7 @@ extern MemHandle MakeNewHandle(size_t size, const Common::String &);
extern bool mem_ReallocateHandle(MemHandle h, size_t size, const Common::String &name);
extern MemHandle NewHandle(size_t size, const Common::String &);
extern void DisposeHandle(MemHandle handle);
extern uint32 MaxMem(Size *growBytes);
} // namespace M4

View File

@ -29,6 +29,7 @@ MODULE_OBJS = \
core/param.o \
core/rooms.o \
core/term.o \
dbg/dbg_wscript.o \
events/mickey.o \
events/mouse_handler.o \
fileio/extensions.o \
@ -45,6 +46,7 @@ MODULE_OBJS = \
graphics/gr_series.o \
graphics/graphics.o \
graphics/krn_pal.o \
graphics/rend.o \
gui/gui_buffer.o \
gui/gui_dialog.o \
gui/gui_item.o \
@ -69,6 +71,7 @@ MODULE_OBJS = \
wscript/ws_machine.o \
wscript/ws_timer.o \
wscript/wscript.o \
wscript/wst_regs.o \
burger/gui/game_menu.o \
burger/gui/gui_cheapo.o \
burger/gui/interface.o \

View File

@ -52,5 +52,36 @@ void Digi::unload(const Common::String &name) {
warning("TODO: Digi::unload");
}
void Digi::task() {
warning("TODO: Digi::task");
}
int32 Digi::play(const char *name, int32 channel, int32 vol, int32 trigger, int32 room_num) {
error("TODO: Digi::play");
return 0;
}
int32 Digi::play_loop(const char *name, int32 channel, int32 vol, int32 trigger, int32 room_num) {
error("TODO: Digi::play_loop");
return 0;
}
void Digi::read_another_chunk() {
warning("TODO: Digi::read_another_chunk");
}
} // namespace Sound
int32 digi_play(const char *name, int32 channel, int32 vol, int32 trigger, int32 room_num) {
return _G(digi).play(name, channel, vol, trigger, room_num);
}
int32 digi_play_loop(const char *name, int32 channel, int32 vol, int32 trigger, int32 room_num) {
return _G(digi).play_loop(name, channel, vol, trigger, room_num);
}
void digi_read_another_chunk() {
return _G(digi).read_another_chunk();
}
} // namespace M4

View File

@ -40,9 +40,27 @@ private:
public:
void preload_sounds(const char **names);
void unload_sounds();
void task();
// digi_play and digi_play_loop play a particular sound file in a given channel,
// at a particular volume. The room_num parameter tells us what directory the sound
// is stored in (all sounds are AIFFs). Trigger is an integer that is fed into
// kernel_dispatch_trigger when the sound has finished playing
// If the sound has been preloaded it will be played from memory, otherwise it will
// be streamed from disk
int32 play(const char *name, int32 channel, int32 vol, int32 trigger, int32 room_num = -1);
int32 play_loop(const char *name, int32 channel, int32 vol, int32 trigger, int32 room_num = -1);
void read_another_chunk();
};
} // namespace Sound
extern int32 digi_play(const char *name, int32 channel, int32 vol, int32 trigger, int32 room_num = -1);
extern int32 digi_play_loop(const char *name, int32 channel, int32 vol, int32 trigger, int32 room_num = -1);
extern void digi_read_another_chunk();
} // namespace M4
#endif

View File

@ -25,5 +25,18 @@
namespace M4 {
namespace Sound {
void Midi::task() {
warning("TODO: Midi::task");
}
void Midi::loop() {
warning("TODO: Midi::loop");
}
} // namespace Sound
void midi_loop() {
_G(midi).loop();
}
} // namespace M4

View File

@ -30,9 +30,14 @@ namespace Sound {
class Midi {
public:
void task();
void loop();
};
} // namespace Sound
extern void midi_loop();
} // namespace M4
#endif

View File

@ -24,6 +24,7 @@
#include "m4/adv_r/adv.h"
#include "m4/adv_r/adv_been.h"
#include "m4/core/errors.h"
#include "m4/dbg/debug.h"
#include "m4/graphics/gr_pal.h"
#include "m4/gui/gui_buffer.h"
#include "m4/gui/gui_dialog.h"
@ -47,6 +48,7 @@ Vars::~Vars() {
game_systems_shutdown();
sysfile_shutdown();
f_stream_Shutdown();
player_been_shutdown();
gui_system_shutdown();
gui_buffer_system_shutdown();
@ -54,6 +56,7 @@ Vars::~Vars() {
mem_stash_shutdown();
param_shutdown();
woodscript_shutdown();
dbg_ws_shutdown();
g_vars = nullptr;
}
@ -80,6 +83,14 @@ bool Vars::init() {
if (!LoadWSAssets("stream script", &_master_palette[0]))
error_show(FL, 'FNF!', "stream script");
grab_fonts();
gr_font_set(_font_inter);
if (_cheat_keys_enabled) {
if (!dbg_ws_init(_kernel.start_up_with_dbg_ws, _font_tiny_prop, _globals))
error(FL, 'DWIF');
}
main_cold_data_init();
create_mouse_watch_dialog();
global_menu_system_init();

View File

@ -42,6 +42,7 @@
#include "m4/fileio/sys_file.h"
#include "m4/graphics/gr_color.h"
#include "m4/graphics/gr_font.h"
#include "m4/graphics/krn_pal.h"
#include "m4/gui/gui_dialog.h"
#include "m4/gui/gui_item.h"
#include "m4/gui/gui_mouse.h"
@ -61,7 +62,7 @@ class Vars;
extern Vars *g_vars;
class Vars : public Mouse_Globals, public WS_Globals, public Timer_Globals {
class Vars : public Mouse_Globals, public Timer_Globals {
private:
void game_systems_initialize(byte flags);
void game_systems_shutdown();
@ -101,9 +102,11 @@ public:
Dialog_Globals _dialog;
Item_Globals _items;
Converstation_Globals _conversations;
WS_Globals _ws;
Triggers _triggers;
Sound::Digi _digi;
Sound::Midi _midi;
KernelPal_Globals _krnPal;
bool _cheating_enabled = false;
bool _cheat_keys_enabled = false;
@ -173,6 +176,7 @@ public:
#define _GV() (*g_vars->getGlobals())
#define _GI() (*g_vars->getInterface())
#define _GW() (*g_vars->getWalker())
#define _GWS(X) _G(ws)._##X
} // namespace M4

File diff suppressed because it is too large Load Diff

View File

@ -28,6 +28,38 @@
namespace M4 {
#define OP_INSTR 0xfe000000
#define OP_FORMAT1 0x01c00000
#define OP_FORMAT2 0x00380000
#define OP_FORMAT3 0x00070000
#define OP_HIGH_DATA 0xffff0000
#define OP_LOW_DATA 0x0000ffff
#define OP_DATA_SIGN 0x8000
#define OP_DATA_VALUE 0x7fff
#define FMT_NOTHING 0
#define FMT_LOCAL_SRC 1
#define FMT_GLOBAL_SRC 2
#define FMT_INT15 3
#define FMT_4_11 4
#define FMT_7_8 5
#define FMT_11_4 6
#define FMT_15_0 7
#define REG_SET_IDX 0x0fff
#define REG_SET_IDX_REG 0x8000
#define LOCAL_FMT 0x7000
#define LOCAL_FMT_PARENT 0x0000
#define LOCAL_FMT_REG 0x1000
#define LOCAL_FMT_DATA 0x2000
#define BRANCH_BR 0
#define BRANCH_BLT 1
#define BRANCH_BLE 2
#define BRANCH_BE 3
#define BRANCH_BNE 4
#define BRANCH_BGE 5
#define BRANCH_BGT 6
struct EOSreq {
EOSreq *next = nullptr;
EOSreq *prev = nullptr;
@ -70,10 +102,29 @@ struct WSCruncher_Globals {
};
extern int32 *ws_GetDataFormats();
extern bool ws_InitCruncher();
extern void ws_KillCruncher();
extern Anim8 *ws_AddAnim8ToCruncher(machine *m, int32 sequHash);
/**
* This procedure assumes a machine has a slot with it's own memory
*/
extern bool ws_ChangeAnim8Program(machine *m, int32 newSequHash);
/**
* This procedure flags the anim8 slot as empty
*/
extern void ws_RemoveAnim8FromCruncher(Anim8 *myAnim8);
extern bool ws_PauseAnim8(Anim8 *myAnim8);
extern bool ws_ResumeAnim8(Anim8 *myAnim8);
extern int32 ws_PreProcessPcode(uint32 **PC, Anim8 *myAnim8);
extern void ws_CrunchAnim8s(int16 *depth_table);
extern void ws_CrunchEOSreqs();
extern bool ws_OnEndSeqRequest(Anim8 *myAnim8, int32 pcOffset, int32 pcCount);
extern void ws_CancelOnEndSeq(Anim8 *myAnim8);
} // End of namespace M4
#endif

View File

@ -19,34 +19,454 @@
*
*/
#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/rend.h"
#include "m4/gui/gui_vmng.h"
#include "m4/vars.h"
#include "m4/m4.h"
namespace M4 {
bool ws_InitHAL() {
_G(deadRectList) = NULL;
_GWS(deadRectList) = nullptr;
return true;
}
void ws_KillHAL() {
vmng_DisposeRectList(&_G(deadRectList));
vmng_DisposeRectList(&_GWS(deadRectList));
}
void ws_DumpMachine(machine *m, Common::WriteStream *logFile) {
Anim8 *myAnim8;
CCB *myCCB;
frac16 *myRegs;
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: %ld\n\tAddress: 0x%08lx\n\n", m->machName, m->myHash, (int32)m));
// If we have an anim8 for this machine
if (m->myAnim8) {
myAnim8 = m->myAnim8;
// Print out the anim8 hash, and physical address
logFile->writeString(Common::String::format("Sequence Hash: %ld\n\tAddress: 0x%08lx\n\n", myAnim8->sequHash, (int32)myAnim8));
// And if this anim8 has registers
if (myAnim8->myRegs) {
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%ld\t%s:\t\t%.2f\t\t0x%08lx\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%ld\tlocal.%ld:\t\t%.2f\t\t0x%08lx\n", i, i - IDX_COUNT, tempFloat, myRegs[i]));
}
}
logFile->writeString(Common::String::format("\n"));
}
// If this anim8 has a CCB
if (myAnim8->myCCB) {
myCCB = myAnim8->myCCB;
logFile->writeString(Common::String::format("Sprite Series Name: %s\tAddress:0x%08lx\tFlags0x%08lx\n", myCCB->seriesName, (uint32)myCCB, myCCB->flags));
logFile->writeString(Common::String::format("\tCurrent Location: (%ld, %ld), (%ld, %ld)\n", myCCB->currLocation->x1, myCCB->currLocation->y1,
myCCB->currLocation->x2, myCCB->currLocation->y2));
logFile->writeString(Common::String::format("\tNew Location: (%ld, %ld), (%ld, %ld)\n", myCCB->newLocation->x1, myCCB->newLocation->y1,
myCCB->newLocation->x2, myCCB->newLocation->y2));
logFile->writeString(Common::String::format("\tscale: %ld\n", myCCB->scaleX));
logFile->writeString(Common::String::format("\tlayer: %ld\n", myCCB->layer));
}
}
}
void ws_Error(machine *m, int32 errorType, trigraph errorCode, const char *errMsg) {
Common::OutSaveFile *logFile;
char description[MAX_STRING_SIZE];
// Find the error description
error_look_up(errorCode, description);
// Open the logFile
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(char *sourceFile, int32 lineNum, const char *fmt, ...) {
Common::OutSaveFile *logFile;
Common::String msgBuff;
va_list ap;
va_start(ap, fmt);
msgBuff == Common::String::vformat(fmt, ap);
va_end(ap);
logFile = g_system->getSavefileManager()->openForSaving("ws_mach.log");
if (logFile) {
logFile->writeString(Common::String::format("Source Code Index: %s:%ld\n", sourceFile, lineNum));
logFile->writeString(Common::String::format("%s\n\n", msgBuff.c_str()));
logFile->finalize();
delete logFile;
}
term_message("Source Code Index: %s:%ld", sourceFile, lineNum);
term_message("%s", msgBuff.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"));
}
void DrawSprite(CCB *myCCB, Anim8 *myAnim8, Buffer *halScrnBuf, GrBuff *screenCodeBuff, uint8 *myPalette, uint8 *ICT,
M4Rect *clipRect, M4Rect *updateRect) {
#ifdef TODO
M4sprite *source;
// Temporary var to prevent excessive dereferences
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 *)((int32) * (source->sourceHandle) + source->sourceOffset);
}
RendGrBuff Destination;
DrawRequestX dr;
RendCell Frame;
Destination.Width = halScrnBuf->stride;
Destination.Height = halScrnBuf->h;
Destination.PixMap = (void *)halScrnBuf->data;
dr.x = myAnim8->myRegs[IDX_X] >> 16;
dr.y = myAnim8->myRegs[IDX_Y] >> 16;
dr.scale_x = myCCB->scaleX;
dr.scale_y = myCCB->scaleY;
dr.depth_map = screenCodeBuff->data;
dr.Pal = (RGBcolor *)myPalette;
dr.ICT = ICT;
dr.depth = myCCB->layer >> 8;
Frame.hot_x = myCCB->source->xOffset;
Frame.hot_y = myCCB->source->yOffset;
Frame.Width = source->w;
Frame.Height = source->h;
if ((!myPalette) || (!ICT)) {
Frame.Comp = (uint32)(source->encoding & 0x7f);
} else {
Frame.Comp = (uint32)source->encoding;
}
Frame.data = source->data;
// And draw the sprite
render_sprite_to_8BBM(&Destination, &dr, &Frame, clipRect, updateRect);
myCCB->flags &= ~CCB_REDRAW;
if (!(myCCB->flags & CCB_DISC_STREAM)) {
//unlock the sprite's handle
HUnLock(source->sourceHandle);
}
#else
error("TODO: DrawSprite");
#endif
}
void ws_DoDisplay(Buffer *background, int16 *depth_table, GrBuff *screenCodeBuff,
uint8 *myPalette, uint8 *ICT, bool updateVideo) {
CCB *myCCB;
ScreenContext *myScreen;
RectList *myRect;
RectList *drawRectList = nullptr;
int32 status, scrnX1, scrnY1;
int32 restoreBgndX1, restoreBgndY1, restoreBgndX2, restoreBgndY2;
Anim8 *myAnim8;
M4Rect *currRect, intersectRect, noClipRect, dummyRect;
bool greyMode;
#ifdef TODO
Buffer drawSpriteBuff;
bool finished;
M4sprite *source;
uint8 myDepth;
M4Rect *newRect;
DrawRequest spriteDrawReq;
#endif
if (((myScreen = vmng_screen_find(_G(gameDrawBuff), &status)) == nullptr) || (status != SCRN_ACTIVE)) {
return;
}
Buffer *halScrnBuf = _G(gameDrawBuff)->get_buffer();
noClipRect.x1 = 0;
noClipRect.y1 = 0;
noClipRect.x2 = halScrnBuf->W - 1;
noClipRect.y2 = halScrnBuf->h - 1;
scrnX1 = myScreen->x1;
scrnY1 = myScreen->y1;
greyMode = krn_GetGreyMode();
// Intialize the drawRectList to the deadRectList
drawRectList = _GWS(deadRectList);
_GWS(deadRectList) = nullptr;
// The drawRectList already 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 (background && 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;
currRect = myCCB->currLocation;
if (myCCB && myCCB->source && (!(myCCB->flags & CCB_NO_DRAW))) {
if (myCCB->flags & CCB_REDRAW) {
// Draw the sprite
DrawSprite(myCCB, myAnim8, halScrnBuf, screenCodeBuff, myPalette, ICT, &noClipRect, currRect);
// Add it's new location to the update list
vmng_AddRectToRectList(&drawRectList, currRect->x1, currRect->y1, currRect->x2, currRect->y2);
} else {
// Loop through the update list, intersect each rect with the sprites
// current location, and update redraw all overlapping areas
myRect = drawRectList;
while (myRect) {
intersectRect.x1 = imath_max(myRect->x1, currRect->x1);
intersectRect.y1 = imath_max(myRect->y1, currRect->y1);
intersectRect.x2 = imath_min(myRect->x2, currRect->x2);
intersectRect.y2 = imath_min(myRect->y2, currRect->y2);
// Now see if there was an intersection
if ((intersectRect.x1 <= intersectRect.x2) && (intersectRect.y1 <= intersectRect.y2)) {
// Draw just the intersected region
DrawSprite(myCCB, myAnim8, halScrnBuf, screenCodeBuff, myPalette, ICT, &intersectRect, &dummyRect);
}
// Next rect
myRect = myRect->next;
}
}
}
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, GrBuff *screenCodes, uint8 *myPalette, uint8 *ICT) {
error("TODO: ws_hal_RefreshWoodscriptBuffer");
}
void GetBezCoeffs(frac16 *ctrlPoints, frac16 *coeffs) {
frac16 x0, x0mult3, x1mult3, x1mult6, x2mult3, x3;
frac16 y0, y0mult3, y1mult3, y1mult6, y2mult3, y3;
x0 = ctrlPoints[0];
x0mult3 = (x0 << 1) + x0;
x1mult3 = (ctrlPoints[2] << 1) + ctrlPoints[2];
x1mult6 = x1mult3 << 1;
x2mult3 = (ctrlPoints[4] << 1) + ctrlPoints[4];
x3 = ctrlPoints[6];
y0 = ctrlPoints[1];
y0mult3 = (y0 << 1) + y0;
y1mult3 = (ctrlPoints[3] << 1) + ctrlPoints[3];
y1mult6 = y1mult3 << 1;
y2mult3 = (ctrlPoints[5] << 1) + ctrlPoints[5];
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])))));
return;
}
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) {
error("TODO: KillCCB");
#ifdef TODO
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(&_G(deadRectList), myCCB->maxArea->x1, myCCB->maxArea->y1,
vmng_AddRectToRectList(&_GWS(deadRectList), myCCB->maxArea->x1, myCCB->maxArea->y1,
myCCB->maxArea->x2, myCCB->maxArea->y2);
} else {
vmng_AddRectToRectList(&_G(deadRectList), myCCB->currLocation->x1, myCCB->currLocation->y1,
vmng_AddRectToRectList(&_GWS(deadRectList), myCCB->currLocation->x1, myCCB->currLocation->y1,
myCCB->currLocation->x2, myCCB->currLocation->y2);
}
}
@ -54,19 +474,83 @@ void KillCCB(CCB *myCCB, bool restoreFlag) {
ws_CloseSSstream(myCCB);
}
if (myCCB->currLocation) {
mem_free((void *)myCCB->currLocation);
mem_free(myCCB->currLocation);
}
if (myCCB->newLocation) {
mem_free((void *)myCCB->newLocation);
mem_free(myCCB->newLocation);
}
if (myCCB->maxArea) {
mem_free((void *)myCCB->maxArea);
mem_free(myCCB->maxArea);
}
if (myCCB->source) {
mem_free((char *)myCCB->source);
mem_free(myCCB->source);
}
mem_free((void *)myCCB);
#endif
mem_free(myCCB);
}
void Cel_msr(Anim8 *myAnim8) {
CCB *myCCB;
frac16 *myRegs;
int32 scaler;
if (!myAnim8) {
error_show(FL, 'WSAI');
}
myCCB = myAnim8->myCCB;
if ((!myCCB) || (!myCCB->source)) {
error_show(FL, 'WSIC');
}
if ((myCCB->source->w == 0) || (myCCB->source->h == 0)) {
return;
}
myRegs = myAnim8->myRegs;
if (!myRegs) {
error_show(FL, 'WSAI');
}
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

View File

@ -24,17 +24,47 @@
#define M4_WSCRIPT_WS_HAL_H
#include "m4/wscript/ws_machine.h"
#include "m4/wscript/ws_cruncher.h"
namespace M4 {
#define CCB_SKIP 0x0001
#define CCB_HIDE 0x0002
#define CCB_REDRAW 0x0004
#define CCB_STREAM 0x0008
#define CCB_DISC_STREAM 0x0010
#define CCB_NO_DRAW (CCB_SKIP | CCB_HIDE)
#define ERR_INTERNAL 0
#define ERR_SEQU 1
#define ERR_MACH 2
struct WSHal_Globals {
RectList *_deadRectList;
int32 _pcOffsetOld;
};
extern bool ws_InitHAL();
extern void ws_KillHAL();
extern void ws_DoDisplay(Buffer *background, int16 *depth_table, GrBuff *screenCodeBuff,
uint8 *myPalette, uint8 *ICT, bool updateVideo);
extern void ws_hal_RefreshWoodscriptBuffer(cruncher *myCruncher, Buffer *background, int16 *depth_table, GrBuff *screenCodes, uint8 *myPalette, uint8 *ICT);
extern void GetBezCoeffs(frac16 *ctrlPoints, frac16 *coeffs);
extern void GetBezPoint(frac16 *x, frac16 *y, frac16 *coeffs, frac16 tVal);
extern bool InitCCB(CCB *myCCB);
extern void HideCCB(CCB *myCCB);
extern void ShowCCB(CCB *myCCB);
//extern void SetLastCCB(CCB *myCCB);
extern void MoveCCB(CCB *myCCB, frac16 deltaX, frac16 deltaY);
extern void KillCCB(CCB *myCCB, bool restoreFlag);
extern void Cel_msr(Anim8 *myAnim8);
extern void ws_OverrideCrunchTime(machine *m);
extern bool CheckAddr();
extern void ws_Error(machine *m, int32 errorType, quadchar errorCode, const char *errMsg);
extern void ws_DumpMachine(machine *m);
extern void ws_LogErrorMsg(char *sourceFile, int32 lineNum, char *fmt, ...);
} // End of namespace M4

File diff suppressed because it is too large Load Diff

View File

@ -66,13 +66,13 @@ struct WSLoad_Globals {
char **_globalDATAnames = nullptr;
char **_globalCELSnames = nullptr;
Handle *_globalMACHHandles = nullptr;
MemHandle *_globalMACHHandles = nullptr;
int32 *_globalMACHoffsets = nullptr;
Handle *_globalSEQUHandles = nullptr;
MemHandle *_globalSEQUHandles = nullptr;
int32 *_globalSEQUoffsets = nullptr;
Handle *_globalDATAHandles = nullptr;
MemHandle *_globalDATAHandles = nullptr;
int32 *_globalDATAoffsets = nullptr;
Handle *_globalCELSHandles = nullptr;
MemHandle *_globalCELSHandles = nullptr;
int32 *_globalCELSoffsets = nullptr;
int32 *_globalCELSPaloffsets = nullptr;
};
@ -81,20 +81,19 @@ extern bool InitWSAssets();
extern bool ClearWSAssets(uint32 assetType, int32 minHash, int32 maxHash);
extern void ShutdownWSAssets();
extern bool ws_CELSIntegrity(int32 minHash, int32 maxHash);
extern bool LoadWSAssets(const char *wsAssetName, RGB8 *myPalette);
extern int32 AddWSAssetCELS(const char *wsAssetName, int32 hash, RGB8 *myPalette);
extern uint32 *FindSpriteSource(uint32 *celsPtr, int32 index);
extern M4sprite *GetWSAssetSprite(char *spriteName, uint32 hash, uint32 index, M4sprite *mySprite, bool *streamSeries);
extern CCB *GetWSAssetCEL(uint32 hash, uint32 index, CCB *myCCB);
extern int32 GetWSAssetCELCount(uint32 hash);
extern int32 GetWSAssetCELFrameRate(uint32 hash);
extern int32 GetWSAssetCELPixSpeed(uint32 hash);
extern int32 ws_get_sprite_width(uint32 hash, int32 index);
extern int32 ws_get_sprite_height(uint32 hash, int32 index);
extern Handle ws_GetSEQU(uint32 hash, int32 *numLocalVars, int32 *offset);
extern Handle ws_GetMACH(uint32 hash, int32 *numStates, int32 *stateTableOffset, int32 *machInstrOffset);
extern Handle ws_GetDATA(uint32 hash, uint32 index, int32 *rowOffset);
extern MemHandle ws_GetSEQU(uint32 hash, int32 *numLocalVars, int32 *offset);
extern MemHandle ws_GetMACH(uint32 hash, int32 *numStates, int32 *stateTableOffset, int32 *machInstrOffset);
extern MemHandle ws_GetDATA(uint32 hash, uint32 index, int32 *rowOffset);
extern int32 ws_GetDATACount(uint32 hash);
extern int32 GetSSHeaderInfo(Common::SeekableReadStream *stream, uint32 **data, RGB8 *myPalette);
extern bool ws_GetSSMaxWH(MemHandle ssHandle, int32 ssOffset, int32 *maxW, int32 *maxH);

File diff suppressed because it is too large Load Diff

View File

@ -97,11 +97,11 @@ struct Anim8 {
Anim8 *behind = nullptr;
Anim8 *myParent = nullptr; // The parent anim8
int32 sequHash = 0; // The current sequence Hash = 0;
Handle sequHandle = nullptr; // The sequence Handle
MemHandle sequHandle = nullptr; // The sequence Handle
int32 pcOffset = 0; // The offset into the sequence of the current PC
CCB *myCCB = nullptr;
int32 dataHash = 0; // The array of data
Handle dataHandle = nullptr;
MemHandle dataHandle = nullptr;
int32 dataOffset = 0;
int32 startTime = 0;
int32 switchTime = 0;
@ -125,7 +125,7 @@ struct machine {
uint32 myHash = 0;
uint32 machID = 0;
char *machName = nullptr;
Handle machHandle = 0;
MemHandle machHandle = 0;
int32 machInstrOffset = 0;
int32 stateTableOffset = 0;
int32 curState = 0;
@ -134,7 +134,7 @@ struct machine {
Anim8 *myAnim8 = nullptr;
Anim8 *parentAnim8 = nullptr;
int32 dataHash = 0;
Handle dataHandle = 0;
MemHandle dataHandle = 0;
int32 dataOffset = 0;
int32 targetCount = 0;
struct machine *msgReplyXM = nullptr;
@ -168,11 +168,26 @@ struct WSMachine_Globals {
// Used for processing pCodes
frac16 *_ws_globals = nullptr;
void *_addrExists = nullptr;
};
extern bool ws_Initialize(frac16 *theGlobals);
extern void ws_Shutdown();
extern void TerminateMachinesByHash(int32 machHash);
extern void PauseEngines();
extern void UnpauseEngines();
extern void AddPauseTime(int32 myTime);
void CycleEngines(Buffer *cleanBackground, int16 *depth_table, GrBuff *screenCodes,
uint8 *myPalette, uint8 *ICT, bool updateVideo);
void ws_RefreshWoodscriptBuffer(Buffer *cleanBackground, int16 *depth_table, GrBuff *screenCodes, uint8 *myPalette, uint8 *ICT);
void TerminateMachine(machine *m);
void TerminateMachinesByHash(uint32 machHash);
bool VerifyMachineExists(machine *m);
int32 ws_KillMachines();
void ws_StepWhile(machine *m, int32 pcOffset, int32 pcCount);
void IntoTheState(machine *m);
machine *TriggerMachineByHash(int32 myHash, Anim8 *parentAnim8, int32 dataHash, int32 dataRow, MessageCB CintrMsg, bool debug, const char *machName);
/**
* This proc is what allows a machine to send a message to another machine(s)
@ -180,6 +195,9 @@ extern void TerminateMachinesByHash(int32 machHash);
extern void SendWSMessage(uint32 msgHash, frac16 msgValue, machine *recvM,
uint32 machHash, machine *sendM, int32 msgCount);
#define kernel_spawn_machine(name,hash,callback) TriggerMachineByHash(hash, NULL, -1, -1, callback, FALSE, (char*)name)
#define kernel_terminate_machine(m) TerminateMachine(m)
} // End of namespace M4
#endif

View File

@ -27,18 +27,18 @@ namespace M4 {
static void dispose_timeRequest(onTimeReq *timeReq);
bool ws_InitWSTimer(void) {
_G(firstTimeReq) = nullptr;
_GWS(firstTimeReq) = nullptr;
return true;
}
void ws_KillTime() {
onTimeReq *tempTime;
tempTime = _G(firstTimeReq);
tempTime = _GWS(firstTimeReq);
while (tempTime) {
_G(firstTimeReq) = _G(firstTimeReq)->next;
_GWS(firstTimeReq) = _GWS(firstTimeReq)->next;
dispose_timeRequest(tempTime);
tempTime = _G(firstTimeReq);
tempTime = _GWS(firstTimeReq);
}
}
@ -48,4 +48,17 @@ static void dispose_timeRequest(onTimeReq *timeReq) {
}
}
void ws_MakeOnTimeReq(int32 wakeUpTime, machine *myXM, int32 pcOffset, int32 pcCount) {
error("TODO: ws_MakeOnTimeReq");
}
void ws_CancelOnTimeReqs(machine *m) {
error("TODO: ws_CancelOnTimeReqs");
}
void ws_CheckTimeReqs(int32 curTime) {
error("TODO: ws_CheckTimeReqs");
}
} // End of namespace M4

View File

@ -0,0 +1,122 @@
/* 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 "m4/wscript/wst_regs.h"
namespace M4 {
const char *myRegLabels[IDX_COUNT] = {
"timer", //0
"tag", //1
"layer", //2
"w", //3
"h", //4
"x", //5
"y", //6
"s", //7
"r", //8
"cels_hash", //9
"cels_index", //10
"cels_count", //11
"cels_frame_rate", //12
"cels_pix_speed", //13
"targ_s", //14
"targ_r", //15
"targ_x", //16
"targ_y", //17
"delta_s", //18
"delta_r", //19
"delta_x", //20
"delta_y", //21
"velocity", //22
"theta", //23
"ztemp1", //24
"ztemp2", //25
"ztemp3", //26
"ztemp4", //27
"ztemp5", //28
"ztemp6", //29
"ztemp7", //30
"ztemp8", //31
"mach_id" //32
};
const char *myGlobLabels[GLOB_COUNT] = {
"***SYSTEM - TIME",
"***SYSTEM - WATCHDOG",
"min_y",
"max_y",
"min_scale",
"max_scale",
"scaler",
"g_temp1",
"g_temp2",
"g_temp3",
"g_temp4",
"g_temp5",
"g_temp6",
"g_temp7",
"g_temp8",
"g_temp9",
"g_temp10",
"g_temp11",
"g_temp12",
"g_temp13",
"g_temp14",
"g_temp15",
"g_temp16",
"g_temp17",
"g_temp18",
"g_temp19",
"g_temp20",
"g_temp21",
"g_temp22",
"g_temp23",
"g_temp24",
"g_temp25",
"g_temp26",
"g_temp27",
"g_temp28",
"g_temp29",
"g_temp30",
"g_temp31",
"g_temp32",
};
const char *tagLabels[TAG_COUNT] = {
"tag_none",
"tag_targs",
"tag_bez",
"tag_deltas",
"tag_vectors",
"tag_text",
"tag_move_cel",
"tag_map_cel"
};
} // End of namespace M4

View File

@ -85,9 +85,11 @@ enum {
#define TAG_MOVE_CEL 0x00004000
#define TAG_MAP_CEL 0x00002000
extern char *myRegLabels[];
extern char *myGlobLabels[];
extern char *tagLabels[];
#define GLOB_COUNT 39
extern const char *myRegLabels[];
extern const char *myGlobLabels[];
extern const char *tagLabels[];
} // End of namespace M4