mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-23 12:44:02 +00:00
CRYO: Lost Eden game engine initial commit
This commit is contained in:
parent
e25bac9690
commit
ecf0d04104
3
engines/cryo/CLError.c
Normal file
3
engines/cryo/CLError.c
Normal file
@ -0,0 +1,3 @@
|
||||
#include "cryolib.h"
|
||||
|
||||
short __debug, __libError, __osError;
|
874
engines/cryo/CLHNM.c
Normal file
874
engines/cryo/CLHNM.c
Normal file
@ -0,0 +1,874 @@
|
||||
#include "cryolib.h"
|
||||
|
||||
static short safe_palette = 0;
|
||||
static short pred_r = 0, pred_l = 0;
|
||||
static short use_adpcm = 0;
|
||||
static float hnm_rate = 0.0;
|
||||
static float next_frame_time = 0.0;
|
||||
static float expected_frame_time = 0.0;
|
||||
static float time_drift = 0.0;
|
||||
static short use_mono = 0;
|
||||
static short use_sound = 0;
|
||||
static short use_sound_sync = 0;
|
||||
static short pending_sounds = 0;
|
||||
static short sound_started = 0;
|
||||
static short preserve_color0 = 0;
|
||||
static soundchannel_t *soundChannel_adpcm = 0;
|
||||
static soundgroup_t *soundGroup_adpcm = 0;
|
||||
static soundchannel_t *soundChannel = 0;
|
||||
static soundgroup_t *soundGroup = 0;
|
||||
static void (*custom_chunk_handler)(unsigned char *buffer, int size, short id, char h6, char h7) = 0;
|
||||
static short use_preload = 0;
|
||||
static short decomp_table[256];
|
||||
|
||||
void CLHNM_Desentrelace320(unsigned char *frame_buffer, unsigned char *final_buffer, unsigned short height);
|
||||
|
||||
void CLHNM_DecompLempelZiv(unsigned char *buffer, unsigned char *output)
|
||||
{
|
||||
unsigned char *inp = buffer;
|
||||
unsigned char *out = output;
|
||||
|
||||
unsigned int queue = 0;
|
||||
int qpos = -1;
|
||||
|
||||
//TODO: fix for BE
|
||||
#define GetBit() ( 1 & ( (qpos >= 0) ? (queue >> qpos--) : (queue = *(unsigned int*)((inp += 4) - 4)) >> ((qpos = 30) + 1) ) )
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (GetBit())
|
||||
{
|
||||
*out++ = *inp++;
|
||||
}
|
||||
else
|
||||
{
|
||||
int l, o;
|
||||
if (GetBit())
|
||||
{
|
||||
l = *inp & 7;
|
||||
o = *(unsigned short*)inp >> 3; inp += 2;
|
||||
o -= 8192;
|
||||
if (!l)
|
||||
l = *inp++;
|
||||
if (!l)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
l = GetBit() * 2 + GetBit();
|
||||
o = *(inp++) - 256;
|
||||
}
|
||||
l += 2;
|
||||
while (l--)
|
||||
{
|
||||
*out = *(out + o); out++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef GetBit
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void CLHNM_DecompUBA(unsigned char *output, unsigned char *curr_buffer, unsigned char *prev_buffer,
|
||||
unsigned char *input, int width, char flags)
|
||||
{
|
||||
unsigned int code;
|
||||
char mode, count, color;
|
||||
unsigned short offs;
|
||||
unsigned char *ref;
|
||||
unsigned char *out_start = output;
|
||||
unsigned char swap;
|
||||
int shft1, shft2;
|
||||
// return;
|
||||
if((flags & 1) == 0)
|
||||
{
|
||||
//HNM4 classic
|
||||
int twolinesabove = -(width * 2);
|
||||
for(;;)
|
||||
{
|
||||
code = PLE32(input) & 0xFFFFFF; //input++;
|
||||
count = code & 0x1F;
|
||||
if(count)
|
||||
{
|
||||
input += 3;
|
||||
mode = (code >> 5) & 0xF;
|
||||
offs = code >> 9;
|
||||
//
|
||||
swap = mode >> 3;
|
||||
ref = ((mode & 1) ? prev_buffer : curr_buffer) + (output - out_start) + (offs * 2) - 32768;
|
||||
if (mode & 2)
|
||||
{
|
||||
// ref += twolinesabove;
|
||||
shft1 = twolinesabove + 1;
|
||||
shft2 = 0;
|
||||
//swap ^= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
shft1 = 0;
|
||||
shft2 = 1;
|
||||
}
|
||||
while(count--)
|
||||
{
|
||||
unsigned char b0 = ref[shft1];
|
||||
unsigned char b1 = ref[shft2];
|
||||
output[swap] = b0;
|
||||
output[swap ^ 1] = b1;
|
||||
output += 2;
|
||||
ref += (mode & 4) ? -2 : 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
input++;
|
||||
mode = code & 0xFF; // bits 0..4 are zero
|
||||
switch(mode)
|
||||
{
|
||||
case 0:
|
||||
*(output++) = *(input++);
|
||||
*(output++) = *(input++);
|
||||
break;
|
||||
case 0x20:
|
||||
output += 2 * *(input++);
|
||||
break;
|
||||
case 0x40:
|
||||
output += 2 * (code >> 8); input += 2;
|
||||
break;
|
||||
case 0x60:
|
||||
count = *(input++);
|
||||
color = *(input++);
|
||||
while(count--)
|
||||
{
|
||||
*(output++) = color;
|
||||
*(output++) = color;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0);
|
||||
//HNM4 hires
|
||||
for(;;)
|
||||
{
|
||||
code = PLE32(input) & 0xFFFFFF; input++;
|
||||
count = code & 0x3F;
|
||||
if(count)
|
||||
{
|
||||
mode = (code >> 5) & 0xF;
|
||||
offs = code >> 9;
|
||||
//
|
||||
}
|
||||
else
|
||||
{
|
||||
mode = code & 0xFF; // bits 0..5 are zero
|
||||
switch(mode)
|
||||
{
|
||||
case 0x00:
|
||||
output += *input++;
|
||||
break;
|
||||
case 0x40:
|
||||
*output++ = *input++;
|
||||
*(output++ + width) = *input++;
|
||||
break;
|
||||
case 0x80:
|
||||
output += width;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CLHNM_Init()
|
||||
{
|
||||
use_preload = 0;
|
||||
custom_chunk_handler = 0;
|
||||
preserve_color0 = 0;
|
||||
CLNoError;
|
||||
}
|
||||
|
||||
void CLHNM_Done()
|
||||
{
|
||||
CLNoError;
|
||||
}
|
||||
|
||||
void CLHNM_SetupTimer(float rate)
|
||||
{
|
||||
hnm_rate = 100.0 / rate;
|
||||
CLNoError;
|
||||
}
|
||||
|
||||
void CLHNM_WaitLoop(hnm_t *hnm)
|
||||
{
|
||||
expected_frame_time += hnm_rate;
|
||||
next_frame_time = expected_frame_time - time_drift;
|
||||
if(use_sound_sync && TimerTicks > 1000.0 + next_frame_time)
|
||||
use_sound = 0;
|
||||
while(TimerTicks < next_frame_time) ; // waste time
|
||||
time_drift = TimerTicks - next_frame_time;
|
||||
}
|
||||
|
||||
void CLHNM_SetupSound(short numSounds, short arg4, short sampleSize, float rate, short mode)
|
||||
{
|
||||
soundChannel = CLSoundChannel_New(mode);
|
||||
soundGroup = CLSoundGroup_New(numSounds, arg4, sampleSize, rate, mode);
|
||||
if(sampleSize == 16)
|
||||
CLSoundGroup_Reverse16All(soundGroup);
|
||||
}
|
||||
|
||||
void CLHNM_SetupSoundADPCM(short numSounds, short arg4, short sampleSize, float rate, short mode)
|
||||
{
|
||||
soundChannel_adpcm = CLSoundChannel_New(mode);
|
||||
soundGroup_adpcm = CLSoundGroup_New(numSounds, arg4, sampleSize, rate, mode);
|
||||
}
|
||||
|
||||
void CLHNM_CloseSound()
|
||||
{
|
||||
if(soundChannel)
|
||||
{
|
||||
CLSoundChannel_Stop(soundChannel);
|
||||
CLSoundChannel_Free(soundChannel);
|
||||
soundChannel = 0;
|
||||
}
|
||||
if(soundGroup)
|
||||
{
|
||||
CLSoundGroup_Free(soundGroup);
|
||||
soundGroup = 0;
|
||||
}
|
||||
if(soundChannel_adpcm)
|
||||
{
|
||||
CLSoundChannel_Stop(soundChannel_adpcm);
|
||||
CLSoundChannel_Free(soundChannel_adpcm);
|
||||
soundChannel = 0;
|
||||
}
|
||||
if(soundGroup_adpcm)
|
||||
{
|
||||
CLSoundGroup_Free(soundGroup_adpcm);
|
||||
soundGroup = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void CLHNM_SetForceZero2Black(short forceblack)
|
||||
{
|
||||
preserve_color0 = forceblack;
|
||||
}
|
||||
|
||||
hnm_t* CLHNM_New(int preload_size)
|
||||
{
|
||||
hnm_t *hnm;
|
||||
short i;
|
||||
|
||||
preload_size = 0; //TODO: let's ignore it for now
|
||||
|
||||
CLBeginCheck;
|
||||
hnm = (hnm_t*)CLMemory_Alloc(sizeof(*hnm));
|
||||
CLCheckError();
|
||||
if(hnm)
|
||||
{
|
||||
if(preload_size)
|
||||
{
|
||||
use_preload = 1;
|
||||
|
||||
}
|
||||
if(!__libError)
|
||||
{
|
||||
hnm->frame = 0;
|
||||
hnm->ff_4 = 0;
|
||||
hnm->file = 0;
|
||||
hnm->work_buffer[0] = 0;
|
||||
hnm->work_buffer[1] = 0;
|
||||
hnm->final_buffer = 0;
|
||||
hnm->read_buffer = 0;
|
||||
hnm->ff_896 = 0;
|
||||
hnm->total_read = 0;
|
||||
for(i = 0;i < 256;i++)
|
||||
{
|
||||
hnm->palette[i].a = 0;
|
||||
hnm->palette[i].r = 0;
|
||||
hnm->palette[i].g = 0;
|
||||
hnm->palette[i].b = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
CLCheckError();
|
||||
}
|
||||
CLEndCheck;
|
||||
return hnm;
|
||||
}
|
||||
|
||||
void CLHNM_Dispose(hnm_t *hnm)
|
||||
{
|
||||
CLBeginCheck;
|
||||
|
||||
if(use_preload)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CLMemory_Free(hnm);
|
||||
CLCheckError();
|
||||
|
||||
CLEndCheck;
|
||||
}
|
||||
|
||||
|
||||
void CLHNM_SetFile(hnm_t *hnm, file_t* file)
|
||||
{
|
||||
hnm->file = file;
|
||||
CLNoError;
|
||||
}
|
||||
|
||||
void CLHNM_SetFinalBuffer(hnm_t *hnm, unsigned char *buffer)
|
||||
{
|
||||
hnm->final_buffer = buffer;
|
||||
CLNoError;
|
||||
}
|
||||
|
||||
void CLHNM_AllocMemory(hnm_t *hnm)
|
||||
{
|
||||
CLBeginCheck;
|
||||
|
||||
hnm->work_buffer[0] = (unsigned char*)CLMemory_Alloc(hnm->header.buffersize + 2);
|
||||
CLCheckError();
|
||||
|
||||
if(!hnm->work_buffer[0])
|
||||
goto fin;
|
||||
|
||||
hnm->work_buffer[1] = (unsigned char*)CLMemory_Alloc(hnm->header.buffersize + 2);
|
||||
CLCheckError();
|
||||
|
||||
if(!hnm->work_buffer[1])
|
||||
{
|
||||
CLMemory_Free(hnm->work_buffer[0]);
|
||||
CLCheckError();
|
||||
hnm->work_buffer[0] = 0;
|
||||
goto fin;
|
||||
}
|
||||
|
||||
if(!use_preload)
|
||||
{
|
||||
hnm->read_buffer = (unsigned char*)CLMemory_Alloc(hnm->header.buffersize + 2);
|
||||
// CLCheckError();
|
||||
if(!hnm->read_buffer)
|
||||
{
|
||||
CLMemory_Free(hnm->work_buffer[0]);
|
||||
CLCheckError();
|
||||
hnm->work_buffer[0] = 0;
|
||||
CLMemory_Free(hnm->work_buffer[1]);
|
||||
CLCheckError();
|
||||
hnm->work_buffer[1] = 0;
|
||||
}
|
||||
}
|
||||
fin:;
|
||||
CLEndCheck;
|
||||
}
|
||||
|
||||
void CLHNM_DeallocMemory(hnm_t *hnm)
|
||||
{
|
||||
CLBeginCheck;
|
||||
if(hnm->work_buffer[0])
|
||||
{
|
||||
CLMemory_Free(hnm->work_buffer[0]);
|
||||
CLCheckError();
|
||||
hnm->work_buffer[0] = 0;
|
||||
}
|
||||
if(hnm->work_buffer[1])
|
||||
{
|
||||
CLMemory_Free(hnm->work_buffer[1]);
|
||||
CLCheckError();
|
||||
hnm->work_buffer[1] = 0;
|
||||
}
|
||||
|
||||
if(!use_preload)
|
||||
{
|
||||
if(hnm->read_buffer)
|
||||
{
|
||||
CLMemory_Free(hnm->read_buffer);
|
||||
CLCheckError();
|
||||
hnm->read_buffer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
CLEndCheck;
|
||||
}
|
||||
|
||||
void CLHNM_Read(hnm_t *hnm, int size)
|
||||
{
|
||||
long _size = size;
|
||||
if(!use_preload)
|
||||
{
|
||||
CLFile_Read(*hnm->file, hnm->read_buffer, &_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
void CLHNM_GiveTime(hnm_t *hnm)
|
||||
{
|
||||
if(use_preload)
|
||||
{
|
||||
//stuff preload_buffer from disk
|
||||
}
|
||||
}
|
||||
|
||||
void CLHNM_CanLoop(hnm_t *hnm, short can_loop)
|
||||
{
|
||||
hnm->can_loop = can_loop;
|
||||
}
|
||||
|
||||
void CLHNM_SelectBuffers(hnm_t *hnm)
|
||||
{
|
||||
if(hnm->frame % 2)
|
||||
{
|
||||
hnm->new_frame_buffer = hnm->work_buffer[1];
|
||||
hnm->old_frame_buffer = hnm->work_buffer[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
hnm->new_frame_buffer = hnm->work_buffer[0];
|
||||
hnm->old_frame_buffer = hnm->work_buffer[1];
|
||||
}
|
||||
}
|
||||
|
||||
void CLHNM_ChangePalette(hnm_t *hnm)
|
||||
{
|
||||
short mincolor, maxcolor;
|
||||
unsigned short fst, cnt;
|
||||
unsigned char *pal;
|
||||
color_t *color;
|
||||
CLPalette_GetLastPalette(hnm->palette);
|
||||
pal = hnm->data_ptr;
|
||||
if(*(unsigned short*)pal == 0xFFFF)
|
||||
return;
|
||||
mincolor = 255;
|
||||
maxcolor = 0;
|
||||
do
|
||||
{
|
||||
fst = *pal++;
|
||||
cnt = *pal++;
|
||||
if(cnt == 0)
|
||||
cnt = 256;
|
||||
debug("hnm: setting palette, fst = %d, cnt = %d, last = %d", fst, cnt, fst + cnt - 1);
|
||||
assert(fst + cnt <= 256);
|
||||
if (mincolor > fst)
|
||||
mincolor = fst;
|
||||
if(maxcolor < fst + cnt)
|
||||
maxcolor = fst + cnt;
|
||||
color = hnm->palette + fst;
|
||||
if(safe_palette)
|
||||
{
|
||||
while(cnt--)
|
||||
{
|
||||
unsigned char r = *pal++;
|
||||
unsigned char g = *pal++;
|
||||
unsigned char b = *pal++;
|
||||
short rr = r << 10;
|
||||
short gg = g << 10;
|
||||
short bb = b << 10;
|
||||
if(color->r != rr || color->g != gg || color->b != bb)
|
||||
CLBlitter_OneBlackFlash();
|
||||
color->r = rr;
|
||||
color->g = gg;
|
||||
color->b = bb;
|
||||
color++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while(cnt--)
|
||||
{
|
||||
unsigned char r = *pal++;
|
||||
unsigned char g = *pal++;
|
||||
unsigned char b = *pal++;
|
||||
color->r = r << 10;
|
||||
color->g = g << 10;
|
||||
color->b = b << 10;
|
||||
color++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
while(*(unsigned short*)pal != 0xFFFF);
|
||||
#if 0
|
||||
if(preserve_color0)
|
||||
{
|
||||
hnm->palette[0].r = 0;
|
||||
hnm->palette[0].g = 0;
|
||||
hnm->palette[0].b = 0;
|
||||
}
|
||||
#endif
|
||||
// CLBlitter_Send2ScreenNextCopy(hnm->palette, mincolor, maxcolor - mincolor);
|
||||
CLBlitter_Send2ScreenNextCopy(hnm->palette, 0, 256);
|
||||
}
|
||||
|
||||
void CLHNM_Desentrelace(hnm_t *hnm)
|
||||
{
|
||||
switch(hnm->header.width)
|
||||
{
|
||||
case 320:
|
||||
CLHNM_Desentrelace320(hnm->new_frame_buffer, hnm->final_buffer, hnm->header.height);
|
||||
CLNoError;
|
||||
break;
|
||||
// case 480:
|
||||
// CLHNM_Desentrelace480(hnm->new_frame_buffer, hnm->final_buffer, hnm->header.height);
|
||||
// CLNoError;
|
||||
// break;
|
||||
default:
|
||||
__libError = -5;
|
||||
__osError = 0;
|
||||
CLCheckError();
|
||||
}
|
||||
}
|
||||
|
||||
void CLHNM_FlushPreloadBuffer(hnm_t *hnm)
|
||||
{
|
||||
if(use_preload)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
soundchannel_t* CLHNM_GetSoundChannel()
|
||||
{
|
||||
return soundChannel;
|
||||
}
|
||||
|
||||
|
||||
void CLHNM_TryRead(hnm_t *hnm, int size)
|
||||
{
|
||||
short err;
|
||||
do
|
||||
{
|
||||
CLHNM_Read(hnm, size);
|
||||
err = __libError == -6;
|
||||
if(err)
|
||||
CLHNM_GiveTime(hnm);
|
||||
}
|
||||
while(err);
|
||||
}
|
||||
|
||||
void CLHNM_ResetInternalTimer()
|
||||
{
|
||||
time_drift = 0.0;
|
||||
next_frame_time = expected_frame_time = TimerTicks;
|
||||
}
|
||||
|
||||
void CLHNM_Reset(hnm_t *hnm)
|
||||
{
|
||||
hnm->frame = 0;
|
||||
hnm->ff_4 = 0;
|
||||
hnm->total_read = 0;
|
||||
sound_started = 0;
|
||||
pending_sounds = 0;
|
||||
CLHNM_ResetInternalTimer();
|
||||
CLNoError;
|
||||
}
|
||||
|
||||
short CLHNM_LoadFrame(hnm_t *hnm)
|
||||
{
|
||||
int chunk;
|
||||
CLBeginCheck;
|
||||
CLHNM_TryRead(hnm, 4);
|
||||
CLEndCheck;
|
||||
chunk = *(int*)hnm->read_buffer;
|
||||
chunk = LE32(chunk);
|
||||
chunk &= 0xFFFFFF; // upper bit - keyframe mark?
|
||||
if(!chunk)
|
||||
return 0;
|
||||
|
||||
if(use_preload)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
if(chunk - 4 > hnm->header.buffersize)
|
||||
{
|
||||
__libError = -3;
|
||||
__osError = 0;
|
||||
CLCheckError();
|
||||
}
|
||||
else
|
||||
if(use_preload && chunk - 4 > 102400)
|
||||
{
|
||||
__libError = -3;
|
||||
__osError = 0;
|
||||
CLCheckError();
|
||||
}
|
||||
}
|
||||
CLBeginCheck;
|
||||
CLHNM_TryRead(hnm, chunk - 4);
|
||||
CLEndCheck;
|
||||
hnm->data_ptr = hnm->read_buffer;
|
||||
hnm->total_read += chunk;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CLHNM_WantsSound(short sound)
|
||||
{
|
||||
use_sound = sound;
|
||||
}
|
||||
|
||||
void CLHNM_LoadDecompTable(short *buffer)
|
||||
{
|
||||
short i;
|
||||
short e;
|
||||
for(i = 0;i < 256;i++)
|
||||
{
|
||||
e = *buffer++;
|
||||
decomp_table[i] = LE16(e);
|
||||
}
|
||||
}
|
||||
|
||||
void CLHNM_DecompADPCM(unsigned char *buffer, short *output, int size)
|
||||
{
|
||||
short l = pred_l, r = pred_r;
|
||||
size &= ~1;
|
||||
while(size--)
|
||||
{
|
||||
*output++ = l += decomp_table[*buffer++];
|
||||
*output++ = r += decomp_table[*buffer++];
|
||||
if(l > 512 || r > 512)
|
||||
DebugStr(" coucou");
|
||||
}
|
||||
pred_l = l;
|
||||
pred_r = r;
|
||||
}
|
||||
|
||||
void CLHNM_SoundInADPCM(short is_adpcm)
|
||||
{
|
||||
use_adpcm = is_adpcm;
|
||||
}
|
||||
|
||||
void CLHNM_SoundMono(short is_mono)
|
||||
{
|
||||
use_mono = is_mono;
|
||||
}
|
||||
|
||||
short CLHNM_NextElement(hnm_t *hnm)
|
||||
{
|
||||
int sz;
|
||||
short id;
|
||||
char h6, h7;
|
||||
short i;
|
||||
if(hnm->frame == 0)
|
||||
{
|
||||
CLHNM_ResetInternalTimer();
|
||||
pred_l = pred_r = 0;
|
||||
}
|
||||
if(hnm->frame == hnm->header.nframe)
|
||||
return 0;
|
||||
if(!CLHNM_LoadFrame(hnm))
|
||||
return 0;
|
||||
for(;;)
|
||||
{
|
||||
sz = PLE32(hnm->data_ptr) & 0xFFFFFF; hnm->data_ptr += 4;
|
||||
id = *(short*)hnm->data_ptr; hnm->data_ptr += 2;
|
||||
h6 = *hnm->data_ptr; hnm->data_ptr += 1;
|
||||
h7 = *hnm->data_ptr; hnm->data_ptr += 1;
|
||||
hnm->chunk_id = id;
|
||||
switch(id)
|
||||
{
|
||||
case BE16('PL'):
|
||||
CLHNM_ChangePalette(hnm);
|
||||
hnm->data_ptr += sz - 8;
|
||||
break;
|
||||
case BE16('IZ'):
|
||||
hnm->frame++;
|
||||
CLHNM_SelectBuffers(hnm);
|
||||
CLHNM_DecompLempelZiv(hnm->data_ptr + 4, hnm->new_frame_buffer);
|
||||
switch(hnm->header.width)
|
||||
{
|
||||
// case 320: CLBlitter_RawCopy320ASM(hnm->new_frame_buffer, hnm->old_frame_buffer, hnm->header.height); break;
|
||||
// case 480: CLBlitter_RawCopy480ASM(hnm->new_frame_buffer, hnm->old_frame_buffer, hnm->header.height); break;
|
||||
// case 640: CLBlitter_RawCopy640ASM(hnm->new_frame_buffer, hnm->old_frame_buffer, hnm->header.height); break;
|
||||
// default: memcpy(hnm->old_frame_buffer, hnm->new_frame_buffer, hnm->header.width * hnm->header.height);
|
||||
default: memcpy(hnm->old_frame_buffer, hnm->new_frame_buffer, hnm->header.buffersize); //TODO strange buffer size here
|
||||
}
|
||||
if(!(h6 & 1))
|
||||
CLHNM_Desentrelace(hnm);
|
||||
else
|
||||
{
|
||||
// if(hnm->header.width == 640)
|
||||
// CLBlitter_RawCopy640(hnm->new_frame_buffer, hnm->final_buffer, hnm->header.height);
|
||||
// else
|
||||
memcpy(hnm->final_buffer, hnm->new_frame_buffer, hnm->header.height); //TODO: wrong size?
|
||||
}
|
||||
if(use_adpcm)
|
||||
{
|
||||
if(!sound_started)
|
||||
{
|
||||
for(i = 0;i < pending_sounds;i++)
|
||||
CLSoundGroup_PlayNextSample(soundGroup_adpcm, soundChannel);
|
||||
sound_started = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!sound_started)
|
||||
{
|
||||
for(i = 0;i < pending_sounds;i++)
|
||||
CLSoundGroup_PlayNextSample(soundGroup, soundChannel);
|
||||
sound_started = 1;
|
||||
}
|
||||
}
|
||||
goto end_frame;
|
||||
case BE16('IU'):
|
||||
hnm->frame++;
|
||||
CLHNM_SelectBuffers(hnm);
|
||||
CLHNM_DecompUBA(hnm->new_frame_buffer, hnm->new_frame_buffer, hnm->old_frame_buffer, hnm->data_ptr, hnm->header.width, h6);
|
||||
if(!(h6 & 1))
|
||||
CLHNM_Desentrelace(hnm);
|
||||
else
|
||||
{
|
||||
// if(hnm->header.width == 640)
|
||||
// CLBlitter_RawCopy640(hnm->new_frame_buffer, hnm->final_buffer, hnm->header.height);
|
||||
// else
|
||||
memcpy(hnm->final_buffer, hnm->new_frame_buffer, hnm->header.width * hnm->header.height);
|
||||
}
|
||||
goto end_frame;
|
||||
case BE16('sd'):
|
||||
case BE16('SD'):
|
||||
if(use_sound)
|
||||
{
|
||||
if(!h6)
|
||||
{
|
||||
int sound_size = sz - 8;
|
||||
if(!use_adpcm)
|
||||
{
|
||||
CLSoundGroup_SetDatas(soundGroup, hnm->data_ptr, sound_size - 2, 0);
|
||||
if(sound_started)
|
||||
CLSoundGroup_PlayNextSample(soundGroup, soundChannel);
|
||||
else
|
||||
pending_sounds++;
|
||||
}
|
||||
else
|
||||
{
|
||||
short *sound_buffer = (short*)CLSoundGroup_GetNextBuffer(soundGroup_adpcm);
|
||||
if(!pending_sounds)
|
||||
{
|
||||
const int kDecompTableSize = 256 * sizeof(short);
|
||||
CLHNM_LoadDecompTable((short*)hnm->data_ptr);
|
||||
CLHNM_DecompADPCM(hnm->data_ptr + kDecompTableSize, sound_buffer, sound_size - kDecompTableSize);
|
||||
CLSoundGroup_AssignDatas(soundGroup_adpcm, sound_buffer, (sound_size - kDecompTableSize) * 2, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
CLHNM_DecompADPCM(hnm->data_ptr, sound_buffer, sound_size);
|
||||
CLSoundGroup_AssignDatas(soundGroup_adpcm, sound_buffer, sound_size * 2, 0);
|
||||
}
|
||||
pending_sounds++;
|
||||
if(sound_started)
|
||||
CLSoundGroup_PlayNextSample(soundGroup_adpcm, soundChannel);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
__libError = -3;
|
||||
__osError = 0;
|
||||
CLCheckError();
|
||||
}
|
||||
}
|
||||
hnm->data_ptr += sz - 8;
|
||||
break;
|
||||
default:
|
||||
if(custom_chunk_handler)
|
||||
custom_chunk_handler(hnm->data_ptr, sz - 8, id, h6, h7);
|
||||
hnm->data_ptr += sz - 8;
|
||||
}
|
||||
}
|
||||
end_frame:;
|
||||
if(use_preload)
|
||||
{
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CLHNM_ReadHeader(hnm_t *hnm)
|
||||
{
|
||||
CLBeginCheck;
|
||||
if(!use_preload)
|
||||
{
|
||||
long size = sizeof(hnm->header);
|
||||
CLFile_Read(*hnm->file, &hnm->header, &size);
|
||||
}
|
||||
else
|
||||
;
|
||||
CLCheckError();
|
||||
CLEndCheck;
|
||||
hnm->header.width = LE16(hnm->header.width);
|
||||
hnm->header.height = LE16(hnm->header.height);
|
||||
hnm->header.filesize = LE32(hnm->header.filesize);
|
||||
hnm->header.nframe = LE32(hnm->header.nframe);
|
||||
hnm->header.table_offset = LE32(hnm->header.table_offset);
|
||||
hnm->header.speed = LE16(hnm->header.speed);
|
||||
hnm->header.maxbuffer = LE16(hnm->header.maxbuffer);
|
||||
hnm->header.buffersize = LE32(hnm->header.buffersize);
|
||||
hnm->header.ff_20 = LE16(hnm->header.ff_20);
|
||||
hnm->header.buffersize += 4096; //TODO: checkme
|
||||
}
|
||||
|
||||
short CLHNM_GetVersion(hnm_t *hnm)
|
||||
{
|
||||
CLNoError;
|
||||
if(hnm->header.id == BE32('HNM4'))
|
||||
return 4;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int CLHNM_GetFrameNum(hnm_t *hnm)
|
||||
{
|
||||
return hnm->frame;
|
||||
}
|
||||
|
||||
void CLHNM_DeactivatePreloadBuffer()
|
||||
{
|
||||
use_preload = 0;
|
||||
}
|
||||
|
||||
void CLHNM_Prepare2Read(hnm_t *hnm, int mode)
|
||||
{
|
||||
if(use_preload)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
void CLHNM_SetPosIntoFile(hnm_t *hnm, long pos)
|
||||
{
|
||||
CLFile_SetPosition(*hnm->file, 1, pos);
|
||||
}
|
||||
|
||||
void CLHNM_Desentrelace320(unsigned char *frame_buffer, unsigned char *final_buffer, unsigned short height)
|
||||
{
|
||||
unsigned int *input = (unsigned int*)frame_buffer;
|
||||
unsigned int *line0 = (unsigned int*)final_buffer;
|
||||
unsigned int *line1 = (unsigned int*)(final_buffer + 320);
|
||||
int count = (height) / 2;
|
||||
while(count--)
|
||||
{
|
||||
short i;
|
||||
for(i = 0;i < 320 / 4;i++)
|
||||
{
|
||||
unsigned int p0 = *input++;
|
||||
unsigned int p4 = *input++;
|
||||
#if 0
|
||||
*line0++ = ((p4 & 0xFF00) >> 8) | ((p4 & 0xFF000000) >> 16) | ((p0 & 0xFF00) << 8) | (p0 & 0xFF000000);
|
||||
// *line0++ = (p0 & 0xFF000000) | ((p0 & 0xFF00) << 8) | ((p4 & 0xFF000000) >> 16) | ((p4 & 0xFF00) >> 8);
|
||||
*line1++ = ((p0 & 0xFF0000) << 8) | ((p0 & 0xFF) << 16) | ((p4 & 0xFF0000) >> 8) | (p4 & 0xFF);
|
||||
#else
|
||||
*line0++ = (p0 & 0xFF) | ((p0 & 0xFF0000) >> 8) | ((p4 & 0xFF) << 16) | ((p4 & 0xFF0000) << 8);
|
||||
*line1++ = ((p0 & 0xFF00) >> 8) | ((p0 & 0xFF000000) >> 16) | ((p4 & 0xFF00) << 8) | (p4 & 0xFF000000);
|
||||
#endif
|
||||
}
|
||||
line0 += 320 / 4;
|
||||
line1 += 320 / 4;
|
||||
}
|
||||
}
|
57
engines/cryo/CLSouNdRaw.c
Normal file
57
engines/cryo/CLSouNdRaw.c
Normal file
@ -0,0 +1,57 @@
|
||||
#include "cryolib.h"
|
||||
|
||||
sound_t* CLSoundRaw_New(short arg1, float rate, short sampleSize, short mode)
|
||||
{
|
||||
sound_t *sound;
|
||||
CLBeginCheck;
|
||||
|
||||
sound = (sound_t*)CLMemory_Alloc(sizeof(*sound));
|
||||
if(sound)
|
||||
{
|
||||
sound->ff_1A = arg1;
|
||||
sound->rate = rate;
|
||||
sound->sampleSize = sampleSize;
|
||||
sound->buffer = 0;
|
||||
// sound->sndHandle = CLMemory_AllocHandle(arg1 + 100);
|
||||
// if(!sound->sndHandle)
|
||||
// {
|
||||
// __libError = -1;
|
||||
// __osError = MemError();
|
||||
// CLCheckError();
|
||||
// }
|
||||
// else
|
||||
{
|
||||
CLSound_PrepareSample(sound, mode);
|
||||
CLNoError;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
__libError = -1;
|
||||
__osError = MemError();
|
||||
CLCheckError();
|
||||
}
|
||||
|
||||
CLEndCheck;
|
||||
return sound;
|
||||
}
|
||||
|
||||
void CLSoundRaw_Free(sound_t *sound)
|
||||
{
|
||||
while(sound->locked) ;
|
||||
// CLMemory_FreeHandle(sound->sndHandle);
|
||||
CLMemory_Free(sound);
|
||||
}
|
||||
|
||||
void CLSoundRaw_AssignBuffer(sound_t *sound, void *buffer, int bufferOffs, int length)
|
||||
{
|
||||
char *buf;
|
||||
CLSound_SetLength(sound, length);
|
||||
sound->length = length;
|
||||
buf = bufferOffs + (char*)buffer;
|
||||
// if(CLSound_GetWantsDesigned())
|
||||
// CLSound_Signed2NonSigned(buf, length);
|
||||
sound->buffer = buf;
|
||||
// if(sound->reversed && sound->sampleSize == 16)
|
||||
// ReverseBlock16(buf, length);
|
||||
}
|
181
engines/cryo/CryoLib.h
Normal file
181
engines/cryo/CryoLib.h
Normal file
@ -0,0 +1,181 @@
|
||||
#pragma once
|
||||
#define SW16(n) ( (((n) & 0xFF) << 8) | (((n) >> 8) & 0xFF) )
|
||||
#define SW32(n) ( (((n) & 0xFF) << 24) | (((n) >> 24) & 0xFF) | (((n) & 0xFF00) << 8) | (((n) >> 8) & 0xFF00))
|
||||
#if 0
|
||||
//big-endian host
|
||||
#define LE16(n) SW16(n)
|
||||
#define LE32(n) SW32(n)
|
||||
#define BE16(n) (n)
|
||||
#define BE32(n) (n)
|
||||
#else
|
||||
//little-endian host
|
||||
#define LE16(n) (n)
|
||||
#define LE32(n) (n)
|
||||
#define BE16(n) SW16(n)
|
||||
#define BE32(n) SW32(n)
|
||||
#endif
|
||||
#define PLE16(p) ( (((unsigned char*)(p))[1] << 8) | ((unsigned char*)(p))[0] )
|
||||
#define PLE32(p) ( (((unsigned char*)(p))[3] << 24) | (((unsigned char*)(p))[2] << 16) | (((unsigned char*)(p))[1] << 8) | ((unsigned char*)(p))[0] )
|
||||
|
||||
#include "audio/mixer.h"
|
||||
|
||||
typedef void *SndChannel;
|
||||
typedef char *Handle;
|
||||
enum {
|
||||
fsFromStart = 1
|
||||
};
|
||||
|
||||
extern short __debug2;
|
||||
|
||||
extern short __debug, __libError, __osError;
|
||||
|
||||
#define CLBeginCheck { short __oldDebug = __debug; __debug = -1;
|
||||
#define CLEndCheck __debug = __oldDebug; }
|
||||
#define CLNoError __libError = 0;
|
||||
|
||||
#define CLCheckError() if(__debug && __libError){ \
|
||||
char buffer[260]; \
|
||||
sprintf(buffer, "File %s at line %d, with __libError = %d and __osError = %d", __FILE__, __LINE__, __libError, __osError); \
|
||||
DebugStr(c2pstr(buffer)); \
|
||||
};
|
||||
|
||||
#define CLAssert(x) if(!(x)) { \
|
||||
char buffer[260]; \
|
||||
sprintf(buffer, "File %s at line %d, with __libError = %d and __osError = %d", __FILE__, __LINE__, __libError, __osError); \
|
||||
DebugStr(c2pstr(buffer)); \
|
||||
};
|
||||
|
||||
struct rect_t {
|
||||
int sy, sx, ey, ex;
|
||||
};
|
||||
typedef struct rect_t rect_t;
|
||||
|
||||
struct view_t {
|
||||
unsigned char *p_buffer;
|
||||
int width;
|
||||
int height;
|
||||
short pitch;
|
||||
short doubled;
|
||||
short allocated;
|
||||
struct {
|
||||
int src_left;
|
||||
int src_top;
|
||||
int dst_left;
|
||||
int dst_top;
|
||||
int width;
|
||||
int height;
|
||||
} norm, zoom;
|
||||
};
|
||||
typedef struct view_t view_t;
|
||||
|
||||
struct color3_t {
|
||||
short r, g, b;
|
||||
};
|
||||
typedef struct color3_t color3_t;
|
||||
|
||||
struct color_t {
|
||||
short a, r, g, b;
|
||||
};
|
||||
typedef struct color_t color_t;
|
||||
|
||||
struct palette_t {
|
||||
color_t colors[256];
|
||||
};
|
||||
typedef struct palette_t palette_t;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct hnmheader_t {
|
||||
int id;
|
||||
char flag1;
|
||||
char flag2;
|
||||
char reseverd;
|
||||
char bpp;
|
||||
unsigned short width;
|
||||
unsigned short height;
|
||||
int filesize;
|
||||
int nframe;
|
||||
int table_offset;
|
||||
short speed;
|
||||
short maxbuffer;
|
||||
int buffersize;
|
||||
short ff_20;
|
||||
char reserved2[14];
|
||||
char copyright[16];
|
||||
};
|
||||
typedef struct hnmheader_t hnmheader_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
struct hnm_t {
|
||||
int frame;
|
||||
int ff_4;
|
||||
file_t* file;
|
||||
hnmheader_t header;
|
||||
unsigned char *work_buffer[2];
|
||||
unsigned char *final_buffer;
|
||||
unsigned char *new_frame_buffer;
|
||||
unsigned char *old_frame_buffer;
|
||||
unsigned char *read_buffer;
|
||||
unsigned char *data_ptr;
|
||||
color_t palette[256];
|
||||
|
||||
short can_loop;
|
||||
|
||||
short ff_896;
|
||||
short chunk_id;
|
||||
int total_read;
|
||||
};
|
||||
typedef struct hnm_t hnm_t;
|
||||
|
||||
//struct filespec_t {
|
||||
//char puff;
|
||||
//};
|
||||
|
||||
struct sound_t {
|
||||
Handle sndHandle;
|
||||
short headerLen;
|
||||
long headerOffset;
|
||||
short ff_A;
|
||||
|
||||
char *buffer;
|
||||
int ff_16;
|
||||
short ff_1A;
|
||||
float rate;
|
||||
short sampleSize;
|
||||
int length;
|
||||
short mode;
|
||||
volatile short locked;
|
||||
long loopStart;
|
||||
short loopTimes;
|
||||
short reversed;
|
||||
short ff_32;
|
||||
short volume;
|
||||
};
|
||||
typedef struct sound_t sound_t;
|
||||
|
||||
#define CL_MAX_SOUNDS 64
|
||||
|
||||
struct soundgroup_t {
|
||||
sound_t *sound[CL_MAX_SOUNDS];
|
||||
short numSounds;
|
||||
short soundIndex;
|
||||
short playIndex;
|
||||
short ff_106;
|
||||
};
|
||||
typedef struct soundgroup_t soundgroup_t;
|
||||
|
||||
#define CL_MAX_CH_SOUNDS 10
|
||||
|
||||
struct soundchannel_t {
|
||||
Audio::SoundHandle ch;
|
||||
int xx;
|
||||
|
||||
short volumeLeft;
|
||||
short volumeRight;
|
||||
short numSounds;
|
||||
|
||||
sound_t *sounds[CL_MAX_CH_SOUNDS];
|
||||
|
||||
short ff_536;
|
||||
};
|
||||
typedef struct soundchannel_t soundchannel_t;
|
||||
|
604
engines/cryo/CryoLibStub.c
Normal file
604
engines/cryo/CryoLibStub.c
Normal file
@ -0,0 +1,604 @@
|
||||
|
||||
///// Mac APIs
|
||||
typedef short OSErr;
|
||||
|
||||
short MemError()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SysBeep(int x)
|
||||
{
|
||||
}
|
||||
|
||||
OSErr SetFPos(short handle, short mode, long pos)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
OSErr FSRead(short handle, long *size, void *buffer)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FlushEvents(short arg1, short arg2)
|
||||
{
|
||||
}
|
||||
|
||||
char* c2pstr(char *s)
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
void DebugStr(char *s)
|
||||
{
|
||||
}
|
||||
|
||||
// from mw lib???
|
||||
long TickCount()
|
||||
{
|
||||
return g_system->getMillis();
|
||||
}
|
||||
|
||||
///// CLMemory
|
||||
void* CLMemory_Alloc(int size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
void CLMemory_Free(void *ptr)
|
||||
{
|
||||
//TODO: due to a bug in ssndfl() sometimes a null ptr passed, skip it
|
||||
if (!ptr)
|
||||
return;
|
||||
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
|
||||
///// CLTimer
|
||||
volatile long TimerTicks = 0; // incremented in realtime
|
||||
|
||||
///// CLView
|
||||
void CLView_SetSrcZoomValues(view_t *view, int x, int y)
|
||||
{
|
||||
view->zoom.src_left = x;
|
||||
view->zoom.src_top = y;
|
||||
}
|
||||
void CLView_SetDisplayZoomValues(view_t *view, int w, int h)
|
||||
{
|
||||
view->zoom.width = w;
|
||||
view->zoom.height = h;
|
||||
}
|
||||
void CLView_Free(view_t *view)
|
||||
{
|
||||
if (view->p_buffer && view->allocated)
|
||||
CLMemory_Free(view->p_buffer);
|
||||
if (view)
|
||||
CLMemory_Free(view);
|
||||
}
|
||||
void CLView_InitDatas(view_t *view, int w, int h, void *buffer)
|
||||
{
|
||||
view->p_buffer = (unsigned char*)buffer;
|
||||
view->width = w;
|
||||
view->height = h;
|
||||
view->pitch = w;
|
||||
view->doubled = 0;
|
||||
view->norm.src_left = 0;
|
||||
view->norm.src_top = 0;
|
||||
view->norm.dst_left = 0;
|
||||
view->norm.dst_top = 0;
|
||||
view->norm.width = w;
|
||||
view->norm.height = h;
|
||||
view->zoom.src_left = 0;
|
||||
view->zoom.src_top = 0;
|
||||
view->zoom.dst_left = 0;
|
||||
view->zoom.dst_top = 0;
|
||||
view->zoom.width = w;
|
||||
view->zoom.height = h;
|
||||
}
|
||||
view_t* CLView_New(int w, int h)
|
||||
{
|
||||
view_t *view = (view_t*)CLMemory_Alloc(sizeof(view_t));
|
||||
if (view)
|
||||
{
|
||||
void *buffer = (unsigned char*)CLMemory_Alloc(w * h);
|
||||
if (buffer)
|
||||
{
|
||||
view->allocated = 1;
|
||||
CLView_InitDatas(view, w, h, buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
CLMemory_Free(view);
|
||||
view = 0;
|
||||
}
|
||||
}
|
||||
return view;
|
||||
}
|
||||
void CLView_CenterIn(view_t *parent, view_t *child)
|
||||
{
|
||||
child->norm.dst_left = (parent->width - child->norm.width) / 2;
|
||||
child->norm.dst_top = (parent->height - child->norm.height) / 2;
|
||||
child->zoom.dst_left = (parent->width - child->zoom.width) / 2;
|
||||
child->zoom.dst_top = (parent->height - child->zoom.height) / 2;
|
||||
}
|
||||
|
||||
///// CLScreenView
|
||||
view_t ScreenView;
|
||||
|
||||
void CLScreenView_Init()
|
||||
{
|
||||
// ScreenView is the game's target screen (a pc display)
|
||||
// we use a dedicated surface for it, which at some point will be
|
||||
// presented to user by System::copyRectToScreen call
|
||||
CLView_InitDatas(&ScreenView, g_ed->_screen.w, g_ed->_screen.h, g_ed->_screen.getPixels());
|
||||
}
|
||||
|
||||
void CLScreenView_CenterIn(view_t *view)
|
||||
{
|
||||
CLView_CenterIn(&ScreenView, view);
|
||||
}
|
||||
|
||||
///// CLPalette
|
||||
unsigned short gIntervalLast, gIntervalFirst, gIntervalSet;
|
||||
short gMacintize = 0;
|
||||
color_t black_palette[256];
|
||||
color_t last_palette[256];
|
||||
void CLPalette_Init()
|
||||
{
|
||||
short i;
|
||||
for (i = 0; i < 256; i++)
|
||||
black_palette[i].r = black_palette[i].g = black_palette[i].b = 0;
|
||||
}
|
||||
void CLPalette_SetLastPalette(color_t *palette, short first, short count)
|
||||
{
|
||||
short i;
|
||||
for (i = first; i < first + count; i++)
|
||||
last_palette[i] = palette[i];
|
||||
}
|
||||
void CLPalette_GetLastPalette(color_t *palette)
|
||||
{
|
||||
short i;
|
||||
for (i = 0; i < 256; i++)
|
||||
palette[i] = last_palette[i];
|
||||
}
|
||||
void CLPalette_SetRGBColor(color_t *palette, unsigned short index, color3_t *rgb)
|
||||
{
|
||||
palette[index].r = rgb->r;
|
||||
palette[index].g = rgb->g;
|
||||
palette[index].b = rgb->b;
|
||||
palette[index].a = 0;
|
||||
}
|
||||
void CLPalette_Macintize(short macintize)
|
||||
{
|
||||
gMacintize = macintize;
|
||||
}
|
||||
void CLPalette_SetInterval(unsigned short first, unsigned short last)
|
||||
{
|
||||
gIntervalFirst = first;
|
||||
gIntervalSet = 1;
|
||||
gIntervalLast = last;
|
||||
}
|
||||
void CLPalette_DeactivateInterval()
|
||||
{
|
||||
gIntervalSet = 0;
|
||||
}
|
||||
void CLPalette_Send2Screen(struct color_t *palette, unsigned short first, unsigned short count)
|
||||
{
|
||||
OSErr err;
|
||||
short i;
|
||||
if (gMacintize)
|
||||
{
|
||||
palette[0].r = palette[0].g = palette[0].b = 0xFFFF;
|
||||
palette[255].r = palette[255].g = palette[255].b = 0;
|
||||
}
|
||||
if (gIntervalSet)
|
||||
{
|
||||
if (first < gIntervalFirst)
|
||||
first = gIntervalFirst;
|
||||
if (first + count > gIntervalLast)
|
||||
count = gIntervalLast - first;
|
||||
}
|
||||
|
||||
byte buffer[256 * 3];
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
buffer[i * 3] = palette[i].r >> 8;
|
||||
buffer[i * 3 + 1] = palette[i].g >> 8;
|
||||
buffer[i * 3 + 2] = palette[i].b >> 8;
|
||||
}
|
||||
|
||||
g_system->getPaletteManager()->setPalette(buffer, first, count);
|
||||
g_system->updateScreen();
|
||||
|
||||
CLPalette_SetLastPalette(palette, first, count);
|
||||
}
|
||||
void CLPalette_BeBlack()
|
||||
{
|
||||
CLPalette_Send2Screen(black_palette, 0, 256);
|
||||
}
|
||||
void CLPalette_BeSystem()
|
||||
{
|
||||
}
|
||||
|
||||
///// CLBlitter
|
||||
static unsigned short newPaletteCount, newPaletteFirst;
|
||||
static color_t *pNewPalette;
|
||||
static unsigned short useNewPalette;
|
||||
|
||||
void CLBlitter_CopyViewRect(view_t *view1, view_t *view2, rect_t *rect1, rect_t *rect2)
|
||||
{
|
||||
int sy, dy = rect2->sy, x, w = rect1->ex - rect1->sx + 1;
|
||||
// debug("- Copy rect %3d:%3d-%3d:%3d -> %3d:%3d-%3d:%3d - %s",
|
||||
// rect1->sx, rect1->sy, rect1->ex, rect1->ey,
|
||||
// rect2->sx, rect2->sy, rect2->ex, rect2->ey,
|
||||
// (rect1->ex - rect1->sx == rect2->ex - rect2->sx && rect1->ey - rect1->sy == rect2->ey - rect2->sy) ? "ok" : "BAD");
|
||||
assert(rect1->ex - rect1->sx == rect2->ex - rect2->sx && rect1->ey - rect1->sy == rect2->ey - rect2->sy);
|
||||
for (sy = rect1->sy; sy <= rect1->ey; sy++, dy++)
|
||||
{
|
||||
unsigned char *s = view1->p_buffer + sy * view1->pitch + rect1->sx;
|
||||
unsigned char *d = view2->p_buffer + dy * view2->pitch + rect2->sx;
|
||||
for (x = 0; x < w; x++)
|
||||
*d++ = *s++;
|
||||
}
|
||||
}
|
||||
void CLBlitter_Send2ScreenNextCopy(color_t *palette, unsigned short first, unsigned short count)
|
||||
{
|
||||
pNewPalette = palette;
|
||||
useNewPalette = 1;
|
||||
newPaletteFirst = first;
|
||||
newPaletteCount = count;
|
||||
}
|
||||
void CLBlitter_OneBlackFlash()
|
||||
{
|
||||
}
|
||||
void CLBlitter_CopyView2ViewSimpleSize(unsigned char *src, short srcw, short srcp, short srch,
|
||||
unsigned char *dst, short dstw, short dstp, short dsth)
|
||||
{
|
||||
short x, y;
|
||||
for (y = 0; y < srch; y++)
|
||||
{
|
||||
for (x = 0; x < srcw; x++)
|
||||
*dst++ = *src++;
|
||||
src += srcp - srcw;
|
||||
dst += dstp - dstw;
|
||||
}
|
||||
}
|
||||
void CLBlitter_CopyView2ScreenCUSTOM(view_t *view)
|
||||
{
|
||||
view_t *dest = &ScreenView;
|
||||
if (!view->doubled)
|
||||
{
|
||||
short srcpitch = view->pitch;
|
||||
short dstpitch = dest->pitch;
|
||||
|
||||
// this is not quite correct?
|
||||
// CLBlitter_CopyView2ViewSimpleSize(view->p_buffer + view->norm.src_top * srcpitch + view->norm.src_left, view->norm.width, srcpitch, view->norm.height,
|
||||
// dest->p_buffer + dest->norm.dst_top * dstpitch + dest->norm.dst_left, dest->norm.width, dstpitch, dest->norm.height);
|
||||
|
||||
CLBlitter_CopyView2ViewSimpleSize(view->p_buffer + view->norm.src_top * srcpitch + view->norm.src_left, view->norm.width, srcpitch, view->norm.height,
|
||||
dest->p_buffer + (dest->norm.dst_top + view->norm.dst_top) * dstpitch + dest->norm.dst_left + view->norm.dst_left, dest->norm.width, dstpitch, dest->norm.height);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
void CLBlitter_CopyView2Screen(view_t *view)
|
||||
{
|
||||
|
||||
if (useNewPalette)
|
||||
{
|
||||
color_t palette[256];
|
||||
CLPalette_GetLastPalette(palette);
|
||||
CLPalette_Send2Screen(pNewPalette, newPaletteFirst, newPaletteCount);
|
||||
useNewPalette = 0;
|
||||
}
|
||||
|
||||
//TODO: quick hack to force screen update
|
||||
if (view)
|
||||
CLBlitter_CopyView2ScreenCUSTOM(view);
|
||||
|
||||
g_system->copyRectToScreen(ScreenView.p_buffer, ScreenView.pitch, 0, 0, ScreenView.width, ScreenView.height);
|
||||
g_system->updateScreen();
|
||||
}
|
||||
void CLBlitter_UpdateScreen()
|
||||
{
|
||||
CLBlitter_CopyView2Screen(nullptr);
|
||||
}
|
||||
void CLBlitter_FillView(view_t *view, unsigned int fill)
|
||||
{
|
||||
short x, y;
|
||||
unsigned char *d = view->p_buffer;
|
||||
assert((fill & 0xFF) * 0x01010101 == fill);
|
||||
for (y = 0; y < view->height; y++)
|
||||
{
|
||||
for (x = 0; x < view->width; x++)
|
||||
*d++ = fill;
|
||||
d += view->pitch - view->width;
|
||||
}
|
||||
}
|
||||
void CLBlitter_FillScreenView(unsigned int fill)
|
||||
{
|
||||
CLBlitter_FillView(&ScreenView, fill);
|
||||
}
|
||||
|
||||
|
||||
///// events wrapper
|
||||
int _mouseButton;
|
||||
byte _keyState[256];
|
||||
|
||||
void pollEvents()
|
||||
{
|
||||
g_system->delayMillis(10);
|
||||
|
||||
Common::Event event;
|
||||
while (g_system->getEventManager()->pollEvent(event)) {
|
||||
// Handle keypress
|
||||
switch (event.type) {
|
||||
case Common::EVENT_QUIT:
|
||||
case Common::EVENT_RTL:
|
||||
return;
|
||||
|
||||
case Common::EVENT_KEYDOWN:
|
||||
// _keyState[(byte)toupper(event.kbd.ascii)] = true;
|
||||
return;
|
||||
case Common::EVENT_KEYUP:
|
||||
// _keyState[(byte)toupper(event.kbd.ascii)] = false;
|
||||
return;
|
||||
case Common::EVENT_LBUTTONDOWN:
|
||||
_mouseButton = 1;
|
||||
return;
|
||||
case Common::EVENT_RBUTTONDOWN:
|
||||
_mouseButton = 2;
|
||||
return;
|
||||
case Common::EVENT_LBUTTONUP:
|
||||
case Common::EVENT_RBUTTONUP:
|
||||
_mouseButton = 0;
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///// CLKeyboard
|
||||
short CLKeyboard_HasCmdDown()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
void CLKeyboard_Read()
|
||||
{
|
||||
pollEvents();
|
||||
}
|
||||
unsigned char CLKeyboard_GetLastASCII()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
short CLKeyboard_IsScanCodeDown(short scancode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
///// CLMouse
|
||||
void CLMouse_Hide()
|
||||
{
|
||||
}
|
||||
void CLMouse_Show()
|
||||
{
|
||||
}
|
||||
void CLMouse_GetPosition(short *x, short *y)
|
||||
{
|
||||
*x = g_system->getEventManager()->getMousePos().x;
|
||||
*y = g_system->getEventManager()->getMousePos().y;
|
||||
}
|
||||
void CLMouse_SetPosition(short x, short y)
|
||||
{
|
||||
g_system->warpMouse(x, y);
|
||||
}
|
||||
unsigned short CLMouse_IsDown()
|
||||
{
|
||||
pollEvents();
|
||||
return _mouseButton != 0;
|
||||
}
|
||||
|
||||
///// CLFile
|
||||
void CLFile_SetFilter(int a3, int a4, int a5, int a6, int a7)
|
||||
{
|
||||
}
|
||||
void CLFile_SetFinderInfos(void *fs, int a4, int a5)
|
||||
{
|
||||
}
|
||||
void CLFile_GetFullPath(void *a3, char *a4)
|
||||
{
|
||||
}
|
||||
void CLFile_MakeStruct(int a3, int a4, char *name, filespec_t *fs)
|
||||
{
|
||||
strcpy(fs->name, name);
|
||||
fs->create = 0;
|
||||
}
|
||||
void CLFile_Create(filespec_t *fs)
|
||||
{
|
||||
fs->create = 1;
|
||||
}
|
||||
void CLFile_Open(filespec_t *fs, short mode, file_t& handle)
|
||||
{
|
||||
handle.open(fs->name);
|
||||
}
|
||||
void CLFile_Close(file_t& handle)
|
||||
{
|
||||
handle.close();
|
||||
}
|
||||
void CLFile_SetPosition(file_t& handle, short mode, long pos)
|
||||
{
|
||||
assert(mode == 1);
|
||||
handle.seek(pos, 0);
|
||||
}
|
||||
void CLFile_Read(file_t& handle, void *buffer, long *size)
|
||||
{
|
||||
handle.read(buffer, *size);
|
||||
}
|
||||
void CLFile_Write(file_t& handle, void *buffer, long *size)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
|
||||
///// CLSound
|
||||
// base sound
|
||||
void CLSound_PrepareSample(sound_t *sound, short mode)
|
||||
{
|
||||
sound->mode = mode;
|
||||
sound->locked = 0;
|
||||
sound->loopTimes = 0;
|
||||
sound->reversed = 0;
|
||||
sound->ff_32 = 0;
|
||||
sound->volume = 255;
|
||||
}
|
||||
void CLSound_SetWantsDesigned(short designed)
|
||||
{
|
||||
}
|
||||
void CLSound_SetLength(sound_t *sound, int length)
|
||||
{
|
||||
}
|
||||
|
||||
///// CLSoundRaw
|
||||
// sound from memory buffer
|
||||
#include "CLSouNdRaw.c"
|
||||
|
||||
///// CLSoundChannel
|
||||
/// sound output device that plays queue of sounds
|
||||
soundchannel_t* CLSoundChannel_New(int arg1)
|
||||
{
|
||||
short i;
|
||||
soundchannel_t *ch = (soundchannel_t*)CLMemory_Alloc(sizeof(*ch));
|
||||
if (!ch)
|
||||
return 0;
|
||||
|
||||
ch->volumeLeft = ch->volumeRight = 255;
|
||||
ch->numSounds = 0;
|
||||
|
||||
for (i = 0; i < CL_MAX_CH_SOUNDS; i++)
|
||||
ch->sounds[i] = 0;
|
||||
|
||||
return ch;
|
||||
}
|
||||
void CLSoundChannel_Free(soundchannel_t *ch)
|
||||
{
|
||||
CLMemory_Free(ch);
|
||||
}
|
||||
void CLSoundChannel_Stop(soundchannel_t *ch)
|
||||
{
|
||||
// g_ed->_mixer->stopHandle(ch->ch);
|
||||
}
|
||||
void CLSoundChannel_Play(soundchannel_t *ch, sound_t *sound)
|
||||
{
|
||||
}
|
||||
short CLSoundChannel_GetVolume(soundchannel_t *ch)
|
||||
{
|
||||
return (ch->volumeLeft + ch->volumeRight) / 2;
|
||||
}
|
||||
void CLSoundChannel_SetVolume(soundchannel_t *ch, short volume)
|
||||
{
|
||||
if (volume < 0 || volume > 255)
|
||||
return;
|
||||
ch->volumeLeft = volume;
|
||||
ch->volumeRight = volume;
|
||||
}
|
||||
void CLSoundChannel_SetVolumeRight(soundchannel_t *ch, short volume)
|
||||
{
|
||||
if (volume < 0 || volume > 255)
|
||||
return;
|
||||
ch->volumeRight = volume;
|
||||
}
|
||||
void CLSoundChannel_SetVolumeLeft(soundchannel_t *ch, short volume)
|
||||
{
|
||||
if (volume < 0 || volume > 255)
|
||||
return;
|
||||
ch->volumeLeft = volume;
|
||||
}
|
||||
|
||||
///// CLSoundGroup
|
||||
/// a queue of sounds of same format
|
||||
#include "CLSoundGroup.c"
|
||||
|
||||
///// CLTimer
|
||||
void CLTimer_Action(void *arg)
|
||||
{
|
||||
// long& counter = *((long*)arg);
|
||||
// counter++;
|
||||
TimerTicks++;
|
||||
}
|
||||
|
||||
void CLTimer_Init()
|
||||
{
|
||||
g_system->getTimerManager()->installTimerProc(CLTimer_Action, 10000, nullptr, "100hz timer");
|
||||
}
|
||||
|
||||
void CLTimer_Done()
|
||||
{
|
||||
g_system->getTimerManager()->removeTimerProc(CLTimer_Action);
|
||||
}
|
||||
|
||||
///// CRYOLib
|
||||
void CRYOLib_InstallExitPatch()
|
||||
{
|
||||
}
|
||||
void CRYOLib_RemoveExitPatch()
|
||||
{
|
||||
}
|
||||
void CRYOLib_Init()
|
||||
{
|
||||
}
|
||||
void CRYOLib_Done()
|
||||
{
|
||||
}
|
||||
void CRYOLib_MinimalInit()
|
||||
{
|
||||
}
|
||||
void CRYOLib_ManagersInit()
|
||||
{
|
||||
CLTimer_Init();
|
||||
CLScreenView_Init();
|
||||
}
|
||||
void CRYOLib_ManagersDone()
|
||||
{
|
||||
CLTimer_Done();
|
||||
}
|
||||
void CRYOLib_SetDebugMode(short enable)
|
||||
{
|
||||
}
|
||||
void CRYOLib_InstallEmergencyExit(void(*proc)())
|
||||
{
|
||||
}
|
||||
void CRYOLib_SetupEnvironment()
|
||||
{
|
||||
}
|
||||
void CRYOLib_RestoreEnvironment()
|
||||
{
|
||||
}
|
||||
void CRYOLib_TestConfig()
|
||||
{
|
||||
}
|
||||
|
||||
///// CLComputer
|
||||
short CLComputer_Has68030()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
short CLComputer_Has68040()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
///// CLDesktop
|
||||
void CLDesktop_TestOpenFileAtStartup()
|
||||
{
|
||||
}
|
||||
|
||||
///// CLHNM
|
||||
#include "CLHNM.c"
|
||||
|
||||
///// CLError
|
||||
#include "CLError.c"
|
7
engines/cryo/LempelZiv.cpp
Normal file
7
engines/cryo/LempelZiv.cpp
Normal file
@ -0,0 +1,7 @@
|
||||
#include "LempelZiv.h"
|
||||
|
||||
namespace Cryo {
|
||||
|
||||
|
||||
|
||||
}
|
102
engines/cryo/LempelZiv.h
Normal file
102
engines/cryo/LempelZiv.h
Normal file
@ -0,0 +1,102 @@
|
||||
#pragma once
|
||||
|
||||
namespace Cryo {
|
||||
|
||||
class BitReaderBase {
|
||||
public:
|
||||
unsigned char *_data; //NB! never override this - used by decompressor
|
||||
unsigned int _queue;
|
||||
unsigned int _queueLeft;
|
||||
public:
|
||||
BitReaderBase(void *data, unsigned int dataSize = 0)
|
||||
{
|
||||
_data = static_cast<unsigned char*>(data);
|
||||
_queue = _queueLeft = 0;
|
||||
}
|
||||
|
||||
unsigned char GetBit()
|
||||
{
|
||||
return 0; // to be overriden
|
||||
}
|
||||
};
|
||||
|
||||
// used to decompress HSQ files
|
||||
class BitReader16 : BitReaderBase {
|
||||
public:
|
||||
unsigned char GetBit()
|
||||
{
|
||||
if (!_queueLeft)
|
||||
{
|
||||
_queue = (_data[1] << 8) | _data[0];
|
||||
_data += 2;
|
||||
_queueLeft += 16;
|
||||
}
|
||||
unsigned char bit = _queue & 1;
|
||||
_queue >>= 1;
|
||||
_queueLeft--;
|
||||
return bit;
|
||||
}
|
||||
};
|
||||
|
||||
// used by HNM decoder
|
||||
class BitReader32 : BitReaderBase {
|
||||
public:
|
||||
unsigned char GetBit()
|
||||
{
|
||||
if (!_queueLeft)
|
||||
{
|
||||
_queue = (_data[3] << 24) | (_data[2] << 16) | (_data[1] << 8) | _data[0];
|
||||
_data += 4;
|
||||
_queueLeft += 32;
|
||||
}
|
||||
unsigned char bit = (_queue >> (_queueLeft - 1)) & 1;
|
||||
_queueLeft--;
|
||||
return bit;
|
||||
}
|
||||
};
|
||||
|
||||
template <class BitReader>
|
||||
class LempelZivBase : BitReader
|
||||
{
|
||||
public:
|
||||
LempelZivBase(void *input, unsigned int inputSize) : BitReader(input, inputSize)
|
||||
|
||||
unsigned int UnpackBuffer(void *output, unsigned int maxOutputSize)
|
||||
{
|
||||
unsigned char *out = static_cast<unsigned char*>(output);
|
||||
for (;;)
|
||||
{
|
||||
if (GetBit())
|
||||
{
|
||||
*out++ = *_data++;
|
||||
}
|
||||
else
|
||||
{
|
||||
int length, offset;
|
||||
if (GetBit())
|
||||
{
|
||||
length = *_data & 7;
|
||||
offset = ((_data[1] << 8) | _data[0]) >> 3; _data += 2;
|
||||
offset -= 8192;
|
||||
if (!length)
|
||||
length = *_data++;
|
||||
if (!length)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
length = GetBit() * 2 + GetBit();
|
||||
offset = *(_data++) - 256;
|
||||
}
|
||||
length += 2;
|
||||
while (length--)
|
||||
{
|
||||
*out = *(out + offset); out++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return out - static_cast<unsigned char*>(output);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
116
engines/cryo/ResourceManager.cpp
Normal file
116
engines/cryo/ResourceManager.cpp
Normal file
@ -0,0 +1,116 @@
|
||||
#include "ResourceManager.h"
|
||||
|
||||
namespace Cryo {
|
||||
|
||||
ResourceManager::ResourceManager()
|
||||
{
|
||||
}
|
||||
|
||||
ResourceManager::ResourceManager(const Common::String &datFileName)
|
||||
{
|
||||
LoadDatFile(datFileName);
|
||||
}
|
||||
|
||||
ResourceManager::~ResourceManager()
|
||||
{
|
||||
}
|
||||
|
||||
bool ResourceManager::LoadDatFile(const Common::String &datFileName)
|
||||
{
|
||||
if (_datFile.isOpen())
|
||||
{
|
||||
_datFile.close();
|
||||
_files.clear();
|
||||
}
|
||||
|
||||
assert(_datFile.open(datFileName));
|
||||
|
||||
unsigned short numFiles = _datFile.readUint16LE();
|
||||
|
||||
for (unsigned short i = 0; i < numFiles; i++)
|
||||
{
|
||||
DatFileEntry entry;
|
||||
|
||||
_datFile.read(entry._name, sizeof(entry._name));
|
||||
entry._size = _datFile.readUint32LE();
|
||||
entry._offset = _datFile.readUint32LE();
|
||||
entry._flag = _datFile.readByte();
|
||||
|
||||
_files.push_back(entry);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *ResourceManager::GetFile(const Common::String &resName, unsigned int hintIndex)
|
||||
{
|
||||
// First, try raw disk file so we can support modding/patching
|
||||
|
||||
if (Common::File::exists(resName))
|
||||
{
|
||||
debug("Loading %s from disk", resName);
|
||||
|
||||
Common::File *resource = new Common::File();
|
||||
resource->open(resName);
|
||||
return resource;
|
||||
}
|
||||
|
||||
// Look inside .dat file
|
||||
|
||||
if (_datFile.isOpen())
|
||||
{
|
||||
for (unsigned int i = hintIndex; i < _files.size(); i++)
|
||||
{
|
||||
if (!resName.compareToIgnoreCase(_files[i]._name))
|
||||
{
|
||||
debug("Loading %s from dat file", resName);
|
||||
Common::SeekableSubReadStream *resource = new Common::SeekableSubReadStream(&_datFile, _files[i]._offset, _files[i]._offset + _files[i]._size);
|
||||
return resource;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug("Unable to load %s - does't exists", resName);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *ResourceManager::GetFile(unsigned int resIndex)
|
||||
{
|
||||
if (_files.size() > resIndex)
|
||||
{
|
||||
return GetFile(Common::String(_files[resIndex]._name), resIndex);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void *ResourceManager::StreamToBuffer(Common::SeekableReadStream *stream, unsigned int *size)
|
||||
{
|
||||
if (!stream)
|
||||
return nullptr;
|
||||
|
||||
unsigned int readSize = stream->size();
|
||||
unsigned char *data = new unsigned char[readSize + 1];
|
||||
readSize = stream->read(data, readSize);
|
||||
|
||||
if (size)
|
||||
*size = readSize;
|
||||
return data;
|
||||
}
|
||||
|
||||
void* ResourceManager::GetData(const Common::String &resName, unsigned int *size)
|
||||
{
|
||||
Common::SeekableReadStream *resource = GetFile(resName);
|
||||
void *data = StreamToBuffer(resource, size);
|
||||
delete resource;
|
||||
return data;
|
||||
}
|
||||
|
||||
void* ResourceManager::GetData(int resIndex, unsigned int *size)
|
||||
{
|
||||
Common::SeekableReadStream *resource = GetFile(resIndex);
|
||||
void *data = StreamToBuffer(resource, size);
|
||||
delete resource;
|
||||
return data;
|
||||
}
|
||||
}
|
77
engines/cryo/ResourceManager.h
Normal file
77
engines/cryo/ResourceManager.h
Normal file
@ -0,0 +1,77 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/file.h"
|
||||
#include "common/fs.h"
|
||||
#include "common/str.h"
|
||||
#include "common/substream.h"
|
||||
#include "common/debug.h"
|
||||
|
||||
namespace Cryo {
|
||||
|
||||
template<typename T>
|
||||
class CryoArray {
|
||||
private:
|
||||
unsigned char *_data;
|
||||
bool _ownData;
|
||||
unsigned short ElementOffset(int num)
|
||||
{
|
||||
assert(_data && num < Count())
|
||||
return (static_cast<unsigned short*>_data)[num];
|
||||
}
|
||||
public:
|
||||
CryoArray(void* data, bool ownData) : _data(data), _ownData(ownData)
|
||||
{
|
||||
}
|
||||
~CryoArray()
|
||||
{
|
||||
if (_ownData)
|
||||
delete data;
|
||||
}
|
||||
unsigned short Count()
|
||||
{
|
||||
return ElementOffset(0) / 2;
|
||||
}
|
||||
const T* operator[](int index)
|
||||
{
|
||||
return static_cast<T*>(_data + ElementOffset(num));
|
||||
}
|
||||
};
|
||||
|
||||
class ResourceManager
|
||||
{
|
||||
private:
|
||||
struct DatFileEntry {
|
||||
char _name[16];
|
||||
unsigned int _size;
|
||||
unsigned int _offset;
|
||||
unsigned char _flag;
|
||||
};
|
||||
|
||||
Common::Array<DatFileEntry> _files;
|
||||
Common::File _datFile;
|
||||
|
||||
static void *StreamToBuffer(Common::SeekableReadStream *stream, unsigned int *size);
|
||||
|
||||
public:
|
||||
ResourceManager(const Common::String &datFileName);
|
||||
ResourceManager();
|
||||
~ResourceManager();
|
||||
|
||||
bool LoadDatFile(const Common::String &datFileName);
|
||||
|
||||
// Load resource as a seekable stream
|
||||
Common::SeekableReadStream *GetFile(const Common::String &resName, unsigned int hintIndex = 0);
|
||||
Common::SeekableReadStream *GetFile(unsigned int resIndex);
|
||||
|
||||
// Load resource as a buffer
|
||||
void* GetData(const Common::String &resName, unsigned int *size = nullptr);
|
||||
void* GetData(int resIndex, unsigned int *size = nullptr);
|
||||
void* operator[](int resIndex)
|
||||
{
|
||||
return GetData(resIndex);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
10
engines/cryo/bugs.txt
Normal file
10
engines/cryo/bugs.txt
Normal file
@ -0,0 +1,10 @@
|
||||
|
||||
1. Open menu and replay last dialog, then press stop. hover over buttons - hint text will be misplaced
|
||||
2. During valley location change some junk appears in the bottom half of screen for a brief time (broken transition effect?)
|
||||
3. Transitions often show a lot of red colors (bad palette fadein/out?)
|
||||
4. After game load in some areas (White Arch) top bar and inventory not redrawn due to (DrawFlags?) initialized incorrectly
|
||||
5. Mac reload feature uses hardcoded savefile from eden.dat
|
||||
6. First time in Tau's cave, try to take knife. When Dina objects, click on her - Tau's dialog will start (maybe it's original bug?)
|
||||
7. Mouse clipping may be lost during FMV scenes
|
||||
8. Screen doubling feature probably doesn't work (not really needed, can be replaced with built-in SCUMMVM scaler)
|
||||
9. Tons of debug messages spam when hover mouse over party icons or menu buttons
|
117
engines/cryo/clsoundgroup.c
Normal file
117
engines/cryo/clsoundgroup.c
Normal file
@ -0,0 +1,117 @@
|
||||
#include "cryolib.h"
|
||||
|
||||
soundgroup_t* CLSoundGroup_New(short numSounds, short arg4, short sampleSize, float rate, short mode)
|
||||
{
|
||||
soundgroup_t *sg;
|
||||
short i;
|
||||
|
||||
sg = (soundgroup_t*)CLMemory_Alloc(sizeof(*sg));
|
||||
if(numSounds < CL_MAX_SOUNDS)
|
||||
sg->numSounds = numSounds;
|
||||
else
|
||||
{
|
||||
__libError = -3;
|
||||
__osError = 0;
|
||||
CLCheckError();
|
||||
sg->numSounds = CL_MAX_SOUNDS;
|
||||
}
|
||||
for(i = 0;i < sg->numSounds;i++)
|
||||
{
|
||||
sound_t *sound = CLSoundRaw_New(arg4, rate, sampleSize, mode);
|
||||
sg->sound[i] = sound;
|
||||
sound->ff_1A = arg4;
|
||||
}
|
||||
sg->soundIndex = 0;
|
||||
sg->playIndex = 0;
|
||||
sg->ff_106 = 1;
|
||||
|
||||
return sg;
|
||||
}
|
||||
|
||||
void CLSoundGroup_Free(soundgroup_t *sg)
|
||||
{
|
||||
short i;
|
||||
for(i = 0;i < sg->numSounds;i++)
|
||||
CLSoundRaw_Free(sg->sound[i]);
|
||||
CLMemory_Free(sg);
|
||||
}
|
||||
|
||||
void CLSoundGroup_Reverse16All(soundgroup_t *sg)
|
||||
{
|
||||
short i;
|
||||
for(i = 0;i < sg->numSounds;i++)
|
||||
sg->sound[i]->reversed = 1;
|
||||
}
|
||||
|
||||
void* CLSoundGroup_GetNextBuffer(soundgroup_t *sg)
|
||||
{
|
||||
sound_t *sound = sg->sound[sg->soundIndex];
|
||||
if(sg->ff_106)
|
||||
while(sound->locked) ;
|
||||
return ((char*)(*sound->sndHandle)) + sound->headerLen;
|
||||
}
|
||||
|
||||
short CLSoundGroup_AssignDatas(soundgroup_t *sg, void *buffer, int length, short isSigned)
|
||||
{
|
||||
sound_t *sound = sg->sound[sg->soundIndex];
|
||||
if(sg->ff_106)
|
||||
while(sound->locked) ;
|
||||
else
|
||||
if(sound->locked)
|
||||
return 0;
|
||||
sound->buffer = (char*)buffer;
|
||||
CLSound_SetLength(sound, length);
|
||||
sound->length = length;
|
||||
// if(sound->reversed && sound->sampleSize == 16)
|
||||
// ReverseBlock16(buffer, length);
|
||||
// if(isSigned)
|
||||
// CLSound_Signed2NonSigned(buffer, length);
|
||||
if(sg->soundIndex == sg->numSounds - 1)
|
||||
sg->soundIndex = 0;
|
||||
else
|
||||
sg->soundIndex++;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
short CLSoundGroup_SetDatas(soundgroup_t *sg, void *data, int length, short isSigned)
|
||||
{
|
||||
void *buffer;
|
||||
sound_t *sound = sg->sound[sg->soundIndex];
|
||||
if(length >= sound->ff_1A)
|
||||
{
|
||||
__libError = -10;
|
||||
__osError = 0;
|
||||
CLCheckError();
|
||||
}
|
||||
if(sg->ff_106)
|
||||
while(sound->locked) ;
|
||||
else
|
||||
if(sound->locked)
|
||||
return 0;
|
||||
buffer = ((char*)(*sound->sndHandle)) + sound->headerLen;
|
||||
sound->buffer = (char*)buffer;
|
||||
memcpy(buffer, data, length);
|
||||
CLSound_SetLength(sound, length);
|
||||
sound->length = length;
|
||||
// if(sound->reversed && sound->sampleSize == 16)
|
||||
// ReverseBlock16(buffer, length);
|
||||
// if(isSigned)
|
||||
// CLSound_Signed2NonSigned(buffer, length);
|
||||
if(sg->soundIndex == sg->numSounds - 1)
|
||||
sg->soundIndex = 0;
|
||||
else
|
||||
sg->soundIndex++;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CLSoundGroup_PlayNextSample(soundgroup_t *sg, soundchannel_t *ch)
|
||||
{
|
||||
CLSoundChannel_Play(ch, sg->sound[sg->playIndex]);
|
||||
if(sg->playIndex == sg->numSounds - 1)
|
||||
sg->playIndex = 0;
|
||||
else
|
||||
sg->playIndex++;
|
||||
|
||||
}
|
3
engines/cryo/configure.engine
Normal file
3
engines/cryo/configure.engine
Normal file
@ -0,0 +1,3 @@
|
||||
# This file is included from the main "configure" script
|
||||
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
|
||||
add_engine cryo "Lost Eden" no "" "" ""
|
81
engines/cryo/cryo.cpp
Normal file
81
engines/cryo/cryo.cpp
Normal file
@ -0,0 +1,81 @@
|
||||
#include "common/scummsys.h"
|
||||
|
||||
#include "common/config-manager.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/debug-channels.h"
|
||||
#include "common/error.h"
|
||||
#include "graphics/surface.h"
|
||||
#include "graphics/screen.h"
|
||||
#include "graphics/palette.h"
|
||||
#include "common/system.h"
|
||||
//#include "common/timer.h"
|
||||
|
||||
#include "engines/util.h"
|
||||
|
||||
#include "cryo/cryo.h"
|
||||
#include "cryo/eden.h"
|
||||
|
||||
namespace Cryo {
|
||||
|
||||
CryoEngine *g_ed = 0;
|
||||
|
||||
CryoEngine::CryoEngine(OSystem *syst, const ADGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc), _console(nullptr) {
|
||||
// Put your engine in a sane state, but do nothing big yet;
|
||||
// in particular, do not load data from files; rather, if you
|
||||
// need to do such things, do them from run().
|
||||
|
||||
// Do not initialize graphics here
|
||||
// Do not initialize audio devices here
|
||||
|
||||
// However this is the place to specify all default directories
|
||||
// const Common::FSNode gameDataDir(ConfMan.get("path"));
|
||||
// SearchMan.addSubDirectoryMatching(gameDataDir, "sound");
|
||||
|
||||
// Here is the right place to set up the engine specific debug channels
|
||||
DebugMan.addDebugChannel(kCryoDebugExample, "example", "this is just an example for a engine specific debug channel");
|
||||
DebugMan.addDebugChannel(kCryoDebugExample2, "example2", "also an example");
|
||||
|
||||
// Don't forget to register your random source
|
||||
_rnd = new Common::RandomSource("cryo");
|
||||
|
||||
debug("CryoEngine::CryoEngine");
|
||||
|
||||
g_ed = this;
|
||||
}
|
||||
|
||||
CryoEngine::~CryoEngine() {
|
||||
debug("CryoEngine::~CryoEngine");
|
||||
|
||||
// Dispose your resources here
|
||||
delete _rnd;
|
||||
|
||||
// Remove all of our debug levels here
|
||||
DebugMan.clearAllDebugChannels();
|
||||
}
|
||||
|
||||
Common::Error CryoEngine::run() {
|
||||
// Initialize graphics using following:
|
||||
initGraphics(320, 200, false);
|
||||
_screen.create(320, 200, Graphics::PixelFormat::createFormatCLUT8());
|
||||
|
||||
// Create debugger console. It requires GFX to be initialized
|
||||
_console = new Console(this);
|
||||
|
||||
// Additional setup.
|
||||
debug("CryoEngine::init");
|
||||
|
||||
// Your main even loop should be (invoked from) here.
|
||||
debug("CryoEngine::go: Hello, World!");
|
||||
|
||||
// This test will show up if -d1 and --debugflags=example are specified on the commandline
|
||||
debugC(1, kCryoDebugExample, "Example debug call");
|
||||
|
||||
// This test will show up if --debugflags=example or --debugflags=example2 or both of them and -d3 are specified on the commandline
|
||||
debugC(3, kCryoDebugExample | kCryoDebugExample2, "Example debug call two");
|
||||
|
||||
game.main();
|
||||
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
} // End of namespace Cryo
|
62
engines/cryo/cryo.h
Normal file
62
engines/cryo/cryo.h
Normal file
@ -0,0 +1,62 @@
|
||||
#ifndef CRYO_H
|
||||
#define CRYO_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/config-manager.h"
|
||||
#include "engines/advancedDetector.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/debug-channels.h"
|
||||
#include "common/error.h"
|
||||
#include "common/random.h"
|
||||
#include "engines/engine.h"
|
||||
#include "gui/debugger.h"
|
||||
#include "graphics/surface.h"
|
||||
#include "graphics/screen.h"
|
||||
#include "cryo/eden.h"
|
||||
|
||||
namespace Cryo {
|
||||
|
||||
class Console;
|
||||
|
||||
// our engine debug channels
|
||||
enum {
|
||||
kCryoDebugExample = 1 << 0,
|
||||
kCryoDebugExample2 = 1 << 1
|
||||
// next new channel must be 1 << 2 (4)
|
||||
// the current limitation is 32 debug channels (1 << 31 is the last one)
|
||||
};
|
||||
|
||||
class CryoEngine : public Engine {
|
||||
public:
|
||||
CryoEngine(OSystem *syst, const ADGameDescription *gameDesc);
|
||||
~CryoEngine();
|
||||
|
||||
virtual Common::Error run();
|
||||
|
||||
// Detection related functions
|
||||
const ADGameDescription *_gameDescription;
|
||||
const char *getGameId() const;
|
||||
Common::Platform getPlatform() const;
|
||||
|
||||
// We need random numbers
|
||||
Common::RandomSource *_rnd;
|
||||
|
||||
Graphics::Surface _screen;
|
||||
EdenGame game;
|
||||
|
||||
private:
|
||||
Console *_console;
|
||||
};
|
||||
|
||||
extern CryoEngine *g_ed;
|
||||
|
||||
// Example console class
|
||||
class Console : public GUI::Debugger {
|
||||
public:
|
||||
Console(CryoEngine *vm) {}
|
||||
virtual ~Console(void) {}
|
||||
};
|
||||
|
||||
} // End of namespace Cryo
|
||||
|
||||
#endif
|
1399
engines/cryo/defs.h
Normal file
1399
engines/cryo/defs.h
Normal file
File diff suppressed because it is too large
Load Diff
131
engines/cryo/detection.cpp
Normal file
131
engines/cryo/detection.cpp
Normal file
@ -0,0 +1,131 @@
|
||||
/* 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 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "base/plugins.h"
|
||||
|
||||
#include "engines/advancedDetector.h"
|
||||
#include "common/file.h"
|
||||
|
||||
#include "cryo/cryo.h"
|
||||
|
||||
|
||||
namespace Cryo {
|
||||
|
||||
const char *CryoEngine::getGameId() const {
|
||||
return _gameDescription->gameId;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static const PlainGameDescriptor cryoGames[] = {
|
||||
{"losteden", "Lost Eden"},
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
namespace Cryo {
|
||||
|
||||
static const ADGameDescription gameDescriptions[] = {
|
||||
|
||||
// Lost Eden PC non-interactive demo version
|
||||
// Probably not worth it
|
||||
{
|
||||
"losteden",
|
||||
0,
|
||||
AD_ENTRY1s("EDEN6.HSQ", nullptr, 17093),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_DEMO,
|
||||
GUIO1(GUIO_NONE)
|
||||
},
|
||||
|
||||
// Lost Eden PC interactive demo version
|
||||
{
|
||||
"losteden",
|
||||
0,
|
||||
AD_ENTRY1s("EDEN.DAT", nullptr, 205473728),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_DEMO,
|
||||
GUIO1(GUIO_NONE)
|
||||
},
|
||||
|
||||
// Lost Eden PC version
|
||||
{
|
||||
"losteden",
|
||||
0,
|
||||
AD_ENTRY1s("EDEN.DAT", nullptr, 449853776),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NONE)
|
||||
},
|
||||
|
||||
// Lost Eden Mac version
|
||||
{
|
||||
"losteden",
|
||||
0,
|
||||
AD_ENTRY1s("EDEN.DAT", nullptr, 489739536),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NONE)
|
||||
},
|
||||
|
||||
AD_TABLE_END_MARKER
|
||||
};
|
||||
|
||||
} // End of namespace Cryo
|
||||
|
||||
class CryoMetaEngine : public AdvancedMetaEngine {
|
||||
public:
|
||||
CryoMetaEngine() : AdvancedMetaEngine(Cryo::gameDescriptions, sizeof(ADGameDescription), cryoGames) {
|
||||
_singleId = "losteden";
|
||||
}
|
||||
|
||||
virtual const char *getName() const {
|
||||
return "Cryo Engine";
|
||||
}
|
||||
|
||||
virtual const char *getOriginalCopyright() const {
|
||||
return "Cryo Engine (C) Cryo Interactive";
|
||||
}
|
||||
|
||||
virtual bool hasFeature(MetaEngineFeature f) const;
|
||||
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
|
||||
};
|
||||
|
||||
bool CryoMetaEngine::hasFeature(MetaEngineFeature f) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CryoMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
|
||||
if (desc) {
|
||||
*engine = new Cryo::CryoEngine(syst, desc);
|
||||
}
|
||||
return desc != 0;
|
||||
}
|
||||
|
||||
#if PLUGIN_ENABLED_DYNAMIC(CRYO)
|
||||
REGISTER_PLUGIN_DYNAMIC(CRYO, PLUGIN_TYPE_ENGINE, CryoMetaEngine);
|
||||
#else
|
||||
REGISTER_PLUGIN_STATIC(CRYO, PLUGIN_TYPE_ENGINE, CryoMetaEngine);
|
||||
#endif
|
9457
engines/cryo/eden.cpp
Normal file
9457
engines/cryo/eden.cpp
Normal file
File diff suppressed because it is too large
Load Diff
14
engines/cryo/eden.h
Normal file
14
engines/cryo/eden.h
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#define EDEN_DEBUG
|
||||
|
||||
namespace Cryo {
|
||||
|
||||
class EdenGame {
|
||||
public:
|
||||
void main();
|
||||
};
|
||||
|
||||
class EdenGameImpl;
|
||||
|
||||
}
|
24
engines/cryo/gameflow.txt
Normal file
24
engines/cryo/gameflow.txt
Normal file
@ -0,0 +1,24 @@
|
||||
|
||||
game phases
|
||||
|
||||
0 - game start
|
||||
10 - enter throne room
|
||||
20 - heard talk of eloi and father
|
||||
30 - in prince's room
|
||||
40 - met dina
|
||||
41 - talking to tau room: 202
|
||||
50 - tau died
|
||||
60 - talked to jabber
|
||||
70 - got a gift from jabber
|
||||
71 - part with dina at secret crypt
|
||||
80 - learned about fresques / got flute
|
||||
81 - convinced monk to help
|
||||
82 - enter throne room
|
||||
90 - got king's permission
|
||||
A0 - met chong
|
||||
A1 - chong joins party
|
||||
B0 - on valley screen after citadel build complete
|
||||
C0 - met ulan
|
||||
D0 - build citadel in uluru
|
||||
E0 - got gift from ulan
|
||||
...
|
14
engines/cryo/module.mk
Normal file
14
engines/cryo/module.mk
Normal file
@ -0,0 +1,14 @@
|
||||
MODULE := engines/cryo
|
||||
|
||||
MODULE_OBJS = \
|
||||
cryo.o \
|
||||
eden.o \
|
||||
detection.o
|
||||
|
||||
# This module can be built as a plugin
|
||||
ifeq ($(ENABLE_CRYO), DYNAMIC_PLUGIN)
|
||||
PLUGIN := 1
|
||||
endif
|
||||
|
||||
# Include common rules
|
||||
include $(srcdir)/rules.mk
|
26
engines/cryo/platdefs.h
Normal file
26
engines/cryo/platdefs.h
Normal file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#if 1
|
||||
#include "common/file.h"
|
||||
|
||||
typedef Common::File file_t;
|
||||
|
||||
struct filespec_t {
|
||||
char create;
|
||||
char name[260];
|
||||
};
|
||||
|
||||
#if 1
|
||||
const int subtitles_x_margin = 16; //PC
|
||||
const int subtitles_x_scr_margin = 16;
|
||||
const int space_width = 6;
|
||||
#define FAKE_DOS_VERSION
|
||||
#else
|
||||
const int subtitles_x_margin = 16; //MAC
|
||||
const int subtitles_x_scr_margin = 16; //MAC
|
||||
const int space_width = 4;
|
||||
#endif
|
||||
const int subtitles_x_width = (320 - subtitles_x_margin * 2);
|
||||
const int subtitles_x_center = subtitles_x_width / 2;
|
||||
|
||||
#endif
|
80
engines/cryo/readme.txt
Normal file
80
engines/cryo/readme.txt
Normal file
@ -0,0 +1,80 @@
|
||||
Citadel of Mo, the last remaining place where humans can be safe from army
|
||||
of vicious Tyrannosaurus led by allmighty Morkus Rex. What await young Adam,
|
||||
prince of Mo, who just came of age and want to travel across the world?
|
||||
Will he be able to restore long lost friendship between dinousaurus and humans?
|
||||
|
||||
|
||||
This is SCUMMVM reimplementation of Cryo's Lost Eden game engine. In order to
|
||||
stay as close as possible to original game and minimize number of bugs
|
||||
introduced during code reconstruction, in its current state this project is
|
||||
a straight reverse-engineered game code hooked up to SCUMMVM framework.
|
||||
Because of that, this code in no way represent the quality or coding practices
|
||||
of SCUMMVM itself. Essentially, this is how the game was originally written.
|
||||
|
||||
There are few Lost Eden game versions known to exists.
|
||||
|
||||
- Non-interactive PC demo version. Basically, a number of video files played
|
||||
in a loop with FM music in background. Google for "ANCIBUR2.HNM" file to
|
||||
find it.
|
||||
|
||||
- Interactive PC demo version. Allows to play through whole Citadel of Mo
|
||||
then shows "Order Now" banner.
|
||||
Can be found here: http://www.ag.ru/games/lost-eden/demos/2677
|
||||
Download is a self-extracting archive, unpack it with 7zip or other tool.
|
||||
|
||||
- PC version. Main version of the game. Written in assembly and partially based
|
||||
on Dune's game code.
|
||||
Runs in real-mode DOS environment, uses VGA 320x200 graphics and digitized
|
||||
sounds/music. Allows to select several languages for in-game subtitles. It is
|
||||
rumored that bootleg Russian translation also exists. Has 3 predefined slots
|
||||
for game save/load.
|
||||
|
||||
- MAC version. Almost identical to PC version. Has slightly modified UI. Such
|
||||
as exta spaces on the inventory bar, resized subtitles overlay and different
|
||||
implementation of mouse cursor (which is worse than the original one). Looks
|
||||
like screen transition effects are also changed / rearranged.
|
||||
This version have no limit on save game slots. Standard system file selection
|
||||
dialogs are used instead. All screen hot-spots coordinates loaded from
|
||||
resource file instead of hard-coded values in PC version.
|
||||
|
||||
- 3DO version. Uses completely different resource formats.
|
||||
|
||||
- CDI version. Uses completely different resource formats.
|
||||
|
||||
- CD32 version. Mentioned in PC demo version, but never released?
|
||||
|
||||
|
||||
This reimplementation project is based on MAC version, since it's much easier
|
||||
to work with than any other versions. As such, currently only MAC version
|
||||
supported. Adding support for PC versions shouldn't be too difficult and
|
||||
mainly involves implementing of proper resources indexing/loading. Game
|
||||
engine loads resources by their indexes in game archive file and these indexes
|
||||
are different between PC and MAC versions.
|
||||
|
||||
At this moment the game is fully playabe/completeable. List of currently
|
||||
discovered bugs can be found in bugs.txt file. None of those are critical or
|
||||
game-breaking. No sound support is present in this version, although all
|
||||
sound front-end code is in place and should be operational. Only single
|
||||
game save/load slot is supported and saves are not cross-platform compatible.
|
||||
Also, no game restart feature work due to the way it's implemented.
|
||||
|
||||
Due to the way original engine is coded, it is not fully portable in its
|
||||
current state. Game uses conditional dialog system (similar system is used in
|
||||
Dune game as well) and this system involves accessing native engine
|
||||
variables through predefined offsets within large structure. Any modification
|
||||
of this structure will result in broken dialog system.
|
||||
|
||||
Because of limited development environment, this code is only tested on
|
||||
MSVS2013 32-bit compiler. There may be some issues with GCC/LLVM compilers
|
||||
or on 64-bit platforms. As mentioned above, this code is neither pretty or
|
||||
bug-free (aka it's a can of worms). Several original bugs, various oddities
|
||||
and problematic areas are marked with TODO comment in the source code. There
|
||||
are number of variables with non-descripitve names like byte_1234, those
|
||||
purpose is yet to be clearly understood. To make code debugging easier,
|
||||
EDEN_DEBUG macro activates several extra features. Some parts, like image
|
||||
drawing routines, can be simplified/generalized. Other parts, like CLView,
|
||||
can be replaced with existing SCUMMVM classes.
|
||||
|
||||
Because parts of this code (mainly decompression and video playback) used
|
||||
by other Cryo's games, it might be worthy to make them reusable by future
|
||||
engines.
|
Loading…
x
Reference in New Issue
Block a user