CRYO: Lost Eden game engine initial commit

This commit is contained in:
Retro-Junk 2016-07-30 23:15:32 +03:00 committed by Eugene Sandulenko
parent e25bac9690
commit ecf0d04104
22 changed files with 13439 additions and 0 deletions

3
engines/cryo/CLError.c Normal file
View File

@ -0,0 +1,3 @@
#include "cryolib.h"
short __debug, __libError, __osError;

874
engines/cryo/CLHNM.c Normal file
View 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
View 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
View 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
View 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"

View File

@ -0,0 +1,7 @@
#include "LempelZiv.h"
namespace Cryo {
}

102
engines/cryo/LempelZiv.h Normal file
View 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);
}
};
}

View 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;
}
}

View 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
View 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
View 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++;
}

View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

131
engines/cryo/detection.cpp Normal file
View 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

File diff suppressed because it is too large Load Diff

14
engines/cryo/eden.h Normal file
View 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
View 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
View 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
View 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
View 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.