]> icculus.org git repositories - taylor/freespace2.git/blob - src/pofview/pofviewcanvas.cpp
merge in updated platform code
[taylor/freespace2.git] / src / pofview / pofviewcanvas.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on
6  * the source.
7  */
8
9 #include "pofview.h"
10
11 #include "pstypes.h"
12 #include "2d.h"
13 #include "3d.h"
14 #include "bmpman.h"
15 #include "systemvars.h"
16 #include "cfile.h"
17 #include "timer.h"
18 #include "key.h"
19 #include "mouse.h"
20
21 #include "floating.h"
22 #include "lighting.h"
23
24
25 float flFrametime;              // used by game lib; DO NOT REMOVE!!
26
27 extern bool in_dialog;
28
29
30 // Stuff for showing ship thrusters.
31 typedef struct thrust_anim {
32         int     num_frames;
33         int     first_frame;
34         float time;                             // in seconds
35 } thrust_anim;
36
37 #define NUM_THRUST_ANIMS                                4
38
39 #define THRUST_ANIM_NORMAL                              0
40 #define THRUST_ANIM_AFTERBURNER                 1
41 #define THRUST_ANIM_GLOW_NORMAL                 2
42 #define THRUST_ANIM_GLOW_AFTERBURNER    3
43
44 static thrust_anim Thrust_anims[NUM_THRUST_ANIMS];
45
46 static char Thrust_anim_names[NUM_THRUST_ANIMS][MAX_FILENAME_LEN] = {
47         "thruster01",
48         "thruster01a",
49         "thrusterglow01",
50         "thrusterglow01a"
51 };
52
53
54 ///////////////////////////////////////////////////////////////////////////////
55
56 PofViewTimer::PofViewTimer(PofViewCanvas *canvas)
57         : wxTimer()
58 {
59         m_canvas = canvas;
60         m_thrust_timer = -1;
61 }
62
63 PofViewTimer::~PofViewTimer()
64 {
65 }
66
67 void PofViewTimer::Notify()
68 {
69         float frame_time;
70
71         if (m_thrust_timer == -1) {
72                 m_thrust_timer = timer_get_milliseconds();
73         }
74
75         int tmp_time = timer_get_milliseconds();
76
77         frame_time = ((float)(tmp_time-m_thrust_timer)) / 1000.0f;
78         flFrametime = frame_time;
79
80         m_thrust_timer = tmp_time;
81
82         m_canvas->DoThrusterFrame(frame_time);
83         m_canvas->MoveViewer(frame_time);
84         m_canvas->Render();
85 }
86
87 wxBEGIN_EVENT_TABLE(PofViewCanvas, wxGLCanvas)
88         EVT_SIZE(PofViewCanvas::OnSize)
89         EVT_PAINT(PofViewCanvas::OnPaint)
90         EVT_ERASE_BACKGROUND(PofViewCanvas::OnEraseBackground)
91         EVT_MOUSE_EVENTS(PofViewCanvas::OnMouse)
92 wxEND_EVENT_TABLE()
93
94 PofViewCanvas::PofViewCanvas(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name)
95         : wxGLCanvas(parent, id, NULL, pos, size, style | wxFULL_REPAINT_ON_RESIZE, name)
96 {
97         first_frame = true;
98         m_ViewerZoom = 0.8f;
99         m_ViewerPos = vmd_zero_vector;
100         m_ViewerPos.xyz.z = -10.0f;
101         m_ViewerOrient = vmd_identity_matrix;
102         m_ObjectOrient = vmd_identity_matrix;
103
104         physics_init( &m_ViewerPhysics );
105         m_ViewerPhysics.flags |= PF_ACCELERATES | PF_SLIDE_ENABLED;
106
107         memset( &m_Viewer_ci, 0, sizeof(control_info) );
108
109         m_mouse_inited = 0;
110         m_mouse_dx = 0;
111         m_mouse_dy = 0;
112
113         m_timer = new PofViewTimer(this);
114         m_timer->Start(1000/30);
115
116         thrust_anim_inited = false;
117
118         model_thrust = 0.5f;
119         model_afterburner = 0;
120
121         shipp_thruster_bitmap = -1;
122         shipp_thruster_frame = 0.0f;
123
124         shipp_thruster_glow_bitmap = -1;
125         shipp_thruster_glow_frame = 0.0f;
126         shipp_thruster_glow_noise = 1.0f;
127 }
128
129 PofViewCanvas::~PofViewCanvas()
130 {
131         delete m_timer;
132 }
133
134
135 extern float Ambient_light;
136 extern void opengl1_tcache_frame();
137
138 static vector Global_light_world = { { { -0.208758f, -0.688253f, 0.694782f } } };
139
140
141 void PofViewCanvas::Render()
142 {
143         PofViewFrame *parent = (PofViewFrame *)GetParent();
144
145         int model_num = parent->GetModelnum();
146
147         if (model_num < 0) {
148                 return;
149         }
150
151         polymodel *pm = model_get(model_num);
152         wxASSERT( pm );
153
154         if (first_frame) {
155                 m_ViewerPos.xyz.z = -pm->rad * 1.5f;
156                 first_frame = false;
157         }
158
159         int w, h;
160
161         GetClientSize(&w, &h);
162
163         gr_reset_clip();
164         gr_set_clip(0, 0, w, h);
165
166         gr_set_clear_color(0, 0, 0);
167         gr_clear();
168         gr_set_color(127, 127, 127);
169
170         float saved_Ambient_light = Ambient_light;
171
172         light_reset();
173
174         if ( parent->LightingOn() ) {
175                 light_add_directional(&Global_light_world, 1.0f, 1.0f, 1.0f, 1.0f);
176         } else {
177                 Ambient_light = 0.0f;
178         }
179
180         g3_start_frame(1);
181
182         g3_set_view_matrix(&m_ViewerPos, &m_ViewerOrient, m_ViewerZoom);
183
184         uint render_flags = 0;
185
186         if ( !parent->UseLighting() ) {
187                 render_flags |= MR_NO_LIGHTING;
188         }
189
190         if ( parent->ShowOutline() ) {
191                 render_flags |= MR_SHOW_OUTLINE;
192                 model_set_outline_color(0,0,0);
193         }
194
195         if ( parent->ShowShields() ){
196                 render_flags |= MR_SHOW_SHIELDS;
197         }
198
199         if ( parent->ShowInvisible() )  {
200                 render_flags |= MR_SHOW_INVISIBLE_FACES;
201         }
202 /*
203         if ( parent->ShowOverwrite() ) {
204                 Tmap_show_layers = 1;
205         } else {
206                 Tmap_show_layers = 0;
207         }
208 */
209         if ( parent->ShowPivots() ) {
210                 render_flags |= MR_SHOW_PIVOTS;
211         }
212
213         if ( parent->ShowPaths() ) {
214                 render_flags |= MR_SHOW_PATHS;
215         }
216
217         if ( parent->ShowRadius() ) {
218                 render_flags |= MR_SHOW_RADIUS;
219         }
220
221         if ( !parent->UseSmoothing() ) {
222                 render_flags |= MR_NO_SMOOTHING;
223         }
224
225         if ( !parent->UseTexturing() ) {
226                 render_flags |= MR_NO_TEXTURING;
227         }
228
229         if ( parent->GetDetailLevel() > 0 ) {
230                 render_flags |= MR_LOCK_DETAIL;
231                 model_set_detail_level(parent->GetDetailLevel()-1);
232         }
233
234         if ( parent->ShowBayPaths() ) {
235                 render_flags |= MR_BAY_PATHS;
236         }
237
238         if ( parent->UseAutocenter() ) {
239                 render_flags |= MR_AUTOCENTER;
240         }
241
242         vector temp_pos = { { { 0.0f, 0.0f, 0.0f } } };
243
244         model_clear_instance( model_num );
245
246         model_show_damaged(model_num, parent->ShowDamaged() );
247
248         if ( model_afterburner ){
249                 model_set_thrust( model_num, 1.0f, shipp_thruster_bitmap, shipp_thruster_glow_bitmap, shipp_thruster_glow_noise );
250         } else {
251                 model_set_thrust( model_num, model_thrust, shipp_thruster_bitmap, shipp_thruster_glow_bitmap, shipp_thruster_glow_noise );
252         }
253
254         if ( parent->ShowThrusters() ) {
255                 render_flags |= MR_SHOW_THRUSTERS;
256         }
257
258         static int whee = -1;
259         if(whee == -1){
260                 whee = bm_load("helvig.pcx");
261         }
262         if(whee != -1){
263                 model_set_insignia_bitmap(whee);
264         }
265
266         if ( parent->GetDetailLevel() > 0 )     {
267                 model_render( model_num, &m_ObjectOrient, &temp_pos, render_flags );
268         } else {
269                 for (int i = 0; i < pm->num_debris_objects; i++) {
270                         vector tmp = { { { 0.0f, 0.0f, 0.0f } } };
271                         vector tmp1 = pm->submodel[pm->debris_objects[i]].offset;
272                         model_find_world_point(&tmp, &tmp1, model_num, -1,&m_ObjectOrient, &temp_pos );
273                         submodel_render( model_num, pm->debris_objects[i],&m_ObjectOrient, &tmp, render_flags );
274                 }
275         }
276
277         g3_end_frame();
278
279         this->SwapBuffers();
280
281         opengl1_tcache_frame();
282
283         Ambient_light = saved_Ambient_light;
284 }
285
286 // JAS - figure out which thruster bitmap will get rendered next
287 // time around.  ship_render needs to have shipp_thruster_bitmap set to
288 // a valid bitmap number, or -1 if we shouldn't render thrusters.
289 void PofViewCanvas::DoThrusterFrame(float frame_time)
290 {
291         float rate;
292         int framenum;
293         thrust_anim *the_anim;
294
295         if ( !thrust_anim_inited ) {
296                 InitThrusters();
297         }
298
299         if (model_afterburner) {
300                 the_anim = &Thrust_anims[THRUST_ANIM_AFTERBURNER];
301                 rate = 1.2f;            // go at 1.2x faster when afterburners on
302         } else {
303                 the_anim = &Thrust_anims[THRUST_ANIM_NORMAL];
304                 // If thrust at 0, go at half as fast, full thrust; full framerate
305                 // so set rate from 0.5 to 1.0, depending on thrust from 0 to 1
306                 rate = 0.5f + model_thrust / 2.0f;
307         }
308
309         shipp_thruster_frame += frame_time * rate;
310
311         // Sanity checks
312         if ( shipp_thruster_frame < 0.0f )      shipp_thruster_frame = 0.0f;
313         if ( shipp_thruster_frame > 100.0f ) shipp_thruster_frame = 0.0f;
314
315         if ( shipp_thruster_frame > the_anim->time )    {
316                 shipp_thruster_frame -= the_anim->time;
317         }
318         framenum = fl2i( (shipp_thruster_frame*the_anim->num_frames) / the_anim->time );
319         if ( framenum < 0 ) framenum = 0;
320         if ( framenum >= the_anim->num_frames ) framenum = the_anim->num_frames-1;
321
322         // Get the bitmap for this frame
323         shipp_thruster_bitmap = the_anim->first_frame + framenum;
324
325 //      mprintf(( "TF: %.2f\n", shipp_thruster_frame ));
326
327
328         // Do for glows
329
330         if (model_afterburner) {
331                 the_anim = &Thrust_anims[THRUST_ANIM_GLOW_AFTERBURNER];
332                 rate = 1.2f;            // go at 1.2x faster when afterburners on
333         } else {
334                 the_anim = &Thrust_anims[THRUST_ANIM_GLOW_NORMAL];
335                 // If thrust at 0, go at half as fast, full thrust; full framerate
336                 // so set rate from 0.5 to 1.0, depending on thrust from 0 to 1
337                 rate = 0.5f + model_thrust / 2.0f;
338         }
339
340         shipp_thruster_glow_frame += frame_time * rate;
341
342         // Sanity checks
343         if ( shipp_thruster_glow_frame < 0.0f ) shipp_thruster_glow_frame = 0.0f;
344         if ( shipp_thruster_glow_frame > 100.0f ) shipp_thruster_glow_frame = 0.0f;
345
346         while (shipp_thruster_glow_frame > the_anim->time) {
347                 shipp_thruster_glow_frame -= the_anim->time;
348         }
349         framenum = fl2i( (shipp_thruster_glow_frame*the_anim->num_frames) / the_anim->time );
350         if ( framenum < 0 ) framenum = 0;
351         if ( framenum >= the_anim->num_frames ) framenum = the_anim->num_frames-1;
352
353         // Get the bitmap for this frame
354         shipp_thruster_glow_bitmap = the_anim->first_frame;
355         shipp_thruster_glow_noise = Noise[framenum];
356
357 //      mprintf(( "TF: %.2f\n", shipp_thruster_frame ));
358
359 }
360
361 void PofViewCanvas::MoveViewer(float frame_time)
362 {
363         int detail_lvl = -1;
364
365         if (in_dialog) {
366                 return;
367         }
368
369         if ( wxGetKeyState(wxKeyCode('1')) ) {
370                 detail_lvl = 1;
371         } else if ( wxGetKeyState(wxKeyCode('2')) ) {
372                 detail_lvl = 2;
373         } else if ( wxGetKeyState(wxKeyCode('3')) ) {
374                 detail_lvl = 3;
375         } else if ( wxGetKeyState(wxKeyCode('4')) ) {
376                 detail_lvl = 4;
377         } else if ( wxGetKeyState(wxKeyCode('5')) ) {
378                 detail_lvl = 5;
379         } else if ( wxGetKeyState(wxKeyCode('6')) ) {
380                 detail_lvl = 6;
381         }
382
383         if (detail_lvl >= 0) {
384                 ((PofViewFrame*)GetParent())->SetDetailLevel(detail_lvl);
385         }
386
387         if ( wxGetKeyState(wxKeyCode('-')) ) {
388                 // Scales the engines thrusters by this much
389                 model_thrust -= 0.1f;
390
391                 if (model_thrust < 0.0f) {
392                         model_thrust = 0.0f;
393                 }
394         } else if ( wxGetKeyState(wxKeyCode('=')) ) {
395                 // Scales the engines thrusters by this much
396                 model_thrust += 0.1f;
397
398                 if (model_thrust > 1.0f) {
399                         model_thrust = 1.0f;
400                 }
401         }
402
403         if ( wxGetKeyState(WXK_BACK) ) {
404                 model_afterburner = 1;
405         } else {
406                 model_afterburner = 0;
407         }
408
409         int model_num = ((PofViewFrame*)GetParent())->GetModelnum();
410
411         if (model_num < 0) {
412                 return;
413         }
414
415         polymodel *pm = model_get(model_num);
416         wxASSERT( pm );
417
418         control_info *ci = &m_Viewer_ci;
419         float kh = 0.0f;
420
421         float c_scale = pm->core_radius; //1.0f;
422
423 //      if (pm->core_radius < 200.0f) {
424 //              c_scale = 1.0f / 6.0f;
425 //      }
426
427         float temp = ci->heading;
428         float temp1 = ci->pitch;
429         memset( ci, 0, sizeof(control_info) );
430         ci->heading = temp;
431         ci->pitch = temp1;
432
433         if ( wxGetKeyState(WXK_NUMPAD6) ) {
434                 kh = frame_time;
435         } else if ( wxGetKeyState(WXK_NUMPAD4) ) {
436                 kh = -frame_time;
437         } else {
438                 kh = 0.0f;
439         }
440
441         if (kh == 0.0f) {
442                 ci->heading = 0.0f;
443         } else if (kh > 0.0f) {
444                 if (ci->heading < 0.0f) {
445                         ci->heading = 0.0f;
446                 }
447         } else { // kh < 0
448                 if (ci->heading > 0.0f) {
449                         ci->heading = 0.0f;
450                 }
451         }
452
453         ci->heading += kh;
454
455         if ( wxGetKeyState(WXK_NUMPAD8) ) {
456                 kh = frame_time;
457         } else if ( wxGetKeyState(WXK_NUMPAD2) ) {
458                 kh = -frame_time;
459         } else {
460                 kh = 0.0f;
461         }
462
463         if (kh == 0.0f){
464                 ci->pitch = 0.0f;
465         } else if (kh > 0.0f) {
466                 if (ci->pitch < 0.0f){
467                         ci->pitch = 0.0f;
468                 }
469         } else { // kh < 0
470                 if (ci->pitch > 0.0f){
471                         ci->pitch = 0.0f;
472                 }
473         }
474
475         ci->pitch += kh;
476
477         if ( wxGetKeyState(WXK_NUMPAD7) ) {
478                 ci->bank = frame_time / 8.0f;
479         } else if ( wxGetKeyState(WXK_NUMPAD9) ) {
480                 ci->bank = -frame_time / 8.0f;
481         }
482
483         if ( wxGetKeyState(wxKeyCode('A')) ) {
484                 ci->forward = frame_time * c_scale;
485         } else if ( wxGetKeyState(wxKeyCode('Z')) ) {
486                 ci->forward = -frame_time * c_scale;
487         }
488
489         if ( wxGetKeyState(WXK_NUMPAD3) ) {
490                 ci->sideways = frame_time * c_scale;
491         } else if ( wxGetKeyState(WXK_NUMPAD1) ) {
492                 ci->sideways = -frame_time * c_scale;
493         }
494
495         if ( wxGetKeyState(WXK_NUMPAD_SUBTRACT) ) {
496                 ci->vertical = frame_time * c_scale;
497         } else if ( wxGetKeyState(WXK_NUMPAD_ADD) ) {
498                 ci->vertical = -frame_time * c_scale;
499         }
500
501         physics_read_flying_controls( &m_ViewerOrient, &m_ViewerPhysics, &m_Viewer_ci, frame_time );
502
503         physics_sim(&m_ViewerPos, &m_ViewerOrient, &m_ViewerPhysics, frame_time * 6.0f );
504 }
505
506 void PofViewCanvas::OnPaint( wxPaintEvent& WXUNUSED(event) )
507 {
508         wxPaintDC dc(this);
509
510         Render();
511 }
512
513 void PofViewCanvas::OnSize(wxSizeEvent& WXUNUSED(event))
514 {
515         if ( !this->IsShownOnScreen() ) {
516                 return;
517         }
518
519         int x = 640, y = 480;
520
521         this->GetClientSize(&x, &y);
522
523         gr_set_viewport(x, y);
524 }
525
526 void PofViewCanvas::OnEraseBackground(wxEraseEvent& WXUNUSED(event))
527 {
528         // Do nothing, to avoid flashing on MSW
529 }
530
531 void PofViewCanvas::OnMouse(wxMouseEvent& event)
532 {
533         if ( event.Dragging() ) {
534                 if (m_mouse_inited) {
535                         m_mouse_dx = event.GetX() - m_mouse_x;
536                         m_mouse_dy = event.GetY() - m_mouse_y;
537                 } else {
538                         m_mouse_inited = 1;
539                 }
540
541                 m_mouse_x = event.GetX();
542                 m_mouse_y = event.GetY();
543
544                 matrix tempm, mousem;
545
546                 if ( m_mouse_dx || m_mouse_dy ) {
547                         vm_trackball( -m_mouse_dx, m_mouse_dy, &mousem );
548                         vm_matrix_x_matrix(&tempm, &m_ObjectOrient, &mousem);
549                         m_ObjectOrient = tempm;
550
551                         m_mouse_dx = m_mouse_dy = 0;
552                 }
553         } else {
554                 m_mouse_inited = 0;
555         }
556 }
557
558 // loads the animations for ship's afterburners
559 void PofViewCanvas::InitThrusters()
560 {
561         int                     fps, i;
562         thrust_anim     *ta;
563
564         if (thrust_anim_inited)
565                 return;
566
567         for ( i = 0; i < NUM_THRUST_ANIMS; i++ ) {
568                 ta = &Thrust_anims[i];
569
570                 // two anims
571                 if (i < THRUST_ANIM_GLOW_NORMAL) {
572                         ta->first_frame = bm_load_animation(Thrust_anim_names[i],  &ta->num_frames, &fps, 1);
573                         if ( ta->first_frame == -1 ) {
574                                 Error(LOCATION,"Error loading animation file: %s\n",Thrust_anim_names[i]);
575                                 return;
576                         }
577                         SDL_assert(fps != 0);
578                         ta->time = i2fl(ta->num_frames)/fps;
579                 }
580                 // two glow bitmaps
581                 else {
582                         ta->num_frames = NOISE_NUM_FRAMES;
583                         fps = 15;
584                         ta->first_frame = bm_load( Thrust_anim_names[i] );
585                         if ( ta->first_frame == -1 ) {
586                                 Error(LOCATION,"Error loading bitmap file: %s\n",Thrust_anim_names[i]);
587                                 return;
588                         }
589                         SDL_assert(fps != 0);
590                         ta->time = i2fl(ta->num_frames)/fps;
591                 }
592         }
593
594         thrust_anim_inited = true;
595 }