MuckyFoot-UrbanChaos/fallen/Source/cutscene.cpp
2017-05-20 11:14:17 +10:00

2157 lines
56 KiB
C++

// cutscene.cpp
// matthew rosenfeld 22 apr 1999
#include <MFStdLib.h>
#include <windows.h>
#include <windowsx.h>
#include <ddlib.h>
#include <commctrl.h>
#include "resource.h"
#include "inline.h"
#include "gi.h"
#include "fmatrix.h"
#include "game.h"
#include "person.h"
#include "GEdit.h"
#include "MapView.h"
#include "console.h"
#include "propedit.h"
#include "cutscene.h"
#include "c:\fallen\editor\headers\anim.h"
#include "poly.h"
#include "polypage.h"
#include "animate.h"
#include "fc.h"
#include "drawxtra.h"
#include "mfx.h"
#include "sound.h"
#include "sound_id.h"
#include "font2d.h"
#define IM_SCENE_FOLDER (0)
#define IM_SCENE_SPEAKER (1)
#define IM_SCENE_PERSON (2)
#define IM_SCENE_ANIM (3)
#define IM_SCENE_CAMERA (4)
#define IM_SCENE_WAVE (5)
#define IM_SCENE_ACTION (6)
#define IM_SCENE_WARNING (7)
#define IM_SCENE_BUBBLE (8)
#define CT_CHAR (1)
#define CT_CAM (2)
#define CT_WAVE (3)
#define CT_FX (4)
#define CT_TEXT (5)
#define PT_ANIM (1)
#define PT_ACTION (2)
#define PT_WAVE (3)
#define PT_CAM (4)
#define PT_TEXT (5)
#define CUTSCENE_DATA_VERSION (2)
#define PF_BACKWARDS (1) // for anims
#define PF_SECURICAM (1) // for cameras
#define PF_INTERPOLATE_MOVE (2) // for both
#define PF_SMOOTH_MOVE_IN (4)
#define PF_SMOOTH_MOVE_OUT (8)
#define PF_SMOOTH_MOVE_BOTH (PF_SMOOTH_MOVE_IN|PF_SMOOTH_MOVE_OUT)
#define PF_INTERPOLATE_ROT (16)
#define PF_SMOOTH_ROT_IN (32)
#define PF_SMOOTH_ROT_OUT (64)
#define PF_SMOOTH_ROT_BOTH (PF_SMOOTH_ROT_IN|PF_SMOOTH_ROT_OUT)
#define PF_SLOMO (128)
// channel memory is reserved in chunks, and expanded when needed
// by creating a new block and copying the old one across. this isn't
// terribly quick, but it's irrelevant in the editor, and in the game
// the number of channels is known at load-time. saves wasting in-game
// memory on stuff like prev/next linked list pointers.
struct CSEditChannel;
struct CSData {
UBYTE version;
UBYTE channelcount;
UBYTE pad1, pad2;
CSChannel *channels;
CSEditChannel *editchannels;
};
struct CSChannel {
UBYTE type; // 0=unused, 1=character, 2=camera, 3=spot sound, 4=vfx
UBYTE flags; // come up with some later... :P
UBYTE pad1,pad2;
UWORD index; // of the sound/character or the type of fx
UWORD packetcount; //
CSPacket *packets; //
};
struct CSPacket {
UBYTE type; // 0=unused, 1=animation, 2=action, 3=sound, 4=camerarec 0
UBYTE flags; // come up with some later... :P
UWORD index; // of animation, sound etc 4
UWORD start; // time of packet start
UWORD length; // natural packet length 8
GameCoord pos; // location 20
UWORD angle,pitch;// no roll :P
};
// this is a parallel to CSData which is not saved, but created afresh as you 'load' a CSData
// and freed on exit. it stores info the editor needs to keep track of but the game doesn't give
// a toss about
struct CSEditChannel {
CSChannel* data;
Thing* thing;
};
//---------------------------------------------------------------
CBYTE interpolate_strings[]="snap|linear|smooth in|smooth out|smooth both";
//---------------------------------------------------------------
#define SLOMO_RATE (10)
PropertyEditor *pedit;
TreeBrowser *browser;
DragServer *drag;
TimeLine *timeline;
TimeLineRuler *ruler;
TimeLineScroll *scroll;
CSData *cutscene;
CSPacket *current_packet=0;
HWND CUTSCENE_edit_wnd=0;
BOOL CUTSCENE_mouselook=0;
BOOL CUTSCENE_playback=0;
BOOL CUTSCENE_slomo=0;
BOOL CUTSCENE_need_keyboard=0;
HTREEITEM darcianim,roperanim,soundbase;
int CUTSCENE_slomo_ctr=SLOMO_RATE;
UBYTE CUTSCENE_fade_level=255;
CBYTE subtitle_str[255];
//---------------------------------------------------------------
extern void calc_camera_pos(void);
//---------------------------------------------------------------
// Data structure handlers -- alloc, free, etc
void CUTSCENE_chan_free(CSChannel &chan) {
int i;
CSPacket *pkt=chan.packets;
for (i=0;i<chan.packetcount;i++,pkt++)
if ((pkt->type==PT_TEXT)&&(pkt->pos.X))
free((CBYTE*)pkt->pos.X);
if (chan.packets) delete [] chan.packets;
}
void CUTSCENE_editchan_free(CSEditChannel &chan) {
if (chan.thing) {
//if (chan.data->type==CT_CHAR) free_person(chan.thing);
THING_kill(chan.thing);
}
chan.thing=0;
}
void CUTSCENE_chan_delete(CSData* cutscene, int chan) {
CSChannel *buff, *buff2;
CSEditChannel *edit, *edit2;
int ct=cutscene->channelcount-1;
if ((chan<0)||(chan>ct)) return;
buff=cutscene->channels+chan;
// frees Thing structures and the like associated with the channel
CUTSCENE_editchan_free(cutscene->editchannels[chan]);
// this only frees the resources allocated by the channel, not the channel itself :(
// yes, that sucks
CUTSCENE_chan_free(*buff);
// now free the channel itself (messy)
buff2 = buff = new CSChannel[ct];
if (chan>0) {
memcpy(buff,cutscene->channels,sizeof(cutscene->channels[0])*chan);
buff2+=chan;
}
if (chan<ct) {
memcpy(buff2,cutscene->channels+chan+1,sizeof(cutscene->channels[0])*(ct-chan));
}
delete [] cutscene->channels;
edit2 = edit = new CSEditChannel[ct];
if (chan>0) {
memcpy(edit,cutscene->editchannels,sizeof(cutscene->editchannels[0])*chan);
edit2+=chan;
}
if (chan<ct) {
memcpy(edit2,cutscene->editchannels+chan+1,sizeof(cutscene->editchannels[0])*(ct-chan));
}
delete [] cutscene->editchannels;
cutscene->channelcount--;
cutscene->channels=buff;
cutscene->editchannels=edit;
}
CSData* CUTSCENE_data_alloc() {
CSData* data = new CSData;
data->channelcount=0;
data->version=CUTSCENE_DATA_VERSION;
data->channels=0;
data->editchannels=0;
return data;
}
void CUTSCENE_data_free(CSData* data) {
if (data->channels) {
int i;
for (i=0;i<data->channelcount;i++) {
CUTSCENE_chan_free(data->channels[i]);
CUTSCENE_editchan_free(data->editchannels[i]);
}
delete [] data->channels;
delete [] data->editchannels;
}
delete data;
}
CSChannel* CUTSCENE_add_channel(CSData* data) {
CSChannel* buff = new CSChannel[data->channelcount+1];
memcpy(buff,data->channels,sizeof(data->channels[0])*data->channelcount);
delete [] data->channels;
// data->channelcount++;
data->channels=buff;
buff=&data->channels[data->channelcount];
buff->flags=0; buff->packetcount=0; buff->packets=0; buff->index=0; buff->type=0;
CSEditChannel* buff2 = new CSEditChannel[data->channelcount+1];
memcpy(buff2,data->editchannels,sizeof(data->editchannels[0])*data->channelcount);
delete [] data->editchannels;
data->editchannels=buff2;
buff2=&data->editchannels[data->channelcount];
data->channelcount++;
buff2->data=buff;
buff2->thing=0;
return buff;
}
CSPacket* CUTSCENE_add_packet(CSChannel* chan) {
CSPacket* buff = new CSPacket[chan->packetcount+1];
memcpy(buff,chan->packets,sizeof(chan->packets[0])*chan->packetcount);
delete [] chan->packets;
chan->packetcount++;
chan->packets=buff;
buff=&chan->packets[chan->packetcount-1];
buff->flags=0; buff->length=0; buff->type=0;
return buff;
}
void CUTSCENE_del_packet(CSChannel* chan, int pack) {
CSPacket* buff;
CSPacket* buff2;
int ct=chan->packetcount-1;
if ((pack<0)||(pack>=chan->packetcount)) return;
buff=chan->packets+pack;
if ((buff->type==PT_TEXT)&&(buff->pos.X)) free((CBYTE*)buff->pos.X);
buff2 = buff = new CSPacket[ct];
if (pack>0) {
memcpy(buff,chan->packets,sizeof(chan->packets[0])*pack);
buff2+=pack;
}
if (pack<ct) {
memcpy(buff2,chan->packets+pack+1,sizeof(chan->packets[0])*(ct-pack));
}
delete [] chan->packets;
chan->packetcount--;
chan->packets=buff;
}
CSPacket *CUTSCENE_get_packet(CSChannel* chan, int cell) {
CSPacket* pkt=chan->packets;
int ctr=1;
if ((cell<0)||(cell>2000)) return 0;
while (pkt&&(pkt->start!=cell)) {
pkt++;
ctr++;
if (ctr>chan->packetcount) pkt=0;
}
return pkt;
}
//-----------------------------------------------------
// Load/save cutscene data
//-----------------------------------------------------
void CUTSCENE_write_packet(FILE *file_handle, CSPacket* pack, int version) {
fwrite((void*)pack,sizeof(CSPacket),1,file_handle);
if ((pack->type==PT_TEXT)&&(pack->pos.X)) {
int l=strlen((CBYTE*)pack->pos.X);
fwrite((void*)&l,sizeof(l),1,file_handle);
fwrite((void*)pack->pos.X,l,1,file_handle);
}
}
void CUTSCENE_write_channel(FILE *file_handle, CSChannel* chan, int version) {
SLONG packnum;
CSPacket* pack=chan->packets;
fwrite((void*)chan,sizeof(CSChannel),1,file_handle);
for (packnum=0;packnum<chan->packetcount;packnum++,pack++) CUTSCENE_write_packet(file_handle,pack,version);
}
void CUTSCENE_write(FILE *file_handle, CSData* cutscene) {
UBYTE channum;
CSChannel* chan=cutscene->channels;
cutscene->version=CUTSCENE_DATA_VERSION;
fwrite((void*)&cutscene->version,1,1,file_handle);
fwrite((void*)&cutscene->channelcount,1,1,file_handle);
for (channum=0;channum<cutscene->channelcount;channum++,chan++) CUTSCENE_write_channel(file_handle,chan,cutscene->version);
}
// --- read ---
void CUTSCENE_read_packet(FILE *file_handle, CSChannel* chan, int version) {
CSPacket *pack = CUTSCENE_add_packet(chan);
fread((void*)pack,sizeof(CSPacket),1,file_handle);
switch(version) {
case 1:
if (pack->type==PT_CAM) pack->length=0xff7f;
break;
}
switch(pack->type) {
case PT_TEXT:
if (pack->pos.X) {
int l;
fread((void*)&l,sizeof(l),1,file_handle);
pack->pos.X=(int)malloc(l+1);
ZeroMemory((void*)pack->pos.X,l+1);
fread((void*)pack->pos.X,l,1,file_handle);
}
break;
}
}
void CUTSCENE_read_channel(FILE *file_handle, CSData* cutscene) {
SLONG packnum, packct;
CSChannel *chan = CUTSCENE_add_channel(cutscene);
fread((void*)chan,sizeof(CSChannel),1,file_handle);
chan->packets=0; packct=chan->packetcount; chan->packetcount=0;
for (packnum=0;packnum<packct;packnum++) CUTSCENE_read_packet(file_handle,chan,cutscene->version);
}
void CUTSCENE_read(FILE *file_handle, CSData** cutsceneref) {
UBYTE channum, chanct;
CSData* cutscene=CUTSCENE_data_alloc();
*cutsceneref=cutscene;
fread((void*)&cutscene->version,1,1,file_handle);
fread((void*)&chanct,1,1,file_handle); // cutscene->channelcount will be updated by read_channel's call to add_channel...
for (channum=0;channum<chanct;channum++) CUTSCENE_read_channel(file_handle,cutscene);
}
//-----------------------------------------------------
// Recreate in-editor data for cutscene
//-----------------------------------------------------
Thing* CUTSCENE_create_person(UBYTE person_type, SLONG x, SLONG y, SLONG z) {
SLONG person_index;
person_index = create_person(
person_type,
0,
x << 8,
y << 8,
z << 8);
return TO_THING(person_index);
}
CBYTE* PeopleStrings[] = { "Darci", "Roper", "Cop", "Civvy", "Rasta Thug", "Grey Thug",
"Red Thug", "Tart", "Slag", "Hostage", "Mechanic", "Tramp", "MIB 1", "MIB 2", "MIB 3" };
void CUTSCENE_recreate(CSData* cutscene) {
int channum, pktnum, image, who;
CSChannel *chan;
CSEditChannel *edit;
CSPacket *pkt;
CBYTE msg[600];
chan=cutscene->channels;
edit=cutscene->editchannels;
for (channum=0;channum<cutscene->channelcount;channum++) {
pkt=chan->packets;
switch(chan->type) {
case CT_CHAR:
msg[0]=IM_SCENE_PERSON;
if ((chan->index>0)&&(chan->index<16))
strcpy(msg+1,PeopleStrings[chan->index-1]);
else
strcpy(msg+1,"Some Person");
if ((chan->index>0)&&(chan->index<=PERSON_NUM_TYPES))
who=chan->index-1;
else
who=-1;
/* switch(chan->index) {
case 1: who=PERSON_DARCI; break;
case 2: who=PERSON_ROPER; break;
default: who=-1;
}*/
if (who>-1)
edit->thing=CUTSCENE_create_person(who,64<<8,0,64<<8);
else
edit->thing=0;
timeline->Add(msg);
for(pktnum=0;pktnum<chan->packetcount;pkt++,pktnum++) {
timeline->MarkEntry(channum,pkt->start,pkt->length,1);
}
break;
case CT_CAM:
msg[0]=IM_SCENE_CAMERA;
strcpy(msg+1,"Camera");
timeline->Add(msg);
for(pktnum=0;pktnum<chan->packetcount;pkt++,pktnum++) {
timeline->MarkEntry(channum,pkt->start,1,4); // always 1, and besides, ct_cam's length is used for Other Things(tm)
}
break;
case CT_WAVE:
msg[0]=IM_SCENE_SPEAKER;
strcpy(msg+1,"Loudspeaker");
timeline->Add(msg);
for(pktnum=0;pktnum<chan->packetcount;pkt++,pktnum++) {
timeline->MarkEntry(channum,pkt->start,1,4);
}
break;
case CT_TEXT:
msg[0]=IM_SCENE_BUBBLE;
strcpy(msg+1,"Subtitles");
timeline->Add(msg);
for(pktnum=0;pktnum<chan->packetcount;pkt++,pktnum++) {
timeline->MarkEntry(channum,pkt->start,pkt->length,4);
}
break;
case CT_FX:
msg[0]=(CBYTE)0xff;
strcpy(msg+1,"FX");
timeline->Add(msg);
break;
default:
msg[0]=(CBYTE)0xff;
strcpy(msg+1,"hell if i know");
timeline->Add(msg);
break;
}
chan++;
edit++;
}
timeline->SetReadHead(0);
timeline->Repaint();
}
void CUTSCENE_remove(CSData* cutscene) {
int channum;
CSChannel *chan;
CSEditChannel *edit;
chan=cutscene->channels;
edit=cutscene->editchannels;
for (channum=0;channum<cutscene->channelcount;channum++,chan++,edit++) {
if (edit->thing) {
THING_kill(edit->thing);
edit->thing=0;
}
}
}
//-----------------------------------------------------
/*
SLONG CUTSCENE_how_long_is_anim(SLONG who, SLONG anim)
{
GameKeyFrame *frame;
SLONG total=0;
frame=global_anim_array[who][anim];
while(frame)
{
SLONG step;
step=frame->TweenStep;
if(!step)
step=1;
total+=256/step;
if(frame->Flags&ANIM_FLAG_LAST_FRAME)
break;
frame = frame->NextFrame;
}
return(total);
}
*/
//---------------------------------------------------------------
// Object Inspector Handler
/*
void InitProps(PropertyEditor *pedit, UWORD type) {
pedit->Clear();
switch (type) {
case 0:
/+ pedit->Add("Name","Unknown",PROPTYPE_STRING);
pedit->Add("Data","Flirble",PROPTYPE_STRING);
pedit->Add("Schlerb","1",PROPTYPE_INT);
pedit->Add("booltest","off",PROPTYPE_BOOL);
pedit->Add("multitst","one|two|three|four",PROPTYPE_MULTI);+/
// pedit->Add("insanetst","one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty|twentyone|blah|wibble|moo|i|just|need|to|pad|this|out|as|much|asis|possible|la|le|lo|li|lu|mi|mo|mu|ma|me|mi|marp|peep|footle",PROPTYPE_MULTI);
break;
}
}
*/
SLONG LoadAllAnimNames(CBYTE *fname, TreeBrowser *browser, SLONG base_ctr);
int GetItemIndex(CBYTE *str, CBYTE *pathtail) {
int i;
CBYTE combined[_MAX_PATH];
strcpy(combined,pathtail);
strcat(combined,str);
i=0;
while (strcmp(sound_list[i],"!")) {
if (!stricmp(combined,sound_list[i])) {
return i;
}
i++;
}
return 0;
}
int ScanWavs(TreeBrowser *browser, CBYTE *path, BOOL subdirs, HTREEITEM parent, UBYTE indent, SLONG param, SLONG img, SLONG imgfld, CBYTE *pathtail) {
HANDLE handle;
BOOL res;
WIN32_FIND_DATA data;
CBYTE *pt;
int count=0, itemndx;
handle = FindFirstFile(path, &data);
res=(handle!=INVALID_HANDLE_VALUE);
while (res) {
if (!(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
if (itemndx=GetItemIndex(data.cFileName,pathtail))
browser->Add(data.cFileName,parent,indent,param+itemndx,img);
count++;
}
res=FindNextFile(handle,&data);
}
FindClose(handle);
if (!subdirs) return count;
pt=strrchr(path,'\\');
strcpy(pt,"\\*.*");
handle = FindFirstFile(path, &data);
res=(handle!=INVALID_HANDLE_VALUE);
while (res) {
if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)&&(data.cFileName[strlen(data.cFileName)-1]!='.')) {
CBYTE path2[_MAX_PATH], wild[_MAX_PATH], combo[_MAX_PATH];
int added;
strcpy(path2,path);
pt=strrchr(path2,'\\');
strcpy(wild,pt); pt++;
strcpy(pt,data.cFileName);
strcat(path2,wild);
browser->Add(data.cFileName,parent,indent,-1,imgfld);
strcpy(combo,pathtail);
strcat(combo,data.cFileName);
strcat(combo,"\\");
added=ScanWavs(browser,path2,true,0,indent+1,param,img,imgfld,combo);
// param+=added;
count+=added;
}
res=FindNextFile(handle,&data);
}
FindClose(handle);
return count;
}
void InitBrowser(HWND hWnd) {
int i;
browser = new TreeBrowser(hWnd);
browser->SetImageList(GEDIT_hinstance,IDB_SCENE_ICONS1);
browser->Add("People",0,0,-1,IM_SCENE_FOLDER);
/* browser->Add("Darci",0,1,1,IM_SCENE_PERSON);
browser->Add("Roper",0,1,2,IM_SCENE_PERSON);
browser->Add("Civilian",0,1,-1,IM_SCENE_FOLDER);
browser->Add("Bald Guy",0,2,3,IM_SCENE_PERSON);
browser->Add("Sports Casual Guy",0,2,4,IM_SCENE_PERSON);
browser->Add("Thug",0,1,5,IM_SCENE_PERSON);*/
for (i=0;i<PERSON_NUM_TYPES;i++)
browser->Add(PeopleStrings[i],0,1,i+1,IM_SCENE_PERSON);
browser->Add("Animations",0,0,-1,IM_SCENE_FOLDER);
darcianim=browser->Add("Darci's",0,1,-1,IM_SCENE_FOLDER);
LoadAllAnimNames("data\\darci1.anm",browser,0);
roperanim=browser->Add("Roper's",0,1,-1,IM_SCENE_FOLDER);
LoadAllAnimNames("data\\roper.anm",browser,1024);
// browser->Add("Tasks",0,0,-1,IM_SCENE_FOLDER);
// browser->Add("Go Here",0,1,8,IM_SCENE_ACTION);
browser->Add("Tools",0,0,-1,IM_SCENE_FOLDER);
browser->Add("Camera",0,1,9,IM_SCENE_CAMERA);
browser->Add("Loudspeaker",0,1,10,IM_SCENE_SPEAKER);
browser->Add("Subtitles",0,1,11,IM_SCENE_BUBBLE);
soundbase=browser->Add("Sound FX",0,0,-1,IM_SCENE_FOLDER);
// browser->AddDir("data\\sfx\\1622\\*.wav",true,0,1,2048,IM_SCENE_WAVE,IM_SCENE_FOLDER);
ScanWavs(browser,"data\\sfx\\1622\\*.wav",true,0,1,2048,IM_SCENE_WAVE,IM_SCENE_FOLDER,"");
}
/*
VOID CALLBACK tf(HWND hWnd, UINT message, UINT idEvent, DWORD dwTime) {
// PostMessage(hWnd, WM_USER, 0, 0);
// evil. eeee ville!
PostMessage(hWnd, WM_ENTERIDLE, 0, 0);
}
*/
//---------------------------------------------------------------
// yucky oh-god-i-have-to-deal-with-the-animation-filing-system-stuff
// all we want is the damn names!
#define ANIM_NAME_SIZE 64
void SkipBodyPartInfo(MFFileHandle file_handle)
{
SLONG c0,c1;
SLONG no_people,no_body_bits,string_len;
CBYTE *dummy;
UBYTE dummy2;
FileRead(file_handle,&no_people,sizeof(SLONG));
FileRead(file_handle,&no_body_bits,sizeof(SLONG));
FileRead(file_handle,&string_len,sizeof(SLONG));
for(c0=0;c0<no_people;c0++)
{
dummy=(CBYTE*)malloc(string_len+1);
FileRead(file_handle,dummy,string_len);
free(dummy);
for(c1=0;c1<no_body_bits;c1++)
FileRead(file_handle,&dummy2,sizeof(UBYTE));
}
}
void LoadAnim(MFFileHandle file_handle, TreeBrowser *browser, SLONG num)
{
CBYTE anim_name[ANIM_NAME_SIZE];
CBYTE full_name[ANIM_NAME_SIZE+20];
SLONG c0,
frame_count;
SWORD wdummy;
CBYTE version=0;
SLONG ldummy;
FileRead(file_handle,&version,1);
if(version==0||version>20)
{
anim_name[0]=version;
FileRead(file_handle,&anim_name[1],ANIM_NAME_SIZE-1);
version=0;
}
else
FileRead(file_handle,anim_name,ANIM_NAME_SIZE);
if ((global_anim_array[0][num]==global_anim_array[0][0])||!global_anim_array[0][num]) {
sprintf(full_name,"%d: (%s disabled)",num&1023,anim_name);
browser->Add(full_name,0,2,0,IM_SCENE_WARNING);
} else {
sprintf(full_name,"%d: %s",num&1023,anim_name);
browser->Add(full_name,0,2,num,IM_SCENE_ANIM);
}
/*// if (!((global_anim_array[0][num]==(void*)0xe4bf8e8c)||!global_anim_array[0][num])) {
if (!((global_anim_array[0][num]==global_anim_array[0][0])||!global_anim_array[0][num])) {
sprintf(full_name,"%d: %s",num&1023,anim_name);
browser->Add(full_name,0,2,num,IM_SCENE_ANIM);
}*/
FileRead(file_handle,&ldummy,sizeof(ldummy));
FileRead(file_handle,&frame_count,sizeof(frame_count));
if(version>3) FileRead(file_handle,&wdummy,1);
for(c0=0;c0<frame_count;c0++)
{
FileRead(file_handle,&wdummy,sizeof(wdummy));
FileRead(file_handle,&ldummy,sizeof(ldummy));
FileRead(file_handle,&ldummy,sizeof(ldummy));
if(version>0) FileRead(file_handle,&wdummy,sizeof(wdummy));
if(version>1)
{
struct FightCol fcol;
SLONG count,c0;
FileRead(file_handle,&count,sizeof(count));
for(c0=0;c0<count;c0++)
FileRead(file_handle,&fcol,sizeof(struct FightCol));
}
}
}
SLONG LoadAllAnimNames(CBYTE *fname, TreeBrowser *browser, SLONG base_ctr)
{
SLONG anim_count,version,
c0;
MFFileHandle file_handle;
file_handle = FileOpen(fname);
if(file_handle!=FILE_OPEN_ERROR)
{
FileRead(file_handle,&anim_count,sizeof(anim_count));
if(anim_count<0)
{
version=anim_count;
FileRead(file_handle,&anim_count,sizeof(anim_count));
SkipBodyPartInfo(file_handle);
}
for(c0=0;c0<anim_count;c0++)
LoadAnim(file_handle,browser,c0+base_ctr);
return anim_count;
}
else
{
// Unable to open file.
return 0;
}
}
//---------------------------------------------------------------
// Main Editor Proc
LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam);
extern void ClearLatchedKeys();
void new_calc_camera_pos() {
// cam_focus_dist=1;
FMATRIX_calc(
cam_matrix,
cam_yaw,
cam_pitch,
0
);
cam_x = cam_focus_x;
cam_y = cam_focus_y; // PAP_calc_height_at(LEDIT_cam_focus_x, LEDIT_cam_focus_z) + 0x100;
cam_z = cam_focus_z;
/* cam_x -= MUL64(cam_matrix[6], cam_focus_dist);
cam_y -= MUL64(cam_matrix[7], cam_focus_dist);
cam_z -= MUL64(cam_matrix[8], cam_focus_dist);*/
FMATRIX_vector (
cam_forward,
cam_yaw,
0
);
FMATRIX_vector (
cam_left,
(cam_yaw + 512) & 2047,
0
);
}
void MouselookToggle() {
CUTSCENE_mouselook^=1;
if (CUTSCENE_mouselook)
{
SetCursorPos(320,240);
SetCapture(CUTSCENE_edit_wnd);
ShowCursor(FALSE);
} else {
ReleaseCapture();
ShowCursor(TRUE);
}
}
int get_index_from_string(CBYTE *string, CBYTE *opts) {
CBYTE *pt,*buff;
int i=0, r=-1;
buff=(CBYTE*)malloc(strlen(opts)+1);
strcpy(buff,opts);
opts=buff; // now we can play with opts without destroying the original
while (pt=strchr(opts,'|')) {
*pt=0;
pt++;
if (!stricmp(string,opts)) r=i;
opts=pt;
i++;
}
if (!stricmp(string,opts)) r=i;
free(buff);
return r;
}
CBYTE* get_string_from_index(int index, CBYTE *opts, CBYTE *result) {
CBYTE *pt=opts;
while (index--) {
pt=strchr(pt,'|');
if (!pt) { *result=0; return result; }
pt++;
}
strcpy(result,pt);
pt=strchr(result,'|');
if (pt) *pt=0;
return result;
}
int CUTSCENE_get_chan_from_item(CSData *cutscene, Thing *dragitem) {
int channum;
CSEditChannel* chan=cutscene->editchannels;
for (channum=0;channum<cutscene->channelcount;channum++,chan++)
if (chan->thing==dragitem) return channum;
return -1;
}
void CUTSCENE_match_selection_to_item(CSData *cutscene, Thing *dragitem) {
int chan=CUTSCENE_get_chan_from_item(cutscene,dragitem);
SendMessage(GetDlgItem(CUTSCENE_edit_wnd,IDC_LIST2),LB_SETCURSEL,chan,0);
current_packet=CUTSCENE_get_packet(cutscene->channels+chan,timeline->GetReadHead());
}
Thing* CUTSCENE_item_from_point(CSData *cutscene, SLONG x, SLONG y, SLONG z) {
SLONG chanctr, packctr;
CSChannel *chan;
// CSPacket *pack;
CSEditChannel *edit;
chan=cutscene->channels;
edit=cutscene->editchannels;
for (chanctr=0;chanctr<cutscene->channelcount;chanctr++) {
if (chan->type==CT_CHAR) {
if ((abs(x-(edit->thing->WorldPos.X>>8))<50)&&(abs(z-(edit->thing->WorldPos.Z>>8))<50)) return edit->thing;
}
chan++; edit++;
}
return 0;
}
BOOL CUTSCENE_find_surrounding_packets(CSChannel *chan, int cell, int* left, int* right) {
int leftmax=-1, rightmin=2001, packctr=0;
CSPacket *pack;
*left=-1; *right=2001;
pack=chan->packets;
for (packctr=0;packctr<chan->packetcount;packctr++,pack++) {
if ((pack->start<=cell)&&(pack->start>leftmax)) {
leftmax=pack->start; *left=packctr;
}
if ((pack->start>=cell)&&(pack->start<rightmin)) {
rightmin=pack->start; *right=packctr;
}
}
return ((leftmax>-1)&&(rightmin<2000));
}
extern SLONG person_normal_animate(Thing *p_person);
inline int LERPValue(int a, int b, int m) {
return a+(((b-a)*m)/256);
}
inline int LERPAngle(int a, int b, int m) {
if ((a-b)>1024) b+=2048;
if ((b-a)>1024) a+=2048;
return a+(((b-a)*m)/256);
}
void LERPAnim(CSChannel *chan, Thing *person, int cell) {
int left,right,lastpos,pos,dist, a, mult, smoothmult, smoothin, smoothout;
int x,y,z;
CSPacket *pktA, *pktB;
GameCoord posn;
CUTSCENE_find_surrounding_packets(chan,cell,&left,&right);
if (left<0) return;
pktA=chan->packets+left;
pos=cell-pktA->start;
// interpolation
if ((right<2001)&&(right!=left)) {
pktB=chan->packets+right;
dist=pktB->start-pktA->start;
// mult=(pos*256)/dist;
mult=(pos*256);
if (CUTSCENE_slomo) {
mult+=((SLOMO_RATE-CUTSCENE_slomo_ctr)*256)/SLOMO_RATE;
}
mult/=dist;
if (pktA->flags&(PF_SMOOTH_MOVE_BOTH|PF_SMOOTH_ROT_BOTH)) {
// this little fiddle should smooth in/out the edges
smoothmult=(mult-128)*4;
smoothmult=(SIN(smoothmult&2047)>>8)+256;
smoothmult>>=1;
smoothin=(mult-256)*2;
smoothin=256+(SIN(smoothin&2047)>>8);
smoothout=SIN(mult*2)>>8;
}
// motion:
if (pktA->flags&PF_INTERPOLATE_MOVE) {
if ((pktA->flags&PF_SMOOTH_MOVE_BOTH)==PF_SMOOTH_MOVE_BOTH) {
/* x=pktA->pos.X+(((pktB->pos.X-pktA->pos.X)*smoothmult)/256);
y=pktA->pos.Y+(((pktB->pos.Y-pktA->pos.Y)*smoothmult)/256);
z=pktA->pos.Z+(((pktB->pos.Z-pktA->pos.Z)*smoothmult)/256);*/
x=LERPValue(pktA->pos.X,pktB->pos.X,smoothmult);
y=LERPValue(pktA->pos.Y,pktB->pos.Y,smoothmult);
z=LERPValue(pktA->pos.Z,pktB->pos.Z,smoothmult);
} else
if (pktA->flags&PF_SMOOTH_MOVE_IN) {
/* x=pktA->pos.X+(((pktB->pos.X-pktA->pos.X)*smoothin)/256);
y=pktA->pos.Y+(((pktB->pos.Y-pktA->pos.Y)*smoothin)/256);
z=pktA->pos.Z+(((pktB->pos.Z-pktA->pos.Z)*smoothin)/256);*/
x=LERPValue(pktA->pos.X,pktB->pos.X,smoothin);
y=LERPValue(pktA->pos.Y,pktB->pos.Y,smoothin);
z=LERPValue(pktA->pos.Z,pktB->pos.Z,smoothin);
} else
if (pktA->flags&PF_SMOOTH_MOVE_OUT) {
/* x=pktA->pos.X+(((pktB->pos.X-pktA->pos.X)*smoothout)/256);
y=pktA->pos.Y+(((pktB->pos.Y-pktA->pos.Y)*smoothout)/256);
z=pktA->pos.Z+(((pktB->pos.Z-pktA->pos.Z)*smoothout)/256);*/
x=LERPValue(pktA->pos.X,pktB->pos.X,smoothout);
y=LERPValue(pktA->pos.Y,pktB->pos.Y,smoothout);
z=LERPValue(pktA->pos.Z,pktB->pos.Z,smoothout);
} else { // linear
/* x=pktA->pos.X+(((pktB->pos.X-pktA->pos.X)*mult)/256);
y=pktA->pos.Y+(((pktB->pos.Y-pktA->pos.Y)*mult)/256);
z=pktA->pos.Z+(((pktB->pos.Z-pktA->pos.Z)*mult)/256);*/
x=LERPValue(pktA->pos.X,pktB->pos.X,mult);
y=LERPValue(pktA->pos.Y,pktB->pos.Y,mult);
z=LERPValue(pktA->pos.Z,pktB->pos.Z,mult);
}
} else {
x=pktA->pos.X;
y=pktA->pos.Y;
z=pktA->pos.Z;
}
// er... later.
// rotation:
if (pktA->flags&PF_INTERPOLATE_ROT) {
if ((pktA->flags&PF_SMOOTH_ROT_BOTH)==PF_SMOOTH_ROT_BOTH) {
mult=smoothmult;
} else
if (pktA->flags&PF_SMOOTH_ROT_IN) {
mult=smoothin;
} else
if (pktA->flags&PF_SMOOTH_ROT_OUT) {
mult=smoothout;
} // else mult is already correct for linear
a=LERPAngle(pktA->angle,pktB->angle,mult);
} else {
a=pktA->angle;
}
person->Draw.Tweened->Angle=a;
posn.X=x; posn.Y=y; posn.Z=z;
move_thing_on_map(person,&posn);
}
set_anim(person,pktA->index);
if (pktA->flags&1) // reverse
pos=(pktA->length-pos)-1;
if (pos<=0) return;
/* TICK_RATIO=1<<TICK_SHIFT;
while (pos--) person_normal_animate(person);*/
TICK_RATIO=pos<<TICK_SHIFT;
if (CUTSCENE_slomo) {
TICK_RATIO+=((SLOMO_RATE-CUTSCENE_slomo_ctr)<<TICK_SHIFT)/SLOMO_RATE;
}
person_normal_animate(person);
}
void LERPCamera(CSChannel *chan, int cell) {
int x,y,z,p,a, left, right, dist, pos, mult, smoothin, smoothout, smoothmult,lens;
CSPacket *pktA,*pktB;
if (!CUTSCENE_find_surrounding_packets(chan, cell,&left,&right)) return;
pktA=chan->packets+left;
pktB=chan->packets+right;
dist=pktB->start-pktA->start;
pos=cell-pktA->start;
mult=(pos*256);
if (CUTSCENE_slomo) {
mult+=((SLOMO_RATE-CUTSCENE_slomo_ctr)*256)/SLOMO_RATE;
// mult+=(SLOMO_RATE-CUTSCENE_slomo_ctr)/SLOMO_RATE;
}
mult/=dist;
if (pktA->flags&(PF_SMOOTH_MOVE_BOTH|PF_SMOOTH_ROT_BOTH)) {
// this little fiddle should smooth in/out the edges
smoothmult=(mult-128)*4;
smoothmult=(SIN(smoothmult&2047)>>8)+256;
smoothmult>>=1;
smoothin=(mult-256)*2;
smoothin=256+(SIN(smoothin&2047)>>8);
smoothout=SIN(mult*2)>>8;
}
if (pktA->flags&PF_INTERPOLATE_MOVE) {
if ((pktA->flags&PF_SMOOTH_MOVE_BOTH)==PF_SMOOTH_MOVE_BOTH) {
x=pktA->pos.X+(((pktB->pos.X-pktA->pos.X)*smoothmult)/256);
y=pktA->pos.Y+(((pktB->pos.Y-pktA->pos.Y)*smoothmult)/256);
z=pktA->pos.Z+(((pktB->pos.Z-pktA->pos.Z)*smoothmult)/256);
lens=(pktA->length&0xff)+((((pktB->length&0xff)-(pktA->length&0xff))*smoothmult)/256);
} else
if (pktA->flags&PF_SMOOTH_MOVE_IN) {
x=pktA->pos.X+(((pktB->pos.X-pktA->pos.X)*smoothin)/256);
y=pktA->pos.Y+(((pktB->pos.Y-pktA->pos.Y)*smoothin)/256);
z=pktA->pos.Z+(((pktB->pos.Z-pktA->pos.Z)*smoothin)/256);
lens=(pktA->length&0xff)+((((pktB->length&0xff)-(pktA->length&0xff))*smoothin)/256);
} else
if (pktA->flags&PF_SMOOTH_MOVE_OUT) {
x=pktA->pos.X+(((pktB->pos.X-pktA->pos.X)*smoothout)/256);
y=pktA->pos.Y+(((pktB->pos.Y-pktA->pos.Y)*smoothout)/256);
z=pktA->pos.Z+(((pktB->pos.Z-pktA->pos.Z)*smoothout)/256);
lens=(pktA->length&0xff)+((((pktB->length&0xff)-(pktA->length&0xff))*smoothout)/256);
} else { // linear
x=pktA->pos.X+(((pktB->pos.X-pktA->pos.X)*mult)/256);
y=pktA->pos.Y+(((pktB->pos.Y-pktA->pos.Y)*mult)/256);
z=pktA->pos.Z+(((pktB->pos.Z-pktA->pos.Z)*mult)/256);
lens=(pktA->length&0xff)+((((pktB->length&0xff)-(pktA->length&0xff))*mult)/256);
}
} else {
x=pktA->pos.X;
y=pktA->pos.Y;
z=pktA->pos.Z;
lens=pktA->length&0xff;
}
lens=((lens-0x7f)*1.5)+0xff;
FC_cam[0].lens=(lens*0x24000)>>8;
if (pktA->flags&PF_INTERPOLATE_ROT) {
if ((pktA->flags&PF_SMOOTH_ROT_BOTH)==PF_SMOOTH_ROT_BOTH) {
mult=smoothmult;
} else
if (pktA->flags&PF_SMOOTH_ROT_IN) {
mult=smoothin;
} else
if (pktA->flags&PF_SMOOTH_ROT_OUT) {
mult=smoothout;
} // else mult is already correct for linear
p=LERPAngle(pktA->pitch,pktB->pitch,mult);
a=LERPAngle(pktA->angle,pktB->angle,mult);
} else {
p=pktA->pitch;
a=pktA->angle;
}
cam_focus_x=x;
cam_focus_y=y;
cam_focus_z=z;
cam_pitch=p;
cam_yaw=a;
CUTSCENE_fade_level=LERPValue(pktA->length>>8,pktB->length>>8,mult);
}
void SnapAnimation() {
int left,right,channum,cell;
CSChannel *chan;
CSEditChannel *edit;
CSPacket *pktA;
GameCoord posA, posB;
channum=timeline->GetSelectedRow();
cell=timeline->GetReadHead();
chan=cutscene->channels+channum;
edit=cutscene->editchannels+channum;
if (!edit->thing) return;
CUTSCENE_find_surrounding_packets(chan,cell-1,&left,&right);
if (left<0) { MessageBeep(0); return; }
pktA=chan->packets+left;
LERPAnim(chan, edit->thing, pktA->start+pktA->length-1);
calc_sub_objects_position(
edit->thing, edit->thing->Draw.Tweened->AnimTween, SUB_OBJECT_LEFT_FOOT,
&posA.X, &posA.Y, &posA.Z);
posA.X<<=8; posA.Y<<=8; posA.Z<<=8;
posA.X+=pktA->pos.X; posA.Y+=pktA->pos.Y; posA.Z+=pktA->pos.Z;
// posA now abs-world-coord pos of foot
LERPAnim(chan, edit->thing, cell);
calc_sub_objects_position(
edit->thing, edit->thing->Draw.Tweened->AnimTween, SUB_OBJECT_LEFT_FOOT,
&posB.X, &posB.Y, &posB.Z);
posB.X<<=8; posB.Y<<=8; posB.Z<<=8;
current_packet->pos.X=posA.X-posB.X;
current_packet->pos.Y=posA.Y-posB.Y;
current_packet->pos.Z=posA.Z-posB.Z;
move_thing_on_map(edit->thing,&current_packet->pos);
/*
track_x<<=8;
track_y<<=8;
track_z<<=8;
track_x+=p_person->WorldPos.X;
track_z+=p_person->WorldPos.Z;
track_y=(PAP_calc_height_at_thing(p_person,track_x>>8,track_z>>8)<<8)+0x180;
*/
}
void DoEraseChan(int channum) {
CBYTE msg[255],buf[255];
timeline->GetText(channum,buf);
sprintf(msg,"Are you sure you want to permanently delete this %s track?",buf);
if (MessageBox(CUTSCENE_edit_wnd,msg,"Confirm: Delete Track",MB_ICONEXCLAMATION|MB_OKCANCEL)==IDOK) {
CUTSCENE_chan_delete(cutscene,channum);
timeline->Del(channum);
current_packet=0;
timeline->SetReadHead(timeline->GetReadHead());
}
}
void DoErase(int do_row=-1, int do_cell=-1) {
CSChannel* chan=0;
CSPacket* pkt=0;
int pack,length;
if ((do_row<0)||(do_cell<0)) {
do_row=timeline->GetSelectedRow();
if (!current_packet) {
if (do_row>-1) DoEraseChan(do_row);
return;
}
do_cell=current_packet->start;
chan=cutscene->channels+do_row;
pkt=current_packet;
} else {
chan=cutscene->channels+do_row;
pkt=CUTSCENE_get_packet(chan,do_cell);
}
if (!pkt) return;
pack=pkt-chan->packets;
length=(pkt->type!=PT_CAM) ? pkt->length : 1;
timeline->MarkEntry(do_row,do_cell,length,0xff);
timeline->Repaint();
CUTSCENE_del_packet(chan, pack);
timeline->SetReadHead(timeline->GetReadHead());
/*
if (current_packet) {
int channum=timeline->GetSelectedRow();
CSChannel* chan=cutscene->channels+channum;
int pack=current_packet-chan->packets;
int packx=current_packet->start;
timeline->MarkEntry(channum,packx,current_packet->length,0xff);
timeline->Repaint();
CUTSCENE_del_packet(chan, pack);
timeline->SetReadHead(packx);
}
*/
}
void DoHandleShit() {
HWND handle=GetDlgItem(CUTSCENE_edit_wnd,IDC_MAP_VIEW);
PAINTSTRUCT ps;
HDC hdc = BeginPaint(handle,&ps);
POINT client_pos;
RECT src,dst;
HRESULT result;
SWORD speed;
static int lasttick=0;
SLONG ofsX=0, ofsY=0, ofsZ=0;
SLONG matrix[9];
int tick=GetTickCount();
if (tick-lasttick>40) {
lasttick=tick;
if (CUTSCENE_playback) {
int rh=timeline->GetReadHead();
if (rh==2000) {
rh=0; CUTSCENE_playback=0;
} else {
if (CUTSCENE_slomo) {
if (!(--CUTSCENE_slomo_ctr)) {
CUTSCENE_slomo_ctr=SLOMO_RATE;
rh++;
}
} else rh++;
}
timeline->SetReadHead(rh);
}
}
speed=(GetKeyState(VK_CAPITAL)&1)?128:64;
if (GetAsyncKeyState(VK_CONTROL)&(1<<15)) speed=8;
if (Keys[KB_LEFT]) ofsX= speed;
if (Keys[KB_RIGHT]) ofsX=-speed;
if (Keys[KB_UP]) ofsZ= speed;
if (Keys[KB_DOWN]) ofsZ=-speed;
if (Keys[KB_DEL]) cam_yaw+=10;
if (Keys[KB_PGDN]) cam_yaw-=10;
if (Keys[KB_HOME]) cam_focus_y+=speed;
if (Keys[KB_END]) cam_focus_y-=speed;
FMATRIX_calc(matrix,cam_yaw&2047,cam_pitch&2047,0);
FMATRIX_TRANSPOSE(matrix);
FMATRIX_MUL(matrix, ofsX, ofsY, ofsZ);
cam_focus_x+=ofsX;
if (GetKeyState(VK_SCROLL)&1) cam_focus_y+=ofsY;
cam_focus_z+=ofsZ;
cam_yaw &= 2047;
cam_pitch &= 2047;
new_calc_camera_pos();
// Draw the engine.
MFX_set_listener(cam_x<<8,cam_y<<8,cam_z<<8,1024+cam_yaw,-1024,cam_pitch-1024);
GI_render_view_into_backbuffer ( cam_x,
cam_y,
cam_z,
cam_yaw,
cam_pitch,
0 );
CONSOLE_draw();
if (subtitle_str[0]) {
// the_display.lp_D3D_Viewport->Clear(1, &the_display.ViewportRect, D3DCLEAR_ZBUFFER);
POLY_frame_init(FALSE, FALSE);
// MENUFONT_Draw(320,400,256,subtitle_str,0x7fffffff,MENUFONT_CENTRED);
FONT2D_DrawStringCentred(subtitle_str,320,400,0x7fffffff,16,POLY_PAGE_FONT2D);
POLY_frame_draw(FALSE, FALSE);
}
if (CUTSCENE_fade_level<255) {
//the_display.lp_D3D_Viewport->Clear(1, &the_display.ViewportRect, D3DCLEAR_ZBUFFER);
POLY_frame_init(FALSE, FALSE);
DRAW2D_Box(0, 0, 640, 480, (255-CUTSCENE_fade_level)<<24, 1, 255);
POLY_frame_draw(FALSE, FALSE);
}
client_pos.x = 0;
client_pos.y = 0;
ClientToScreen(handle,&client_pos);
GetClientRect(handle,&src);
dst = src;
OffsetRect(&dst,client_pos.x,client_pos.y);
// Set the clipper.
result = the_display.lp_DD_Clipper->SetHWnd(0,handle);
// Blit the view.
result = the_display.lp_DD_FrontSurface->Blt(&dst,the_display.lp_DD_BackSurface,&src,DDBLT_WAIT,0);
EndPaint(handle,&ps);
}
BOOL browserCB(TreeBrowser *tb, int reason, int index, HTREEITEM item, char *str) {
int image=tb->GetImageFromItem(item);
CSChannel *chan;
CSEditChannel *echan;
SLONG x,y,z,who;
switch (reason) {
case TBCB_DBLCLK:
char msg[800];
if ((image==IM_SCENE_SPEAKER)||(image==IM_SCENE_PERSON)||(image==IM_SCENE_CAMERA)||(image==IM_SCENE_BUBBLE)) {
msg[0]=image;
strcpy(msg+1,str);
timeline->Add(msg);
timeline->Repaint();
chan=CUTSCENE_add_channel(cutscene);
echan=cutscene->editchannels+(chan-cutscene->channels);
GI_get_pixel_world_pos(320,240,&x,&y,&z,0);
/* x=cam_focus_x; z=cam_focus_z;
y=PAP_calc_map_height_at(x,z);*/
switch(image) {
case IM_SCENE_PERSON:
chan->type=CT_CHAR;
chan->index=index;
if ((index>0)&&(index<=PERSON_NUM_TYPES))
who=index-1;
else
who=-1;
/* switch(index) {
case 1: who=PERSON_DARCI; break;
case 2: who=PERSON_ROPER; break;
default: who=-1;
}*/
if (who>-1) echan->thing=CUTSCENE_create_person(who,x,y,z);
break;
case IM_SCENE_CAMERA: chan->type=CT_CAM; break;
case IM_SCENE_SPEAKER: chan->type=CT_WAVE; break;
case IM_SCENE_BUBBLE: chan->type=CT_TEXT; break;
}
}
return 0;
case TBCB_DRAG:
if ((image==IM_SCENE_ANIM)&&!index) return 0;
return ((image==IM_SCENE_WAVE)||(image==IM_SCENE_ACTION)||(image==IM_SCENE_ANIM));
break;
default:
return 0;
}
}
void Update3DStuff(CSChannel *chan, CSEditChannel *edit, int cell) {
CSPacket *pkt;
int index,lens;
pkt=CUTSCENE_get_packet(chan,cell);
if (!pkt) {
if (chan->type==CT_CHAR) LERPAnim(chan,edit->thing,cell);
if ((chan->type==CT_CAM)&&!(GetAsyncKeyState(VK_CONTROL)&(1<<15))) LERPCamera(chan,cell);
return;
}
switch(pkt->type) {
case PT_ANIM:
index=pkt->index;
while (index>1023) { index-=1024; }
if (edit->thing) {
//edit->thing->WorldPos=pkt->pos;
move_thing_on_map(edit->thing,&pkt->pos);
edit->thing->Draw.Tweened->Angle=pkt->angle;
set_anim(edit->thing,index);
if (pkt->flags&1) LERPAnim(chan,edit->thing,cell); // should handle the reversing
}
break;
case PT_CAM:
if (!(GetAsyncKeyState(VK_CONTROL)&(1<<15))) {
cam_focus_x=pkt->pos.X;
cam_focus_y=pkt->pos.Y;
cam_focus_z=pkt->pos.Z;
cam_pitch=pkt->pitch;
cam_yaw=pkt->angle;
lens=((pkt->length&0xff)-0x7f);
lens=(lens*1.5)+0xff;
FC_cam[0].lens=(lens*0x24000)>>8;
PolyPage::SetGreenScreen(pkt->flags&PF_SECURICAM);
CUTSCENE_slomo=pkt->flags&PF_SLOMO;
CUTSCENE_fade_level=pkt->length>>8;
}
break;
case PT_WAVE:
if (CUTSCENE_playback) MFX_play_xyz(MUSIC_REF+(chan-cutscene->channels),pkt->index-2048,0,pkt->pos.X<<8,pkt->pos.Y<<8,pkt->pos.Z<<8);
break;
case PT_TEXT:
if (pkt->pos.X)
strcpy(subtitle_str,(CBYTE*)pkt->pos.X);
else
subtitle_str[0]=0;
break;
}
}
int LerpModeMangle(int selection, int which) {
int res=0;
if (selection>0) res|=1;
if ((selection==2)||(selection==4)) res|=2;
if (selection>2) res|=4;
if (which==1) res<<=1;
if (which==2) res<<=4;
return res;
}
int UnMangleLerp(int flags, int which) {
if (which==1) flags>>=1;
if (which==2) flags>>=4;
flags&=(1|2|4);
switch (flags) {
case 0: case 2: case 4: case 6: default: return 0;
case 1: return 1;
case 3: return 2;
case 5: return 3;
case 7: return 4;
}
}
BOOL timelineCB(TimeLine *tb, int reason, int index, int subline, int cell) {
CSChannel *chan;
CSEditChannel *edit;
CSPacket *pkt;
int channum;
CBYTE str[255];
switch(reason) {
/* case TLCB_GETBARINFO:
chan=&cutscene->Channels[index];
break;*/
case TLCB_SELECT:
for (channum=0;channum<cutscene->channelcount;channum++)
if (channum!=index) // we need to update the 3d display, but not the property window
{
chan=cutscene->channels+channum;
edit=cutscene->editchannels+channum;
Update3DStuff(chan,edit,cell);
}
if (index<0) return 0;
chan=cutscene->channels+index;
edit=cutscene->editchannels+index;
current_packet=pkt=CUTSCENE_get_packet(chan,cell);
pedit->Clear();
Update3DStuff(chan,edit,cell);
if (!pkt) return 0;
/* if (!pkt) {
if (chan->type==CT_CHAR) LERPAnim(chan,edit->thing,cell);
if ((chan->type==CT_CAM)&&!ControlFlag) LERPCamera(chan,cell);
return 0;
}*/
switch(pkt->type) {
case PT_ANIM:
{
HTREEITEM base=darcianim;
int index=pkt->index;
if (index>1023) { base=roperanim; index-=1024; }
browser->GetTextFromItem(browser->GetChildFromItem(base,index),str,255);
/* if (edit->thing) {
edit->thing->WorldPos=pkt->pos;
edit->thing->Draw.Tweened->Angle=pkt->angle;
set_anim(edit->thing,index);
}*/
}
pedit->Add("Type","Animation",PROPTYPE_READONLY);
pedit->Add("Anim",str,PROPTYPE_READONLY);
pedit->Add("Snap position","(click here)",PROPTYPE_BUTTON);
pedit->Add("Play direction","forwards|backwards",PROPTYPE_MULTI);
if (pkt->flags&1) pedit->Update(3,"backwards");
pedit->Add("Movement",interpolate_strings,PROPTYPE_MULTI);
pedit->Add("Rotation",interpolate_strings,PROPTYPE_MULTI);
pedit->Update(4,get_string_from_index(UnMangleLerp(pkt->flags,1),interpolate_strings,str));
pedit->Update(5,get_string_from_index(UnMangleLerp(pkt->flags,2),interpolate_strings,str));
break;
case PT_CAM:
pedit->Add("Type","Camera",PROPTYPE_READONLY);
pedit->Add("Cam mode","normal|security camera",PROPTYPE_MULTI);
if (pkt->flags&PF_SECURICAM) pedit->Update(1,"security camera");
pedit->Add("Movement",interpolate_strings,PROPTYPE_MULTI);
pedit->Add("Rotation",interpolate_strings,PROPTYPE_MULTI);
pedit->Update(2,get_string_from_index(UnMangleLerp(pkt->flags,1),interpolate_strings,str));
pedit->Update(3,get_string_from_index(UnMangleLerp(pkt->flags,2),interpolate_strings,str));
itoa(pkt->length>>8,str,10);
pedit->Add("Fade in",str,PROPTYPE_INT);
itoa((pkt->length&0xff)-0x7f,str,10);
pedit->Add("Zoom ratio",str,PROPTYPE_INT);
pedit->Add("Slo-mo","off",PROPTYPE_BOOL);
if (pkt->flags&PF_SLOMO) pedit->Update(6,"on");
CUTSCENE_fade_level=pkt->length>>8;
break;
case PT_WAVE:
pedit->Add("Type","Wave",PROPTYPE_READONLY);
pedit->Add("Wave",sound_list[pkt->index-2048],PROPTYPE_READONLY);
pedit->Add("Preview","(click here)",PROPTYPE_BUTTON);
//if (CUTSCENE_playback) MFX_play_xyz(MUSIC_REF+channum,pkt->index-2048,0,pkt->pos.X,pkt->pos.Y,pkt->pos.Z);
break;
case PT_TEXT:
pedit->Add("Type","Subtitle",PROPTYPE_READONLY);
if (pkt->pos.X)
strcpy(subtitle_str,(CBYTE*)pkt->pos.X);
else
subtitle_str[0]=0;
pedit->Add("Text",subtitle_str,PROPTYPE_STRING);
//pedit->Add("Style","normal|something else",PROPTYPE_MULTI);
break;
}
break;
}
return 0;
}
BOOL propeditCB(PropertyEditor *tb, int reason, int index, CBYTE *value) {
int res,i;
switch(reason) {
case PECB_EDITMODE:
CUTSCENE_need_keyboard=index;
break;
case PECB_UPDATE:
if (current_packet) {
switch(current_packet->type) {
case PT_CAM:
switch(index) {
case 1: // normal/securitycam
current_packet->flags&=~1;
current_packet->flags|=(*value=='s');
PolyPage::SetGreenScreen(current_packet->flags&1);
break;
case 2: // motion mode
current_packet->flags&=~(2|4|8);
//current_packet->flags|=(*value=='s')<<1;
res=get_index_from_string(value,interpolate_strings);
current_packet->flags|=LerpModeMangle(res,1);
break;
case 3: // linear/smooth rotation
current_packet->flags&=~(16|32|64);
//current_packet->flags|=(*value=='s')<<2;
res=get_index_from_string(value,interpolate_strings);
current_packet->flags|=LerpModeMangle(res,2);
break;
case 4: // Fade
res=i=atoi(value);
SATURATE(res,0,255);
if (res!=i) {
itoa(res,value,10);
pedit->Update(4,value);
}
current_packet->length&=0xff;
current_packet->length|=(res<<8);
break;
case 5: // Zoom
res=i=atoi(value);
SATURATE(res,-127,128);
if (res!=i) {
itoa(res,value,10);
pedit->Update(5,value);
}
current_packet->length&=0xff00;
current_packet->length|=res+127;
// i=(current_packet->length&0xff);
i=(res*1.5)+0xff;
FC_cam[0].lens=(i*0x24000)>>8;
break;
case 6: // Slo-mo
current_packet->flags&=~PF_SLOMO;
if (!stricmp("on",value)) current_packet->flags|=PF_SLOMO;
CUTSCENE_slomo=current_packet->flags&PF_SLOMO;
break;
}
break;
case PT_ANIM:
switch(index) {
case 3:
current_packet->flags&=~1;
current_packet->flags|=(*value=='b');
break;
case 4: // motion mode
current_packet->flags&=~(2|4|8);
res=get_index_from_string(value,interpolate_strings);
current_packet->flags|=LerpModeMangle(res,1);
break;
case 5: // linear/smooth rotation
current_packet->flags&=~(16|32|64);
res=get_index_from_string(value,interpolate_strings);
current_packet->flags|=LerpModeMangle(res,2);
break;
}
break;
case PT_TEXT:
switch(index) {
case 1:
free((CBYTE*)current_packet->pos.X);
current_packet->pos.X = (int)malloc(strlen(value)+1);
strcpy((CBYTE*)current_packet->pos.X,value);
}
break;
}
}
break;
case PECB_BUTTON:
if (current_packet) {
switch(current_packet->type) {
case PT_ANIM:
if (index==2) SnapAnimation();
break;
case PT_WAVE:
if (index==2)
//MFX_play_stereo(MUSIC_REF,current_packet->index-2048,0);
MFX_play_xyz(MUSIC_REF,current_packet->index-2048,0,cam_x<<8,cam_y<<8,cam_z<<8);
break;
}
}
}
return FALSE;
}
LRESULT CALLBACK scene_map_view_proc (
HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam
)
{
static Thing *dragitem=NULL;
static int dragmode=0;
SLONG wx,wy,wz,dx,dz, angle;
switch(message)
{
case WM_LBUTTONDOWN:
{
UWORD sx=LOWORD(lParam);
UWORD sy=HIWORD(lParam);
if (GI_get_pixel_world_pos(sx,sy,&wx,&wy,&wz,0)) {
Thing *dragtest=CUTSCENE_item_from_point(cutscene,wx,wy,wz);
if (dragtest) {
dragitem=dragtest;
SetCapture(hWnd);
CUTSCENE_match_selection_to_item(cutscene,dragitem);
dragmode=1;
}
}
}
break;
case WM_RBUTTONDOWN:
{
UWORD sx=LOWORD(lParam);
UWORD sy=HIWORD(lParam);
if (GI_get_pixel_world_pos(sx,sy,&wx,&wy,&wz,0)) {
Thing *dragtest=CUTSCENE_item_from_point(cutscene,wx,wy,wz);
if (dragtest) {
dragitem=dragtest;
CUTSCENE_match_selection_to_item(cutscene,dragitem);
SetCapture(hWnd);
dragmode=2;
}
}
}
break;
case WM_MOUSEMOVE:
if (dragitem) {
POINT pt;
GetCursorPos(&pt);
ScreenToClient(hWnd,&pt);
GI_get_pixel_world_pos(pt.x,pt.y,&wx,&wy,&wz,0);
switch(dragmode) {
case 1:
{
GameCoord pos={wx<<8,wy<<8,wz<<8};
move_thing_on_map(dragitem,&pos);
if (current_packet) current_packet->pos=pos;
}
break;
case 2:
dx=wx-(dragitem->WorldPos.X>>8);
dz=(dragitem->WorldPos.Z>>8)-wz;
angle=(1024+Arctan(dx,dz))&2047;
if (dragitem->Class==CLASS_PERSON)
dragitem->Draw.Tweened->Angle=angle;
if (current_packet) current_packet->angle=angle;
//dir>>=3;
break;
}
// SetCursor();
}
break;
case WM_LBUTTONUP:
case WM_RBUTTONUP:
if (current_packet&&dragitem) {
current_packet->angle=dragitem->Draw.Tweened->Angle;
current_packet->pos=dragitem->WorldPos;
}
dragitem=0;
ReleaseCapture();
break;
}
return DefWindowProc(hWnd,message,wParam,lParam);
}
extern SLONG how_long_is_anim(SLONG anim);
BOOL CALLBACK cuts_proc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
HWND the_ctrl;
static UINT timer;
int i;
SLONG wx,wy,wz;
switch(message)
{
case WM_INITDIALOG:
CUTSCENE_edit_wnd=hWnd;
the_ctrl = GetDlgItem(hWnd,IDC_LIST1);
// InitCols(the_ctrl);
pedit = new PropertyEditor(the_ctrl);
//InitProps(pedit,0);
pedit->SetCallback(propeditCB);
InitBrowser(the_ctrl = GetDlgItem(hWnd,IDC_TREE1));
drag = new DragServer(hWnd,GEDIT_hinstance);
browser->SetDraggable(drag);
browser->SetCallback(browserCB);
// timer = SetTimer(hWnd,NULL,40,tf);
timeline = new TimeLine(
GetDlgItem(hWnd,IDC_LIST2),
ruler = new TimeLineRuler(GetDlgItem(hWnd,IDC_BUTTON1)),
scroll= new TimeLineScroll(GetDlgItem(hWnd,IDC_SCROLLBAR1))
);
timeline->SetImageList(GEDIT_hinstance,IDB_SCENE_ICONS1);
timeline->SetCallback(timelineCB);
cam_focus_x = 64 << 8;
cam_focus_z = 64 << 8;
cam_focus_y = 0x800;
cam_focus_dist = 12 << 8;
cam_pitch = 1800;
CUTSCENE_recreate(cutscene);
return TRUE;
case WM_KEYDOWN:
case WM_KEYUP:
ClearLatchedKeys();
KeyboardProc(message,wParam,lParam);
break;
case WM_USER:
DoHandleShit();
return TRUE;
case WM_MEASUREITEM:
if (timeline&&(wParam==IDC_LIST2)) timeline->Measure(lParam);
break;
case WM_DRAWITEM:
if (timeline&&(wParam==IDC_LIST2)) timeline->Draw(lParam);
if (ruler&&(wParam==IDC_BUTTON1)) ruler->Draw(lParam);
break;
case WM_DESTROY:
// KillTimer(hWnd,timer);
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_CEDIT_MOUSELOOK:
MouselookToggle();
return TRUE;
case ID_CEDIT_PLAYBACK:
CUTSCENE_playback^=1;
return TRUE;
case ID_CEDIT_REWIND:
if ((i=timeline->GetReadHead())>0) timeline->SetReadHead(i-1);
return true;
case ID_CEDIT_FFWD:
if ((i=timeline->GetReadHead())<2000) timeline->SetReadHead(i+1);
return true;
case ID_CEDIT_ERASE:
DoErase();
break;
case ID_CEDIT_CAMERA_PUNCHIN:
if (!current_packet) {
int channum=timeline->GetSelectedRow();
CSChannel* chan=cutscene->channels+channum;
if ((channum>=0)&&(channum<cutscene->channelcount)) {
CSEditChannel* edit=&cutscene->editchannels[channum];
switch (chan->type) {
case CT_CAM:
{
CSPacket* p=CUTSCENE_add_packet(chan);
p->start=timeline->GetReadHead();
p->type=PT_CAM;
p->length=0xff7f; // fully faded in, and normal lens length
current_packet=p;
timeline->MarkEntry(channum,p->start,1,4);
timeline->Repaint();
break;
}
case CT_TEXT:
{
CSPacket* p=CUTSCENE_add_packet(chan);
p->start=timeline->GetReadHead();
p->type=PT_TEXT;
p->length=1;
p->pos.X=0;
current_packet=p;
timeline->MarkEntry(channum,p->start,1,4);
timeline->Repaint();
break;
}
}
}
}
if (current_packet) {
switch (current_packet->type) {
case PT_CAM:
current_packet->pos.X=cam_focus_x;
current_packet->pos.Y=cam_focus_y;
current_packet->pos.Z=cam_focus_z;
current_packet->angle=cam_yaw;
current_packet->pitch=cam_pitch;
break;
case PT_TEXT:
// do we need to do anything, really? i doubt it
break;
}
timeline->SetReadHead(current_packet->start); // heh
}
return TRUE;
case ID_FILE_EXIT:
PostMessage(hWnd,WM_CLOSE,0,0);
break;
case IDC_BUTTON1:
return ruler->Process(hWnd,wParam,lParam);
case IDC_LIST2:
return timeline->Process(hWnd,wParam,lParam);
/* case IDOK:
SendMessage(hWnd,WM_CLOSE,0,0);
return TRUE;*/
}
break;
case WM_MOUSEMOVE:
if (CUTSCENE_mouselook) {
POINT pt;
GetCursorPos(&pt);
SetCursorPos(320,240);
pt.x-=320; pt.y-=240;
cam_yaw-=pt.x;
cam_pitch-=pt.y;
DoHandleShit();
ClearLatchedKeys();
break;
}
if (!drag->Process(message,wParam,lParam)) {
// do stuff here if you care...
}
break;
case WM_LBUTTONUP:
if (!drag->Process(message,wParam,lParam)) {
// do stuff here if you care...
}
break;
case UM_DROP:
{
POINT pt,pt2;
pt.x=LOWORD(lParam);
pt.y=HIWORD(lParam);
pt2=pt;
ClientToScreen(hWnd,&pt);
HWND target=ChildWindowFromPoint(hWnd,pt2);
if ((HWND)wParam==browser->hWnd) {
if (target==timeline->hWnd) {
ScreenToClient(timeline->hWnd,&pt);
int chan=timeline->GetRowFromY(pt.y);
if ((chan>=0)&&(chan<cutscene->channelcount)) {
CSChannel* chn=cutscene->channels+chan;
CSEditChannel* edit=&cutscene->editchannels[chan];
int which,x=timeline->GetCellFromX(pt.x-100);
int length=1;
if ((browser->drag_item.iImage==IM_SCENE_WAVE)&&(chn->type!=CT_WAVE)) break;
if ((browser->drag_item.iImage==IM_SCENE_ACTION)&&(chn->type!=CT_CHAR)) break;
if ((browser->drag_item.iImage==IM_SCENE_ANIM)&&(chn->type!=CT_CHAR)) break;
DoErase(chan,x);
CSPacket* p=CUTSCENE_add_packet(&cutscene->channels[chan]);
p->start=x;
switch(browser->drag_item.iImage) {
case IM_SCENE_WAVE:
p->type=PT_WAVE;
p->index=browser->drag_item.lParam;
/*GI_get_pixel_world_pos(320,240,&wx,&wy,&wz,0);
p->pos.X=wx;
p->pos.Y=wy;
p->pos.Z=wz;*/
p->pos.X=cam_x;
p->pos.Y=cam_y;
p->pos.Z=cam_z;
p->length=1;
//which=2;
which=4;
break;
case IM_SCENE_ACTION:
p->type=PT_ACTION;
which=1;
break;
case IM_SCENE_ANIM:
p->type=PT_ANIM;
p->index=browser->drag_item.lParam;
length=p->index;
while (length>1023) length-=1024;
length=/*CUTSCENE_*/how_long_is_anim(/*cutscene->editchannels[chan].thing->Genus.Person->AnimType,*/length);
which=1;
p->pos=edit->thing->WorldPos;
p->angle=edit->thing->Draw.Tweened->Angle;
p->length=length;
break;
}
timeline->MarkEntry(chan,x,length,which);
timeline->Repaint();
}
}
}
}
break;
case WM_NOTIFY:
switch(LOWORD(wParam))
{
case IDC_LIST1:
return pedit->Process(hWnd,wParam,lParam);
case IDC_TREE1:
return browser->Process(hWnd,wParam,lParam);
// return ProcessListCtl(hWnd,GetDlgItem(hWnd,IDC_LIST1),wParam,lParam);
break;
}
case WM_HSCROLL:
return scroll->Process(hWnd,wParam,lParam);
case WM_CLOSE:
ReleaseCapture();
CUTSCENE_edit_wnd=0;
delete timeline;
delete pedit;
delete browser;
delete drag;
delete ruler;
delete scroll;
CUTSCENE_remove(cutscene);
// EndDialog(hWnd,0);
DestroyWindow(hWnd);
PostQuitMessage(0);
return FALSE;
}
return FALSE;
}
//---------------------------------------------------------------
extern SLONG load_anim_system(struct GameKeyFrameChunk *game_chunk,CBYTE *name,SLONG type=0);
extern void setup_anim_stuff(void);
extern void setup_global_anim_array(void);
void do_cutscene_setup(EventPoint *the_ep)
{
HWND dlg;
MSG msg;
HRESULT result;
HACCEL CEDIT_accel;
WNDCLASSEX new_class;
ATOM the_class;
LPCTSTR cname;
BOOL block_keyboard_messages=0;
subtitle_str[0]=0;
// Create map view window class.
new_class.cbSize = sizeof(WNDCLASSEX);
new_class.style = CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW;
new_class.lpfnWndProc = scene_map_view_proc;
new_class.cbClsExtra = 0;
new_class.cbWndExtra = sizeof(HANDLE);
new_class.hInstance = GEDIT_hinstance;
new_class.hIcon = NULL;
new_class.hCursor = GEDIT_arrow;
new_class.hbrBackground = (struct HBRUSH__ *)GetStockObject(BLACK_BRUSH);
new_class.lpszMenuName = NULL;
new_class.lpszClassName = "Scene Map View";
new_class.hIconSm = NULL;
the_class=RegisterClassEx(&new_class);
if(!the_class) return;
if (!the_ep->Data[0]) {
cutscene=CUTSCENE_data_alloc();
the_ep->Data[0]=(SLONG)cutscene;
} else {
cutscene=(CSData*)the_ep->Data[0];
}
CEDIT_accel = LoadAccelerators(GEDIT_hinstance, MAKEINTRESOURCE(IDR_CEDIT_ACCELERATORS));
// the animations aren't normally loaded in the editor
/* ANIM_init();
setup_anim_stuff();
load_anim_system(&game_chunk[0],"darci1.all");
load_anim_system(&game_chunk[2],"roper.all");
load_anim_system(&game_chunk[3],"rthug.all");
load_anim_system(&game_chunk[4],"roper2.all");
setup_global_anim_array();*/
// lets do our own funkathonic message loop thang baby
dlg=CreateDialog( GEDIT_hinstance, MAKEINTRESOURCE(IDD_SCENE_EDITOR),
GEDIT_view_wnd, (DLGPROC)cuts_proc );
ShowWindow(dlg,SW_SHOWNORMAL);
while(1)
{
// MFX_set_listener(cam_x,cam_y,cam_z,-(cam_yaw),0,-(cam_pitch));
MFX_render();
if(!PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE))
{
// No messages pending- send a user message so we can
// do our processing and display the engine.
PostMessage(dlg, WM_USER, 0, 0);
// clear latched keys in keyboard driver
ClearLatchedKeys();
}
result = GetMessage(&msg, NULL, 0, 0);
if(result==0 || result==-1)
break;
// damn you, evil mousewheel handler!
/* if (msg.message==WM_MOUSEWHEEL) {
msg.wParam=(short)HIWORD(msg.wParam);
}
if (msg.message==GEDIT_wm_mousewheel) {
msg.message=WM_MOUSEWHEEL;
}*/
switch (msg.message) { // special case stuff, whee
case WM_DESTROY:
case WM_CLOSE:
result=-1;
break;
}
if(result==0 || result==-1)
break;
// damn you, evil keyboard handler!
block_keyboard_messages=0;
switch(msg.message)
{
case WM_KEYDOWN:
case WM_KEYUP:
KeyboardProc(msg.message,msg.wParam,msg.lParam);
if(ED_KEYS) block_keyboard_messages=1;
break;
default:
TranslateMessage(&msg);
}
if (!block_keyboard_messages) {
BOOL ok=1;
if (!CUTSCENE_need_keyboard) ok=!TranslateAccelerator(dlg, CEDIT_accel, &msg);
if (ok) {
if(dlg==0 || !IsDialogMessage(dlg,&msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
/* if ((!block_keyboard_messages)&&!TranslateAccelerator(dlg, CEDIT_accel, &msg))
// if (!block_keyboard_messages)
if(dlg==0 || !IsDialogMessage(dlg,&msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}*/
}
cname=(LPCTSTR)MAKELONG(the_class,0);
UnregisterClass(cname,GEDIT_hinstance);
// DestroyWindow(dlg);
}
//---------------------------------------------------------------