convert line ends
[canaan.git] / prj / cam / src / editor / editmode.c
blob90569f1ca69feae6db6523951fb9a2b3724356cd
1 /*
2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
4 */
6 // $Header: r:/t2repos/thief2/src/editor/editmode.c,v 1.73 2000/02/19 13:10:34 toml Exp $
8 #include <stdio.h>
9 #include <time.h>
11 #include <lg.h>
12 #include <loopapi.h>
13 #include <appagg.h>
14 #include <config.h>
15 #include <uiapp.h>
17 #include <hotkey.h>
18 #include <menus.h>
20 #include <editmode.h>
21 #include <gamemode.h>
23 #include <cfgtool.h>
24 #include <brushgfh.h>
25 #include <swappnp.h>
26 #include <command.h>
27 #include <contexts.h>
28 #include <dispatch.h>
29 #include <dispbase.h>
30 #include <vismsg.h>
31 #include <editbr.h>
32 #include <editgeom.h>
33 #include <loopmsg.h>
34 #include <biploop.h>
35 #include <resloop.h>
36 #include <scrnloop.h>
37 #include <plyrloop.h>
38 #include <scrnmode.h>
39 #include <scrnman.h>
40 #include <status.h>
41 #include <testloop.h>
42 #include <gen_bind.h>
43 #include <ailoop.h>
44 #include <uiedit.h>
45 #include <uiloop.h>
46 #include <viewmgr.h>
47 #include <dispapi.h>
48 #include <schloop.h>
49 #include <backup.h>
50 #include <motedit.h>
51 #include <linkdraw.h>
52 #include <simman.h>
53 #include <dspchdef.h>
54 #include <simdef.h>
55 #include <brestore.h>
56 #include <palette.h>
57 #include <rendprop.h>
58 #include <pgrpprop.h>
60 // stuff for camera synch
61 #include <dbasemsg.h>
62 #include <dispbase.h>
63 #include <playrobj.h>
64 #include <camera.h>
66 // So that we can know whether we're switching into a cDarkPanel
67 // This wants to be handled *some* other way in the long run:
68 // #include <drkpanid.h>
70 #include <gametool.h>
71 #include <memall.h>
72 #include <dbmem.h> // must be last header!
74 // convienience, since doug is lazy, and gedit.h uses vectors and stuff
75 // these are in gedit.h, but i dont want to need editbr and such in editmode
76 extern void gedit_enter(void), gedit_exit(void);
78 extern void UpdateMenuCheckmarks(void);
80 ////////////////////////////////////////
81 // LOOPMODE DESCRIPTOR
85 // Here is the list of the loop clients that this mode uses.
86 // Most clients are implemented in fooloop.c
89 static bool (*inpbnd_handler)(uiEvent *, Region *, void *);
91 #define GAMESPEC_RESERVED_CLIENT 0
93 static tLoopClientID* _Clients[] =
95 &GUID_NULL, // reserved for gamespec
96 &LOOPID_Test,
97 &LOOPID_ScrnMan,
98 &LOOPID_UI,
99 &LOOPID_Res,
100 &LOOPID_Biped,
101 &LOOPID_EditGeom,
102 &LOOPID_Editor,
103 &LOOPID_AI,
104 &LOOPID_Schema,
108 // Here's the actual loopmode descriptor
109 // It gets added to the loop manager in loopapp.c
112 sLoopModeDesc EditLoopMode =
114 { &LOOPID_EditMode, "Edit mode"},
115 _Clients,
116 sizeof(_Clients)/sizeof(_Clients[0]),
119 ////////////////////////////////////////
120 // CONTEXT FOR LOOPMODE
123 // context for scrnman client
124 static sScrnMode scrnmode =
126 kScrnModeDimsValid|kScrnModeBitDepthValid|kScrnModeFlagsValid,
127 640,480,
129 kScrnModeWindowed,
132 static ScrnManContext _scrndata =
134 { &scrnmode },
137 // context for ui client
138 static uiLoopContext _uidata =
140 "editor\\cursor",
143 // context for resource sys client
144 static ResLoopContext _resdata =
147 "editor.res", // a list of files to open
151 static sLoopModeInitParm _EditContext[] =
153 { &LOOPID_ScrnMan, (tLoopClientData)&_scrndata},
154 { &LOOPID_UI, (tLoopClientData)&_uidata},
155 { &LOOPID_Res, (tLoopClientData)&_resdata},
156 { &LOOPID_EditGeom, (tLoopClientData)1}, // listen to frame events.
158 { NULL, } // terminator
161 ////////////////////////////////////////////////////////////
162 // GAME SPEC CLIENT INSTALLATION
164 void EditModeSetGameSpecClient(const GUID* ID)
166 _Clients[GAMESPEC_RESERVED_CLIENT] = ID;
170 ////////////////////////////////////////
171 // INSTANTIATOR
174 static sLoopInstantiator _instantiator =
176 &LOOPID_EditMode,
177 mmEditBrush,
178 _EditContext,
182 // This function fills out and returns the instantiator for this mode, based on
183 // an "edit mode descriptor structure." The point of this is to hide the list
184 // of loop clients behind the "edit mode" abstraction barrier. So a system
185 // that wants to change to edit mode doesn't need to know which loop client the
186 // mode uses to keep track of screen res, etc.
189 sLoopInstantiator* DescribeEditMode(EditMinorMode minorMode, EditModeDesc* desc)
191 if (minorMode != mmEditNoChange)
193 _instantiator.minorMode = minorMode;
195 if (desc != NULL)
197 if (desc->scrnmode)
198 ScrnModeCopy(&scrnmode,desc->scrnmode,kScrnModeAllValid);
201 return &_instantiator;
208 /////////////////////////////////////////////////////////////
209 // EDITOR LOOP CLIENT
210 ////////////////////////////////////////////////////////////
212 // this is a generic loop client for all sorts of stuff that only happens in editor
213 // mode and doesn't quite merit its own loop client.
215 // This client has no context data. If it did, this type would not be void.
216 // Your client could have any type it wants.
217 typedef void Context;
219 // The client stores all its state here, plus a pointer to its context.
220 // This client happens to have no state.
222 typedef struct _StateRecord
224 Context* context;
225 BOOL first_frame;
226 BOOL from_game;
227 BOOL in_mode;
228 } StateRecord;
230 ////////////////////////////////////////
231 // Database message handler
234 static void synch_edit_camera(void)
236 // actually write the current camera pos back into the editor spotlight
237 mxs_vector *plypos;
238 mxs_angvec *plyang;
239 Camera* player_cam = PlayerCamera();
240 if (vm_spotlight_loc(&plypos,&plyang))
241 CameraGetLocation(player_cam, plypos, plyang);
244 static void db_message(DispatchData* msg)
246 msgDatabaseData data;
247 data.raw = msg->data;
248 switch (DB_MSG(msg->subtype))
250 case kDatabaseReset:
251 GFHSetCurrentBrush(NULL);
252 break;
253 case kDatabasePostLoad:
254 if ((msg->subtype & (kObjPartConcrete|kObjPartBriefcase)) == kObjPartConcrete)
255 if (!BackupLoading())
256 synch_edit_camera();
258 if (!(msg->subtype & kFiletypeAll))
259 pal_update();
260 break;
262 case kDatabaseDefault:
263 pal_update();
264 break;
272 ----------------------------------------
273 Processes keys sent from input binder
274 ----------------------------------------
276 static char *ProcessEditKey (char *cmd, char *val, BOOL already_down)
278 return CommandExecute (cmd);
279 }//end ProcessEditKey ()
282 ////////////////////////////////////////
284 // LOOP/DISPATCH callback
285 // Here's where we do the dirty work.
288 #pragma off(unreferenced)
289 static eLoopMessageResult LGAPI _LoopFunc(void* data, eLoopMessage msg, tLoopMessageData hdata)
291 int cookie;
292 Region* root = GetRootRegion();
293 // useful stuff for most clients
294 eLoopMessageResult result = kLoopDispatchContinue;
295 StateRecord* state = (StateRecord*)data;
296 LoopMsg info;
298 // our specific stuff
299 struct tm time_of_day;
300 time_t ltime;
301 static bool once = FALSE;
303 info.raw = hdata;
305 switch(msg)
307 case kMsgResumeMode:
308 case kMsgEnterMode:
309 pal_update(); // set the palette
310 EditorCreateGUI();
311 // run the scripts
312 state->first_frame = TRUE;
313 state->in_mode = TRUE;
315 //input binding stuff
316 g_pInputBinder->lpVtbl->GetHandler (g_pInputBinder, &inpbnd_handler);
317 uiInstallRegionHandler (root, UI_EVENT_KBD_COOKED, inpbnd_handler, NULL, &cookie);
318 g_pInputBinder->lpVtbl->SetMasterProcessCallback (g_pInputBinder, ProcessEditKey);
319 g_pInputBinder->lpVtbl->SetContext (g_pInputBinder, HK_BRUSH_EDIT, TRUE);
320 HotkeyContext = HK_BRUSH_EDIT;
322 StatusEnable();
323 gedit_enter();
324 if (config_is_defined("editorcam_from_game"))
325 synch_edit_camera();
326 SetMainMenu("edit");
327 UpdateMenuCheckmarks();
328 state->from_game = IsEqualGUID(info.mode->from.pID,&LOOPID_GameMode);
330 if (state->from_game)
332 ISimManager* pSimMan = AppGetObj(ISimManager);
333 ISimManager_SuspendSim(pSimMan);
334 SafeRelease(pSimMan);
337 ParticleGroupEnterMode();
339 break;
341 case kMsgExitMode:
342 if (!state->in_mode)
343 break;
344 case kMsgSuspendMode:
345 state->in_mode = FALSE;
346 ParticleGroupExitMode();
347 if(g_InMotionEditor)
348 MotEditClose();
349 SetMainMenu(NULL);
350 EditorDestroyGUI();
351 StatusDisable();
353 // Determine if we're going into game mode...
354 if (IsEqualGUID(info.mode->to.pID,&LOOPID_GameMode) ||
355 GameToolIsToGameModeGUID(info.mode->to.pID))
357 ISimManager* pSimMan = AppGetObj(ISimManager);
358 sDispatchMsg msg = { kSimInit};
360 gedit_exit();
361 SaveBrushSelection();
362 BackupMission();
363 ISimManager_StartSim(pSimMan);
364 SafeRelease(pSimMan);
368 break;
370 case kMsgAppInit:
371 InitDrawnRelations();
372 break;
374 case kMsgAppTerm:
375 TermDrawnRelations();
376 break;
378 case kMsgEnd:
379 Free(state);
380 break;
382 case kMsgNormalFrame:
383 time(&ltime);
384 memcpy(&time_of_day, localtime(&ltime), sizeof(struct tm));
385 StatusField(SF_TIME,asctime(&time_of_day));
386 StatusUpdate();
387 GFHUpdate(GFH_FRAME);
388 if(g_InMotionEditor)
389 MotEditUpdate(info.frame->dTicks);
391 if (state->first_frame)
393 if (!once)
394 process_config_scripts("edit_script");
395 once = TRUE;
396 process_config_scripts("edit_always_script");
398 if (state->from_game)
400 RestoreMissionBackup();
401 RemoveMissionBackup();
402 RestoreBrushSelection();
405 state->first_frame = FALSE;
409 break;
411 case kMsgVisual:
412 uieditStyleSetup(); // recompute the guiStyle
413 vm_redraw();
414 uieditRedrawAll();
415 StatusDrawStringAll();
416 break;
418 case kMsgDatabase:
419 db_message(info.dispatch);
420 break;
422 return result;
426 // Loop client factory function.
429 #pragma off(unreferenced)
430 static ILoopClient* LGAPI _CreateClient(sLoopClientDesc * pDesc, tLoopClientData data)
432 StateRecord* state;
433 // allocate space for our state, and fill out the fields
434 state = Malloc(sizeof(StateRecord));
435 memset(state,0,sizeof(*state));
436 state->context = (Context*)data;
438 return CreateSimpleLoopClient(_LoopFunc,state,&EditorLoopClientDesc);
440 #pragma on(unreferenced)
443 // The loop client descriptor
446 sLoopClientDesc EditorLoopClientDesc =
448 &LOOPID_Editor, // client's guid
449 "Editor client", // string name
450 kPriorityNormal, // priority
451 kMsgEnd | kMsgsMode | kMsgsFrame | kMsgVisual | kMsgDatabase | kMsgsAppOuter, // messages we want
453 kLCF_Callback,
454 _CreateClient,
456 NO_LC_DATA,
459 { kConstrainAfter, &LOOPID_ScrnMan, kMsgsMode},
460 { kConstrainAfter, &LOOPID_UI, kMsgsMode},
461 { kConstrainAfter, &LOOPID_Res, kMsgsMode},
462 { kConstrainAfter, &LOOPID_EditGeom, kMsgsMode},
464 { kConstrainAfter, &LOOPID_Player, kMsgDatabase},
465 { kConstrainBefore, &LOOPID_ScrnMan, kMsgVisual},
467 // { kConstrainAfter, &LOOPID_People, kMsgsMode},
468 { kNullConstraint }
472 ////////////////////////////////////////////////////////////
473 // Command: edit_mode w,h
474 // Change to edit mode. w,h are screen dims
477 void enter_edit_mode(char* args)
479 EditModeDesc adesc;
480 EditModeDesc* desc = &adesc;
481 sScrnMode scrnmode = { 0 };
482 int w = 0, h = 0;
484 desc->scrnmode = &scrnmode;
486 sscanf(args,"%d,%d",&w,&h);
487 if (w != 0 && h != 0)
489 scrnmode.valid_fields |= kScrnModeDimsValid;
490 scrnmode.w = w;
491 scrnmode.h = h;
495 ILoop* looper = AppGetObj(ILoop);
496 sLoopInstantiator* loop;
498 loop = DescribeEditMode(mmEditNoChange,desc);
499 ILoop_ChangeMode(looper,kLoopModeSwitch,loop);
501 SafeRelease(looper);