]> icculus.org git repositories - taylor/freespace2.git/blob - src/pofview/pofviewcanvas.cpp
fixes for demo upsells
[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
417         if (pm == NULL) {
418                 return;
419         }
420
421         control_info *ci = &m_Viewer_ci;
422         float kh = 0.0f;
423
424         float c_scale = pm->core_radius; //1.0f;
425
426 //      if (pm->core_radius < 200.0f) {
427 //              c_scale = 1.0f / 6.0f;
428 //      }
429
430         float temp = ci->heading;
431         float temp1 = ci->pitch;
432         memset( ci, 0, sizeof(control_info) );
433         ci->heading = temp;
434         ci->pitch = temp1;
435
436         if ( wxGetKeyState(WXK_NUMPAD6) ) {
437                 kh = frame_time;
438         } else if ( wxGetKeyState(WXK_NUMPAD4) ) {
439                 kh = -frame_time;
440         } else {
441                 kh = 0.0f;
442         }
443
444         if (kh == 0.0f) {
445                 ci->heading = 0.0f;
446         } else if (kh > 0.0f) {
447                 if (ci->heading < 0.0f) {
448                         ci->heading = 0.0f;
449                 }
450         } else { // kh < 0
451                 if (ci->heading > 0.0f) {
452                         ci->heading = 0.0f;
453                 }
454         }
455
456         ci->heading += kh;
457
458         if ( wxGetKeyState(WXK_NUMPAD8) ) {
459                 kh = frame_time;
460         } else if ( wxGetKeyState(WXK_NUMPAD2) ) {
461                 kh = -frame_time;
462         } else {
463                 kh = 0.0f;
464         }
465
466         if (kh == 0.0f){
467                 ci->pitch = 0.0f;
468         } else if (kh > 0.0f) {
469                 if (ci->pitch < 0.0f){
470                         ci->pitch = 0.0f;
471                 }
472         } else { // kh < 0
473                 if (ci->pitch > 0.0f){
474                         ci->pitch = 0.0f;
475                 }
476         }
477
478         ci->pitch += kh;
479
480         if ( wxGetKeyState(WXK_NUMPAD7) ) {
481                 ci->bank = frame_time / 8.0f;
482         } else if ( wxGetKeyState(WXK_NUMPAD9) ) {
483                 ci->bank = -frame_time / 8.0f;
484         }
485
486         if ( wxGetKeyState(wxKeyCode('A')) ) {
487                 ci->forward = frame_time * c_scale;
488         } else if ( wxGetKeyState(wxKeyCode('Z')) ) {
489                 ci->forward = -frame_time * c_scale;
490         }
491
492         if ( wxGetKeyState(WXK_NUMPAD3) ) {
493                 ci->sideways = frame_time * c_scale;
494         } else if ( wxGetKeyState(WXK_NUMPAD1) ) {
495                 ci->sideways = -frame_time * c_scale;
496         }
497
498         if ( wxGetKeyState(WXK_NUMPAD_SUBTRACT) ) {
499                 ci->vertical = frame_time * c_scale;
500         } else if ( wxGetKeyState(WXK_NUMPAD_ADD) ) {
501                 ci->vertical = -frame_time * c_scale;
502         }
503
504         physics_read_flying_controls( &m_ViewerOrient, &m_ViewerPhysics, &m_Viewer_ci, frame_time );
505
506         physics_sim(&m_ViewerPos, &m_ViewerOrient, &m_ViewerPhysics, frame_time * 6.0f );
507 }
508
509 void PofViewCanvas::OnPaint( wxPaintEvent& WXUNUSED(event) )
510 {
511         wxPaintDC dc(this);
512
513         Render();
514 }
515
516 void PofViewCanvas::OnSize(wxSizeEvent& WXUNUSED(event))
517 {
518         if ( !this->IsShownOnScreen() ) {
519                 return;
520         }
521
522         int x = 640, y = 480;
523
524         this->GetClientSize(&x, &y);
525
526         gr_set_viewport(x, y);
527 }
528
529 void PofViewCanvas::OnEraseBackground(wxEraseEvent& WXUNUSED(event))
530 {
531         // Do nothing, to avoid flashing on MSW
532 }
533
534 void PofViewCanvas::OnMouse(wxMouseEvent& event)
535 {
536         if ( event.Dragging() ) {
537                 if (m_mouse_inited) {
538                         m_mouse_dx = event.GetX() - m_mouse_x;
539                         m_mouse_dy = event.GetY() - m_mouse_y;
540                 } else {
541                         m_mouse_inited = 1;
542                 }
543
544                 m_mouse_x = event.GetX();
545                 m_mouse_y = event.GetY();
546
547                 matrix tempm, mousem;
548
549                 if ( m_mouse_dx || m_mouse_dy ) {
550                         vm_trackball( -m_mouse_dx, m_mouse_dy, &mousem );
551                         vm_matrix_x_matrix(&tempm, &m_ObjectOrient, &mousem);
552                         m_ObjectOrient = tempm;
553
554                         m_mouse_dx = m_mouse_dy = 0;
555                 }
556         } else {
557                 m_mouse_inited = 0;
558         }
559 }
560
561 // loads the animations for ship's afterburners
562 void PofViewCanvas::InitThrusters()
563 {
564         int                     fps, i;
565         thrust_anim     *ta;
566
567         if (thrust_anim_inited)
568                 return;
569
570         for ( i = 0; i < NUM_THRUST_ANIMS; i++ ) {
571                 ta = &Thrust_anims[i];
572
573                 // two anims
574                 if (i < THRUST_ANIM_GLOW_NORMAL) {
575                         ta->first_frame = bm_load_animation(Thrust_anim_names[i],  &ta->num_frames, &fps, 1);
576                         if ( ta->first_frame == -1 ) {
577                                 Error(LOCATION,"Error loading animation file: %s\n",Thrust_anim_names[i]);
578                                 return;
579                         }
580                         SDL_assert(fps != 0);
581                         ta->time = i2fl(ta->num_frames)/fps;
582                 }
583                 // two glow bitmaps
584                 else {
585                         ta->num_frames = NOISE_NUM_FRAMES;
586                         fps = 15;
587                         ta->first_frame = bm_load( Thrust_anim_names[i] );
588                         if ( ta->first_frame == -1 ) {
589                                 Error(LOCATION,"Error loading bitmap file: %s\n",Thrust_anim_names[i]);
590                                 return;
591                         }
592                         SDL_assert(fps != 0);
593                         ta->time = i2fl(ta->num_frames)/fps;
594                 }
595         }
596
597         thrust_anim_inited = true;
598 }