camera.cc 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958
  1. /********************************************************************** <BR>
  2. This file is part of Crack dot Com's free source code release of
  3. Golgotha. <a href="http://www.crack.com/golgotha_release"> <BR> for
  4. information about compiling & licensing issues visit this URL</a>
  5. <PRE> If that doesn't help, contact Jonathan Clark at
  6. golgotha_source@usa.net (Subject should have "GOLG" in it)
  7. ***********************************************************************/
  8. #include "camera.hh"
  9. #include "global_id.hh"
  10. #include "g1_render.hh"
  11. #include "math/angle.hh"
  12. #include "input.hh"
  13. #include "player.hh"
  14. #include "objs/stank.hh"
  15. #include "math/trig.hh"
  16. #include "resources.hh"
  17. #include "map_man.hh"
  18. #include "map.hh"
  19. #include "m_flow.hh"
  20. #include "cwin_man.hh"
  21. #include "lisp/lisp.hh"
  22. #include "controller.hh"
  23. #include "objs/field_camera.hh"
  24. #include "objs/map_piece.hh"
  25. #include "saver.hh"
  26. #include "time/profile.hh"
  27. #include "lisp/lisp.hh"
  28. #include "sound/sfx_id.hh"
  29. #include "demo.hh"
  30. #include "lisp/li_init.hh"
  31. i4_profile_class pf_suggest_camera_event("suggest_camera_event");
  32. enum {
  33. G1_PAN_LEFT =(1<<0),
  34. G1_PAN_RIGHT =(1<<1),
  35. G1_PAN_FORWARD =(1<<2),
  36. G1_PAN_BACKWARD =(1<<3),
  37. G1_PAN_UP =(1<<4),
  38. G1_PAN_DOWN =(1<<5),
  39. G1_ROTATE_LEFT =(1<<6),
  40. G1_ROTATE_RIGHT =(1<<7),
  41. G1_ROTATE_UP =(1<<8),
  42. G1_ROTATE_DOWN =(1<<9),
  43. G1_MOVE_LEFT =(1<<10),
  44. G1_MOVE_RIGHT =(1<<11),
  45. G1_MOVE_FORWARD =(1<<12),
  46. G1_MOVE_BACKWARD =(1<<13)
  47. };
  48. char *cmd_names[]={"Pan Left",
  49. "Pan Right",
  50. "Pan Forward",
  51. "Pan Backward",
  52. "Pan Up",
  53. "Pan Down",
  54. "Rotate Left",
  55. "Rotate Right",
  56. "Rotate Up",
  57. "Rotate Down",
  58. "Move Left",
  59. "Move Right",
  60. "Move Forward",
  61. "Move Backward",
  62. 0};
  63. w32 g1_scroll_bits=0;
  64. li_object *g1_camera_key_press(li_object *o, li_environment *env)
  65. {
  66. w32 flag=li_get_int(li_eval(env->current_function()),env);
  67. g1_scroll_bits|=flag;
  68. return 0;
  69. }
  70. li_object *g1_camera_key_depress(li_object *o, li_environment *env)
  71. {
  72. w32 flag=li_get_int(li_eval(env->current_function()),env);
  73. g1_scroll_bits&=~flag;
  74. return 0;
  75. }
  76. li_object *g1_toggle_follow_mode(li_object *_o, li_environment *env)
  77. {
  78. g1_object_class *o=g1_player_man.get_local()->get_commander();
  79. if (g1_current_controller.get() && o)
  80. if (g1_current_controller->view.view_mode==G1_FOLLOW_MODE)
  81. g1_current_controller->view.suggest_camera_mode(G1_ACTION_MODE, o->global_id);
  82. else
  83. g1_current_controller->view.suggest_camera_mode(G1_FOLLOW_MODE, o->global_id);
  84. return 0;
  85. }
  86. class g1_add_camera_funs_initer : public i4_init_class
  87. {
  88. public:
  89. void init()
  90. {
  91. char **cmd;
  92. int f=1;
  93. for (cmd=cmd_names; *cmd; cmd++)
  94. {
  95. li_set_value(*cmd, new li_int(f));
  96. li_add_function(*cmd, g1_camera_key_press);
  97. char end_cmd[200];
  98. sprintf(end_cmd, "-%s", *cmd);
  99. li_add_function(end_cmd, g1_camera_key_depress);
  100. li_set_value(end_cmd, new li_int(f));
  101. f=f<<1;
  102. }
  103. }
  104. } g1_add_camera_funs_instance;
  105. li_object *g1_action_mode(li_object *o, li_environment *env)
  106. {
  107. if (g1_current_view_state())
  108. g1_current_view_state()->suggest_camera_mode(G1_ACTION_MODE);
  109. return 0;
  110. }
  111. li_object *g1_strategy_mode(li_object *o, li_environment *env)
  112. {
  113. if (g1_current_view_state())
  114. g1_current_view_state()->suggest_camera_mode(G1_STRATEGY_MODE);
  115. return 0;
  116. }
  117. li_object *g1_follow_mode(li_object *o, li_environment *env)
  118. {
  119. g1_player_piece_class *com=g1_player_man.get_local()->get_commander();
  120. if (g1_current_view_state() && com)
  121. g1_current_view_state()->suggest_camera_mode(G1_FOLLOW_MODE, com->global_id);
  122. return 0;
  123. }
  124. li_object *g1_camera_mode(li_object *o, li_environment *env)
  125. {
  126. if (g1_current_view_state())
  127. g1_current_view_state()->suggest_camera_mode(G1_WATCH_MODE);
  128. return 0;
  129. }
  130. li_object *g1_set_current_camera(li_object *o, li_environment *env)
  131. {
  132. if (g1_current_view_state() && g1_current_controller.get())
  133. {
  134. g1_object_class *c=g1_find_named_camera(li_get_string(li_eval(li_car(o,env),env),env));
  135. if (c)
  136. {
  137. g1_camera_event evt;
  138. evt.camera_at=c;
  139. evt.type=G1_WATCH_FORCE;
  140. g1_current_controller->view.suggest_camera_event(evt);
  141. }
  142. }
  143. return 0;
  144. }
  145. li_object *g1_set_camera_position(li_object *o, li_environment *env)
  146. {
  147. if (g1_current_view_state())
  148. {
  149. float x=li_get_float(li_eval(li_first(o,env), env),env);
  150. float y=li_get_float(li_eval(li_second(o,env), env),env);
  151. g1_current_view_state()->set_camera_position(x,y);
  152. }
  153. return 0;
  154. }
  155. void g1_camera_info_struct::defaults()
  156. {
  157. gx=gy=1;
  158. gz=10;
  159. horizon_rotate=i4_pi()/2;
  160. ground_rotate=i4_pi()/2;
  161. roll=0;
  162. }
  163. void g1_camera_info_struct::load(g1_loader_class *fp)
  164. {
  165. fp->read_format("ffffff", &gx, &gy, &gz, &ground_rotate, &horizon_rotate, &roll);
  166. }
  167. void g1_camera_info_struct::save(g1_saver_class *fp)
  168. {
  169. fp->write_format("ffffff", &gx, &gy, &gz, &ground_rotate, &horizon_rotate, &roll);
  170. }
  171. g1_camera_event::g1_camera_event()
  172. {
  173. follow_object=0;
  174. camera_at=0;
  175. type=G1_WATCH_INVALID;
  176. min_time=10, max_time=50; // min/max times to sustain camera shot (in ticks)
  177. time_elapsed=0; // time that we've spent on this shot already (in ticks)
  178. };
  179. void g1_view_state_class::save(g1_saver_class *fp)
  180. {
  181. fp->start_version(1);
  182. start.save(fp);
  183. end.save(fp);
  184. fp->write_format("ff",
  185. &start_end_interpolate_fraction,
  186. &start_end_interpolate_fraction_step);
  187. fp->write_8(view_mode);
  188. fp->write_global_id(follow_object_id);
  189. fp->end_version();
  190. }
  191. void g1_view_state_class::defaults()
  192. {
  193. move_offset=i4_3d_vector(0,0,0);
  194. watch_type=G1_WATCH_IDLE;
  195. follow_object_id=g1_global_id.invalid_id();
  196. view_mode=G1_STRATEGY_MODE;
  197. start_end_interpolate_fraction_step=0.0;
  198. start_end_interpolate_fraction=1.0;
  199. start_invalid=i4_T;
  200. start.defaults();
  201. end.defaults();
  202. current.defaults();
  203. }
  204. void g1_camera_event::object_ids_changed() // call after level is reloaded
  205. {
  206. camera_at=0;
  207. follow_object=0;
  208. }
  209. void g1_view_state_class::load(g1_loader_class *fp)
  210. {
  211. if (fp && fp->check_version(1))
  212. {
  213. start.load(fp);
  214. end.load(fp);
  215. fp->read_format("ff",
  216. &start_end_interpolate_fraction,
  217. &start_end_interpolate_fraction_step);
  218. view_mode=(g1_view_mode_type)fp->read_8();
  219. follow_object_id=fp->read_global_id();
  220. }
  221. else
  222. follow_object_id=g1_global_id.invalid_id();
  223. current_cam.object_ids_changed();
  224. next_cam.object_ids_changed();
  225. }
  226. g1_view_state_class::g1_view_state_class()
  227. {
  228. defaults();
  229. }
  230. // calculates current and returns a pointer to it
  231. g1_camera_info_struct *g1_view_state_class::get_camera()
  232. {
  233. float fr=g1_render.frame_ratio;
  234. if (fr>1.0) fr=1.0;
  235. if (fr<0.0) fr=0.0;
  236. float i=start_end_interpolate_fraction + start_end_interpolate_fraction_step * fr;
  237. current.gx = i4_interpolate(start.gx, end.gx, i);
  238. current.gy = i4_interpolate(start.gy, end.gy, i);
  239. current.gz = i4_interpolate(start.gz, end.gz, i);
  240. current.ground_rotate = i4_interpolate_angle(start.ground_rotate, end.ground_rotate, i);
  241. current.horizon_rotate = i4_interpolate_angle(start.horizon_rotate, end.horizon_rotate, i);
  242. current.roll = i4_interpolate_angle(start.roll, end.roll, i);
  243. current.ground_x_rotate = i4_interpolate_angle(start.ground_x_rotate, end.ground_x_rotate, i);
  244. current.ground_y_rotate = i4_interpolate_angle(start.ground_y_rotate, end.ground_y_rotate, i);
  245. return &current;
  246. }
  247. void g1_view_state_class::update_follow_mode()
  248. {
  249. start=end;
  250. g1_object_class *follow = g1_global_id.check_id(follow_object_id) ?
  251. g1_global_id.get(follow_object_id) : 0;
  252. if (follow)
  253. {
  254. g1_player_piece_class *stank=g1_player_man.get_local()->get_commander();
  255. i4_float fr = g1_render.frame_ratio;
  256. i4_float itheta = follow==stank ? stank->base_angle : follow->theta;
  257. i4_float idist = g1_resources.follow_camera_dist;
  258. i4_float iheight = g1_resources.follow_camera_height;
  259. i4_float ix = follow->x;
  260. i4_float iy = follow->y;
  261. i4_float ih = follow->h+ 0.1;
  262. end.ground_rotate = g1_resources.follow_camera_rotation + itheta;
  263. end.gx = ix - cos(end.ground_rotate) * idist;
  264. end.gy = iy - sin(end.ground_rotate) * idist;
  265. float th = ih + iheight;
  266. float gh = g1_get_map()->terrain_height(end.gx, end.gy)+0.01;
  267. if (th < gh)
  268. {
  269. g1_resources.follow_camera_height = gh - ih;
  270. th = gh;
  271. }
  272. end.gz = th;
  273. float xy_dist = sqrt((ix - end.gx) * (ix - end.gx) +
  274. (iy - end.gy) * (iy - end.gy));
  275. end.horizon_rotate = i4_atan2(end.gz - ih, xy_dist);
  276. end.roll=0;
  277. end.ground_x_rotate=0;
  278. end.ground_y_rotate=0;
  279. start_end_interpolate_fraction=0.0;
  280. start_end_interpolate_fraction_step=1.0;
  281. }
  282. else
  283. {
  284. view_mode=G1_WATCH_MODE;
  285. update();
  286. }
  287. }
  288. void g1_view_state_class::update_action_mode()
  289. {
  290. g1_player_piece_class *stank=g1_player_man.get_local()->get_commander();
  291. if (!stank)
  292. {
  293. view_mode=G1_WATCH_MODE;
  294. update();
  295. }
  296. else
  297. {
  298. stank->calc_action_cam(start,0);
  299. stank->calc_action_cam(end,1);
  300. start_end_interpolate_fraction=0.0;
  301. start_end_interpolate_fraction_step=1.0;
  302. }
  303. }
  304. li_symbol_ref watch_camera_turn_speed("watch_camera_turn_speed"),
  305. watch_camera_max_speed("watch_camera_max_speed"),
  306. watch_camera_accel("watch_camera_accel");
  307. void g1_check_position(float &x, float &y)
  308. {
  309. if (x<0) x=0;
  310. if (y<0) y=0;
  311. if (x+1>=g1_get_map()->width()) x=g1_get_map()->width()-1;
  312. if (x+1>=g1_get_map()->height()) x=g1_get_map()->height()-1;
  313. }
  314. void g1_view_state_class::use_next_cam()
  315. {
  316. if (next_cam.camera_at.get()==current_cam.camera_at.get()) // don't snap if same camera position
  317. next_cam.time_elapsed=1;
  318. current_cam=next_cam;
  319. next_cam.type=G1_WATCH_INVALID;
  320. if (current_cam.type!=G1_WATCH_INVALID)
  321. {
  322. g1_object_class *watch_obj=current_cam.follow_object.get();
  323. if (watch_obj)
  324. {
  325. i4_3d_vector pos=i4_3d_vector(watch_obj->x, watch_obj->y, watch_obj->h);
  326. g1_object_class *cam_object=g1_find_closest_field_camera(pos);
  327. if (cam_object)
  328. current_cam.camera_at=cam_object;
  329. }
  330. else if (next_cam.camera_at.get())
  331. {
  332. i4_transform_class t;
  333. g1_object_class *cam=next_cam.camera_at.get();
  334. cam->world_transform=&t;
  335. cam->calc_world_transform(0, &t);
  336. i4_3d_vector startp,endp;
  337. t.transform(i4_3d_vector(0,0,0), startp);
  338. t.transform(i4_3d_vector(1,0,0), endp);
  339. float xy_theta=i4_atan2(endp.y - startp.y, endp.x - startp.x);
  340. float xy_dist=sqrt((endp.y - startp.y) * (endp.y - startp.y) +
  341. (endp.x - startp.x) * (endp.x - startp.x));
  342. float z_theta=i4_atan2(endp.z - startp.z, xy_dist);
  343. end.gx=startp.x;
  344. end.gy=startp.y;
  345. end.gz=startp.z;
  346. end.ground_x_rotate=0;
  347. end.ground_y_rotate=0;
  348. end.ground_rotate=xy_theta;
  349. end.horizon_rotate=-z_theta;
  350. end.roll = 0;
  351. start=end;
  352. }
  353. }
  354. }
  355. void g1_view_state_class::update_watch_mode()
  356. {
  357. start=end;
  358. i4_bool next=i4_F;
  359. // see if the next camera has higher priority
  360. if ((next_cam.type>current_cam.type && current_cam.time_elapsed>current_cam.min_time) ||
  361. (next_cam.type!=G1_WATCH_INVALID && current_cam.time_elapsed>current_cam.max_time))
  362. next=i4_T;
  363. if (!current_cam.follow_object.get()) // object following is gone
  364. next=i4_T;
  365. if (current_cam.type==G1_WATCH_INVALID)
  366. next=i4_T;
  367. if (next)
  368. use_next_cam();
  369. if (current_cam.type==G1_WATCH_INVALID)
  370. return ;
  371. g1_object_class *obj_to_watch=current_cam.follow_object.get();
  372. g1_object_class *camera_at=current_cam.camera_at.get();
  373. if (camera_at)
  374. {
  375. end.gx=camera_at->x;
  376. end.gy=camera_at->y;
  377. end.gz=camera_at->h;
  378. }
  379. if (obj_to_watch)
  380. {
  381. i4_3d_vector watch=i4_3d_vector(obj_to_watch->x, obj_to_watch->y, obj_to_watch->h);
  382. float xy_theta=i4_atan2(watch.y - end.gy, watch.x - end.gx);
  383. float xy_dist=sqrt((watch.y - end.gy) * (watch.y - end.gy) +
  384. (watch.x - end.gx) * (watch.x - end.gx));
  385. float z_theta=i4_atan2(watch.z - end.gz, xy_dist);
  386. float turn_speed=li_get_float(li_get_value(watch_camera_turn_speed.get()),0);
  387. if (current_cam.time_elapsed==0) // ifrst tick it's ok to snap
  388. {
  389. end.ground_rotate=xy_theta;
  390. end.horizon_rotate=-z_theta;
  391. }
  392. else
  393. {
  394. i4_rotate_to(end.ground_rotate, xy_theta, turn_speed);
  395. i4_rotate_to(end.horizon_rotate, -z_theta, turn_speed);
  396. }
  397. end.roll = 0;
  398. }
  399. current_cam.time_elapsed++;
  400. start_end_interpolate_fraction=0.0;
  401. start_end_interpolate_fraction_step=1.0;
  402. }
  403. void g1_view_state_class::update_circle_mode()
  404. {
  405. start=end;
  406. i4_3d_vector watch=circle.looking_at;
  407. // camera vel
  408. // x = angle of ration about object being watched
  409. // y = distance in from object in xy plane
  410. // z = height above object
  411. if (end.gz-watch.z<3)
  412. {
  413. end.gz+=circle.zvel;
  414. circle.zvel+=0.0005;
  415. if (circle.zvel>0.1)
  416. circle.zvel=0.1;
  417. }
  418. circle.dist+=circle.dist_vel;
  419. circle.dist_vel-=0.01;
  420. if (circle.dist_vel<0)
  421. circle.dist_vel=0;
  422. circle.theta+=circle.theta_vel;
  423. end.gx=watch.x + cos(circle.theta)*circle.dist;
  424. end.gy=watch.y + sin(circle.theta)*circle.dist;
  425. float xy_theta=i4_atan2(watch.y - end.gy, watch.x - end.gx);
  426. float xy_dist=sqrt((watch.y - end.gy) * (watch.y - end.gy) +
  427. (watch.x - end.gx) * (watch.x - end.gx));
  428. float z_theta=i4_atan2(watch.z - end.gz, xy_dist);
  429. end.ground_rotate=xy_theta;
  430. end.horizon_rotate=-z_theta;
  431. end.roll = 0;
  432. end.ground_x_rotate=end.ground_y_rotate=0;
  433. start_end_interpolate_fraction=0.0;
  434. start_end_interpolate_fraction_step=1.0;
  435. }
  436. void g1_view_state_class::update_strategy_mode()
  437. {
  438. i4_angle a=end.ground_rotate, move_speed=1.0;
  439. start=end;
  440. end.ground_x_rotate=end.ground_y_rotate=0;
  441. end.ground_rotate=i4_pi()/2;
  442. end.horizon_rotate=i4_pi()/2 - i4_pi()/8;
  443. end.roll=0;
  444. if (g1_scroll_bits & G1_MOVE_LEFT)
  445. g1_current_controller->pan(-sin(a)*move_speed, cos(a)*move_speed, 0);
  446. if (g1_scroll_bits & G1_MOVE_RIGHT)
  447. g1_current_controller->pan(sin(a)*move_speed, -cos(a)*move_speed, 0);
  448. if (g1_scroll_bits & G1_MOVE_FORWARD)
  449. g1_current_controller->pan(cos(a)*move_speed, sin(a)*move_speed, 0);
  450. if (g1_scroll_bits & G1_MOVE_BACKWARD)
  451. g1_current_controller->pan(-cos(a)*move_speed, -sin(a)*move_speed, 0);
  452. end.gx+=move_offset.x;
  453. end.gy+=move_offset.y;
  454. move_offset=i4_3d_vector(0,0,0);
  455. if (end.gx<2.0) end.gx = 2.0;
  456. else if (end.gx>g1_map_width-2.0) end.gx = g1_map_width-2.0;
  457. if (end.gy<2.0) end.gy = 2.0;
  458. else if (end.gy>g1_map_height-2.0) end.gy = g1_map_height-2.0;
  459. end.gz=g1_get_map()->terrain_height(end.gx, end.gy) + g1_resources.startegy_camera_dist;
  460. start_end_interpolate_fraction=0.0;
  461. start_end_interpolate_fraction_step=1.0;
  462. }
  463. static float g1_pan_speed=0, g1_rotate_speed=0;
  464. static li_symbol_ref editor_pan_accel("editor_pan_accel");
  465. static li_symbol_ref editor_rotate_accel("editor_rotate_accel");
  466. void g1_view_state_class::update_edit_mode()
  467. {
  468. start_end_interpolate_fraction=1.0;
  469. start_end_interpolate_fraction_step=0;
  470. i4_angle a=end.ground_rotate;
  471. end.gx+=move_offset.x;
  472. end.gy+=move_offset.y;
  473. move_offset=i4_3d_vector(0,0,0);
  474. if (g1_scroll_bits & (G1_ROTATE_DOWN | G1_ROTATE_UP | G1_ROTATE_RIGHT | G1_ROTATE_LEFT))
  475. g1_rotate_speed+=li_get_float(li_get_value(editor_rotate_accel.get()),0);
  476. else
  477. g1_rotate_speed=0;
  478. if (g1_scroll_bits & (G1_PAN_DOWN | G1_PAN_UP | G1_PAN_RIGHT | G1_PAN_LEFT |
  479. G1_PAN_FORWARD | G1_PAN_BACKWARD))
  480. {
  481. g1_pan_speed+=li_get_float(li_get_value(editor_pan_accel.get()),0);
  482. if (g1_pan_speed>4)
  483. g1_pan_speed=4;
  484. }
  485. else
  486. g1_pan_speed=0;
  487. if (g1_scroll_bits & G1_ROTATE_LEFT)
  488. g1_current_controller->rotate(g1_rotate_speed, 0);
  489. if (g1_scroll_bits & G1_ROTATE_RIGHT)
  490. g1_current_controller->rotate(-g1_rotate_speed, 0);
  491. if (g1_scroll_bits & G1_ROTATE_UP)
  492. g1_current_controller->rotate(0, -g1_rotate_speed);
  493. if (g1_scroll_bits & G1_ROTATE_DOWN)
  494. g1_current_controller->rotate(0, g1_rotate_speed);
  495. if (g1_scroll_bits & G1_PAN_DOWN)
  496. g1_current_controller->pan(0,0,-g1_pan_speed);
  497. if (g1_scroll_bits & G1_PAN_UP)
  498. g1_current_controller->pan(0,0,g1_pan_speed);
  499. if (g1_scroll_bits & G1_PAN_LEFT)
  500. g1_current_controller->pan(-sin(a)*g1_pan_speed, cos(a)*g1_pan_speed,0);
  501. if (g1_scroll_bits & G1_PAN_RIGHT)
  502. g1_current_controller->pan(sin(a)*g1_pan_speed, -cos(a)*g1_pan_speed,0);
  503. if (g1_scroll_bits & G1_PAN_FORWARD)
  504. g1_current_controller->pan(cos(a)*g1_pan_speed, sin(a)*g1_pan_speed,0);
  505. if (g1_scroll_bits & G1_PAN_BACKWARD)
  506. g1_current_controller->pan(-cos(a)*g1_pan_speed, -sin(a)*g1_pan_speed,0);
  507. }
  508. void g1_view_state_class::update_camera_mode()
  509. {
  510. g1_movie_flow_class *m=g1_get_map()->current_movie;
  511. g1_cut_scene_class *cut=m ? m->current() : 0;
  512. if (cut)
  513. {
  514. i4_float cx, cy, cz, tx, ty, tz, xy_theta, z_theta, xy_dist;
  515. cut->paths[g1_cut_scene_class::CAMERA].get_point(m->get_frame(), cx,cy,cz);
  516. cut->paths[g1_cut_scene_class::TARGET].get_point(m->get_frame(), tx,ty,tz);
  517. xy_theta=i4_atan2(ty-cy, tx-cx);
  518. xy_dist=sqrt((ty-cy)*(ty-cy) + (tx-cx)*(tx-cx));
  519. z_theta=i4_atan2(tz-cz, xy_dist);
  520. end.gx=cx; end.gy=cy; end.gz=cz;
  521. end.ground_rotate=xy_theta;
  522. end.horizon_rotate=-z_theta;
  523. end.roll = 0;
  524. }
  525. else
  526. {
  527. view_mode=G1_WATCH_MODE;
  528. update();
  529. return;
  530. }
  531. }
  532. // should be called after every tick, updates end camera pos
  533. void g1_view_state_class::update()
  534. {
  535. if (&g1_current_controller->view==this)
  536. g1_change_key_context(view_mode);
  537. if (start_end_interpolate_fraction>=1.0)
  538. {
  539. start=end;
  540. start_end_interpolate_fraction_step=1.0;
  541. start_end_interpolate_fraction=0;
  542. }
  543. else
  544. start_end_interpolate_fraction+=start_end_interpolate_fraction_step;
  545. switch (view_mode)
  546. {
  547. case G1_EDIT_MODE :
  548. update_edit_mode();
  549. break;
  550. case G1_STRATEGY_MODE :
  551. update_strategy_mode();
  552. break;
  553. case G1_ACTION_MODE :
  554. update_action_mode();
  555. break;
  556. case G1_FOLLOW_MODE :
  557. update_follow_mode();
  558. break;
  559. case G1_CAMERA_MODE :
  560. update_camera_mode();
  561. break;
  562. case G1_WATCH_MODE :
  563. update_watch_mode();
  564. break;
  565. case G1_CIRCLE_WAIT :
  566. update_circle_mode();
  567. break;
  568. }
  569. }
  570. void g1_view_state_class::calc_transform(i4_transform_class &transform)
  571. {
  572. g1_camera_info_struct *c=get_camera();
  573. // now calculate our actual transform
  574. i4_transform_class tmp;
  575. transform.identity();
  576. tmp.rotate_y(i4_pi());
  577. transform.multiply(tmp);
  578. tmp.rotate_x(i4_pi()/2);
  579. transform.multiply(tmp);
  580. tmp.rotate_z(-i4_pi()/2);
  581. transform.multiply(tmp);
  582. tmp.rotate_x(-c->roll);
  583. transform.multiply(tmp);
  584. tmp.rotate_y(-c->horizon_rotate);
  585. transform.multiply(tmp);
  586. tmp.rotate_z(-c->ground_rotate);
  587. transform.multiply(tmp);
  588. //action mode is the only mode that specifies these
  589. tmp.rotate_y(-c->ground_y_rotate);
  590. transform.multiply(tmp);
  591. tmp.rotate_x(-c->ground_x_rotate);
  592. transform.multiply(tmp);
  593. tmp.translate(-c->gx, -c->gy, -c->gz);
  594. transform.multiply(tmp);
  595. s1_set_camera_pos(transform);
  596. }
  597. void g1_view_state_class::suggest_camera_mode(g1_view_mode_type mode,
  598. w32 follow_object_global_id)
  599. {
  600. if (mode==G1_CIRCLE_WAIT)
  601. {
  602. g1_object_class *o=g1_global_id.checked_get(follow_object_global_id);
  603. if (o)
  604. {
  605. circle.zvel=circle.theta=0;
  606. circle.theta_vel=0.05;
  607. circle.dist=1;
  608. circle.dist_vel=0.2;
  609. circle.looking_at=i4_3d_vector(o->x, o->y, o->h);
  610. end.gz=o->h+0.1;
  611. }
  612. else return ;
  613. }
  614. view_mode=mode;
  615. follow_object_id=follow_object_global_id;
  616. switch (mode)
  617. {
  618. case G1_STRATEGY_MODE :
  619. g1_demo_script_add("(strategy_mode)");
  620. break;
  621. case G1_ACTION_MODE :
  622. g1_demo_script_add("(action_mode)");
  623. break;
  624. case G1_FOLLOW_MODE :
  625. g1_demo_script_add("(follow_mode)");
  626. break;
  627. }
  628. }
  629. void g1_view_state_class::set_camera_position(float game_x, float game_y)
  630. {
  631. move_offset.x=game_x-end.gx;
  632. move_offset.y=game_y-end.gy;
  633. char cmd[50];
  634. sprintf(cmd, "(set_camera_pos %0.2f %0.2f)", game_x, game_y);
  635. g1_demo_script_add(cmd);
  636. }
  637. void g1_view_state_class::suggest_camera_event(g1_camera_event &event)
  638. {
  639. pf_suggest_camera_event.start();
  640. if (event.type==G1_WATCH_FORCE)
  641. {
  642. next_cam=event;
  643. suggest_camera_mode(G1_WATCH_MODE, event.follow_object.get() ?
  644. event.follow_object->global_id : 0 );
  645. }
  646. #if 0
  647. if (event.type>next_cam.type)
  648. {
  649. next_cam=event;
  650. if (event.type==G1_WATCH_FORCE)
  651. suggest_camera_mode(G1_WATCH_MODE, event.follow_object.get() ?
  652. event.follow_object->global_id : 0 );
  653. }
  654. // see if next is same type & at the caera location
  655. else
  656. {
  657. i4_bool current_dead=i4_F;
  658. // object we are watching is dead
  659. g1_map_piece_class *mp;
  660. mp=g1_map_piece_class::cast(current_cam.follow_object.get());
  661. if (mp && mp->health<=0)
  662. current_dead=i4_T;
  663. if ((current_dead || event.type==next_cam.type) &&
  664. next_cam.camera_at.get()!=current_cam.camera_at.get())
  665. {
  666. g1_object_class *watch_obj=next_cam.follow_object.get();
  667. if (watch_obj)
  668. {
  669. i4_3d_vector pos=i4_3d_vector(watch_obj->x, watch_obj->y, watch_obj->h);
  670. g1_object_class *cam_object=g1_find_closest_field_camera(pos);
  671. if (cam_object && cam_object==current_cam.camera_at.get())
  672. current_cam.camera_at=cam_object;
  673. }
  674. }
  675. }
  676. #endif
  677. pf_suggest_camera_event.stop();
  678. }
  679. void g1_view_state_class::get_camera_pos(i4_3d_vector &v)
  680. {
  681. v.x=current.gx;
  682. v.y=current.gy;
  683. v.z=current.gz;
  684. }
  685. float g1_view_state_class::dist_sqrd(const i4_3d_vector &v)
  686. {
  687. float d=(end.gx-v.x)*(end.gx-v.x) +
  688. (end.gy-v.y)*(end.gy-v.y) +
  689. (end.gz-v.z)*(end.gz-v.z);
  690. return d;
  691. }
  692. void g1_view_state_class::zoom(float dist)
  693. {
  694. float xy_contribute=fabs(cos(end.horizon_rotate));
  695. i4_3d_vector move_vector(cos(end.ground_rotate) * xy_contribute,
  696. sin(end.ground_rotate) * xy_contribute,
  697. -sin(end.horizon_rotate));
  698. end.gx+=move_vector.x * dist;
  699. end.gy+=move_vector.y * dist;
  700. end.gz+=move_vector.z * dist;
  701. }
  702. void g1_view_state_class::pan(i4_float x, i4_float y, i4_float z)
  703. {
  704. end.gx+=x;
  705. end.gy+=y;
  706. end.gz+=z;
  707. }
  708. void g1_view_state_class::rotate(i4_float about_game_z, i4_float up_down)
  709. {
  710. end.horizon_rotate+=up_down;
  711. end.ground_rotate+=about_game_z;
  712. }
  713. g1_view_state_class *g1_current_view_state()
  714. {
  715. if (!g1_current_controller.get())
  716. return 0;
  717. else
  718. return &g1_current_controller->view;
  719. }
  720. li_automatic_add_function(g1_action_mode, "action_mode");
  721. li_automatic_add_function(g1_strategy_mode, "strategy_mode");
  722. li_automatic_add_function(g1_follow_mode, "follow_mode");
  723. li_automatic_add_function(g1_set_camera_position, "set_camera_pos");
  724. li_automatic_add_function(g1_camera_mode, "camera_mode");
  725. li_automatic_add_function(g1_set_current_camera, "set_current_camera");
  726. li_automatic_add_function(g1_toggle_follow_mode, "toggle_follow_mode");