]> icculus.org git repositories - taylor/freespace2.git/blob - src/nebedit/nebedit.cpp
fix issue with looping audio streams
[taylor/freespace2.git] / src / nebedit / nebedit.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 /*
10  * $Logfile: /Freespace2/code/nebedit/NebEdit.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * Program to edit nebulas in 2d
16  *
17  * $Log$
18  * Revision 1.3  2002/06/09 04:41:23  relnev
19  * added copyright header
20  *
21  * Revision 1.2  2002/05/07 03:16:47  theoddone33
22  * The Great Newline Fix
23  *
24  * Revision 1.1.1.1  2002/05/03 03:28:10  root
25  * Initial import.
26  *
27  * 
28  * 7     7/15/99 3:07p Dave
29  * 32 bit detection support. Mouse coord commandline.
30  * 
31  * 6     5/19/99 4:07p Dave
32  * Moved versioning code into a nice isolated common place. Fixed up
33  * updating code on the pxo screen. Fixed several stub problems.
34  * 
35  * 5     1/08/99 2:06p Dave
36  * Fixed pfoview for software mode.
37  * 
38  * 4     12/18/98 1:14a Dave
39  * Rough 1024x768 support for Direct3D. Proper detection and usage through
40  * the launcher.
41  * 
42  * 3     11/13/98 2:32p Dave
43  * Improved commandline parsing for exe pathname.
44  * 
45  * 2     10/24/98 9:51p Dave
46  * 
47  * 1     10/24/98 9:39p Dave
48  * 
49  * 13    4/13/98 10:11a John
50  * Made timer functions thread safe.  Made timer_init be called in all
51  * projects.
52  * 
53  * 12    3/23/98 1:35p Sandeep
54  * 
55  * 11    3/05/98 11:15p Hoffoss
56  * Changed non-game key checking to use game_check_key() instead of
57  * game_poll().
58  * 
59  * 10    12/29/97 5:10p Allender
60  * fixed problems with speed not being reported properly in multiplayer
61  * games.  Made read_flying_controls take frametime as a parameter.  More
62  * ship/weapon select stuff
63  * 
64  * 9     12/04/97 3:47p John
65  * Made joystick move mouse cursor
66  * 
67  * 8     11/21/97 11:32a John
68  * Added nebulas.   Fixed some warpout bugs.
69  * 
70  * 7     11/19/97 10:15p Adam
71  * upped maxtris to 200
72  * 
73  * 6     11/19/97 4:28p Sandeep
74  * added poly/vert counter
75  * 
76  * 5     11/19/97 1:59p Sandeep
77  * Added multiple vertex editing mode
78  * 
79  * 4     11/16/97 2:29p John
80  * added versioning to nebulas; put nebula code into freespace.
81  * 
82  * 3     11/13/97 12:04p Sandeep
83  * Added face editing support, deletion support, and a saving and loading
84  * stuff.
85  * 
86  * 2     11/10/97 9:59p John
87  * some tweaking
88  * 
89  * 1     11/10/97 9:42p John
90  *
91  * $NoKeywords: $
92  */
93
94
95 #include "wx/wxprec.h"
96
97 #ifndef WX_PRECOMP
98 #include "wx/wx.h"
99 #endif
100
101 #include "wx/filedlg.h"
102
103 #include "pstypes.h"
104 #include "2d.h"
105 #include "3d.h"
106 #include "key.h"
107 #include "palman.h"
108 #include "bmpman.h"
109 #include "timer.h"
110 #include "floating.h"
111 #include "osapi.h"
112 #include "cfile.h"
113 #include "linklist.h"
114 #include "lighting.h"
115 #include "mouse.h"
116 #include "vecmat.h"
117 #include "physics.h"
118 #include "model.h"
119 #include "font.h"
120 #include "cmdline.h"
121 #include "cfilesystem.h"
122
123
124 #define SCREEN_W        640     
125 #define SCREEN_H        480
126
127 vector ViewerPos;
128 matrix ViewerOrient;
129 matrix ModelOrient;
130 vector ModelPos;
131 physics_info ViewerPhysics;
132 float ViewerZoom = 1.0f;
133
134 int test_model = -1;
135 int Fred_running = 0;
136 int Pofview_running = 0;
137 int Fonttool_running = 0;
138 float flFrametime = 0.0f;
139
140 int Font1 = -1;
141
142 color color_green;
143
144 vector Global_light_world = { { { 0.208758f, -0.688253f, -0.694782f } } };
145
146 // nebula stuff
147
148 #define NEB_W 6
149 #define NEB_H 6
150 #define MAX_TRIS 200
151 #define MAX_POINTS 300
152
153 int neb_w = 0, neb_h = 0;
154
155 int nebula_inited = 0;
156 int num_pts = 0;
157
158 static int x[MAX_POINTS], y[MAX_POINTS], l[MAX_POINTS];
159 float scale_factor = 1.0f;
160
161 int num_tris = 0;
162 int tri[MAX_TRIS][3];
163
164 color nebula_color;
165
166 int Mouse_x, Mouse_y;
167 int Current_point;
168 bool Selected[MAX_POINTS];
169 bool Sel_mode = false;   // false = 1 point at a time, true = select multiple points
170 int Current_face;
171
172 int View_mode = 0;      // 0 = 2d editor, 1 = 3d viewer
173
174 int Vert_mode = 0;   // 0 = Move vertices/Add vertices, 2 = Move face/Add face
175
176 int Which_vert = 0;  // Current vertex of the faceadd
177
178 int Orig_pos_x;
179 int Orig_pos_y;
180 int End_pos_x;
181 int End_pos_y;
182 bool Draw_sel_box = false;
183
184 int Neb_created = 0;
185
186 int Nebedit_running = 1;
187
188 extern void project_2d_onto_sphere(vector *, float, float);
189
190 class NebeditApp: public wxApp
191 {
192 public:
193         virtual bool OnInit();
194 };
195
196 bool NebeditApp::OnInit()
197 {
198         return false;
199 }
200
201
202 void create_default_neb()
203 {
204         int i,j;
205         neb_w = NEB_W;
206         neb_h = NEB_H;
207         num_pts = neb_w*neb_h;
208
209         for (j=0; j<neb_h; j++ )        {
210                 for (i=0; i<neb_w; i++ )        {
211                         x[i+j*neb_w] = ((i+1)*SCREEN_W)/(neb_w+2);
212                         y[i+j*neb_w] = ((j+3)*SCREEN_H)/(neb_h+6);
213                         if ( (j==0) || (j==neb_h-1))    {
214                                 l[i+j*neb_w] = 0;
215                         } else {
216                                 l[i+j*neb_w] = 31;
217                         }
218                 }
219         }
220
221         num_tris = 0;
222
223         for (j=0; j<neb_h-1; j++ )      {
224                 for (i=0; i<neb_w-1; i++ )      {
225                         tri[num_tris][0] = i+neb_w*j;
226                         tri[num_tris][1] = i+neb_w*j+1;
227                         tri[num_tris][2] = i+neb_w*(j+1)+1;
228                         num_tris++;
229
230                         tri[num_tris][0] = i+neb_w*j;
231                         tri[num_tris][1] = i+neb_w*(j+1)+1;
232                         tri[num_tris][2] = i+neb_w*(j+1);
233                         num_tris++;
234                 }
235         }
236
237         Neb_created = 1;
238 }
239
240 #define NEBULA_FILE_ID "NEBU"                   
241 #define NEBULA_MAJOR_VERSION 1          // Can be 1-?
242 #define NEBULA_MINOR_VERSION 0          // Can be 0-99
243
244 void save_nebula_sub(const char *filename)
245 {
246         CFILE *fp;
247         float xf, yf;
248         int version;
249         int i;
250
251         fp = cfopen(filename, "wb");
252
253         if ( !fp )      {
254                 return;
255         }
256
257         // ID of NEBU
258         cfwrite( "NEBU", 4, 1, fp );
259         version = NEBULA_MAJOR_VERSION*100+NEBULA_MINOR_VERSION;
260         cfwrite_int(version, fp);
261         cfwrite_int(num_pts, fp);
262         cfwrite_int(num_tris, fp);
263
264         for (i=0; i<num_pts; i++ )      {
265                 xf = INTEL_FLOAT(float(x[i])/640.0f);
266                 yf = INTEL_FLOAT(float(y[i])/480.0f);
267                 cfwrite_float(xf, fp);
268                 cfwrite_float(yf, fp);
269                 cfwrite_int(l[i], fp);
270         }
271
272         for (i=0; i<num_tris; i++ )     {
273                 cfwrite_int(tri[i][0], fp);
274                 cfwrite_int(tri[i][1], fp);
275                 cfwrite_int(tri[i][2], fp);
276         }
277
278         cfclose(fp);
279 }
280
281 // returns 0 if failed
282 int load_nebula_sub(const char *filename)
283 {
284         CFILE *fp;
285         char id[16];
286         int version, major, minor;
287
288         fp = cfopen(filename, "rb");
289
290         if ( !fp )      {
291                 return 0;
292         }
293
294         // ID of NEBU
295         cfread( id, 4, 1, fp );
296         if ( strncmp( id, NEBULA_FILE_ID, 4))   {
297                 mprintf(( "Not a valid nebula file.\n" ));
298                 return 0;
299         }
300
301         version = cfread_int(fp);
302         major = version / 100;
303         minor = version % 100;
304
305         if ( (major != NEBULA_MAJOR_VERSION) && (minor != NEBULA_MINOR_VERSION) ) {
306                 mprintf(( "An out of date nebula file.\n" ));
307                 return 0;
308         }
309
310         num_pts = cfread_int(fp);
311         SDL_assert( num_pts < MAX_POINTS );
312         num_tris = cfread_int(fp);
313         SDL_assert( num_tris < MAX_TRIS );
314
315         for (int i=0; i<num_pts; i++ )  {
316                 x[i] = fl2i(cfread_float(fp) * 640.0f);
317                 y[i] = fl2i(cfread_float(fp) * 480.0f);
318                 l[i] = cfread_int(fp);
319         }
320
321         for (int i=0; i<num_tris; i++ ) {
322                 tri[i][0] = cfread_int(fp);
323                 tri[i][1] = cfread_int(fp);
324                 tri[i][2] = cfread_int(fp);
325         }
326
327         cfclose(fp);
328
329         return 1;
330 }
331
332 void nebedit_close()
333 {
334         char a_path[MAX_PATH_LEN];
335
336         cf_create_default_path_string(a_path, CF_TYPE_CACHE, "autosaved.neb");
337
338         save_nebula_sub( a_path );
339 }
340
341 void save_nebula()
342 {
343         wxFileDialog saveFileDialog(NULL, _("Save Nebula File"), wxEmptyString,
344                                                                 wxEmptyString, _("Nebula Files (*.neb)|*.neb"),
345                                                                 wxFD_SAVE|wxFD_OVERWRITE_PROMPT);
346
347         if (saveFileDialog.ShowModal() == wxID_OK) {
348                 save_nebula_sub(saveFileDialog.GetPath().ToAscii());
349         }
350 }
351
352 void load_nebula()
353 {
354         int create_default = 1;
355
356         wxFileDialog openFileDialog(NULL, _("Open Nebula File"), wxEmptyString,
357                                                                 wxEmptyString, _("Nebula Files (*.neb)|*.neb"),
358                                                                 wxFD_OPEN|wxFD_FILE_MUST_EXIST);
359
360         if (openFileDialog.ShowModal() == wxID_OK) {
361                 create_default = !load_nebula_sub(openFileDialog.GetPath().ToAscii());
362         }
363
364         if ( create_default )   {
365                 create_default_neb();
366         }
367
368         Neb_created = 1;
369 }
370
371 void nebula_init()
372 {
373         if ( nebula_inited ) return;
374         memset(Selected, 0, sizeof(bool)*MAX_POINTS);
375         nebula_inited++;
376
377         create_default_neb();   
378         gr_init_alphacolor( &nebula_color, 0, 255, 0, 255, AC_TYPE_HUD );
379
380         return;
381 }
382
383 void draw_tri_2d( int i, int j, int k )
384 {
385         int index[3];
386
387         index[0] = i;
388         index[1] = j;
389         index[2] = k;
390
391         vertex va, vb, vc;
392         vertex * verts[3] = { &va, &vb, &vc };
393 //      gr_zbuffering = 0;
394         for (int v=0; v<3; v++ )        {
395                 verts[v]->sx = i2fl(x[index[v]]);   
396                 verts[v]->sy = i2fl(y[index[v]]);
397                 verts[v]->u = 0.0f;
398                 verts[v]->v = 0.0f;
399                 verts[v]->sw = 1.0f; 
400                 verts[v]->b = (ubyte)(i2fl(l[index[v]]*255)/31.0f);
401         }
402
403 //      gr_set_color( 0, 0, 0 );
404         gr_tmapper(3, verts, TMAP_FLAG_RAMP | TMAP_FLAG_GOURAUD | TMAP_FLAG_NEBULA );
405
406         if ( !key_pressed(SDLK_LSHIFT) )        {
407                 gr_set_color(100,100,100);
408                 gr_line( x[i], y[i], x[j], y[j] );
409                 gr_line( x[j], y[j], x[k], y[k] );
410                 gr_line( x[k], y[k], x[i], y[i] );
411         }
412 }
413
414 void nebula_draw_2d()
415 {
416         int i;
417         
418         for (i=0; i<num_tris; i++ )     {
419                 draw_tri_2d( tri[i][0], tri[i][1], tri[i][2] );
420         }               
421
422                 gr_set_color(100,0,0);
423                 for (i=0; i<num_pts; i++ )      {
424                         gr_circle( x[i], y[i], 4 );
425                 }
426                 if (Sel_mode == 1) { // multiple selection
427                         if (Draw_sel_box) {
428                                 gr_set_color(200,0,200);
429                                 gr_line(Orig_pos_x, Orig_pos_y, Orig_pos_x, End_pos_y);
430                                 gr_line(Orig_pos_x, End_pos_y, End_pos_x, End_pos_y);
431                                 gr_line(End_pos_x, Orig_pos_y, End_pos_x, End_pos_y);
432                                 gr_line(End_pos_x, Orig_pos_y, Orig_pos_x, Orig_pos_y);
433                         } else {
434                                 gr_set_color(0,100,0);
435                                 for (i=0;i<num_pts;i++)
436                                         if (Selected[i]) gr_circle( x[i], y[i], 5);
437                         }
438                 } else if ((Vert_mode==0)&&(Current_point>-1)) {
439                         gr_set_color(0,100,0);
440                         gr_circle( x[Current_point], y[Current_point], 5);
441                 } else if (Vert_mode == 1) {
442                         for (i=0;i<Which_vert;i++) {
443                                 gr_set_color(0,0,100);
444                                 gr_circle( x[tri[num_tris][i]], y[tri[num_tris][i]], 6);
445                         }
446                         gr_set_color(200,200,0);
447                         if (Current_face>-1) {
448                                 gr_line(x[tri[Current_face][0]], y[tri[Current_face][0]], 
449                                                 x[tri[Current_face][1]], y[tri[Current_face][1]]);
450                                 gr_line(x[tri[Current_face][1]], y[tri[Current_face][1]], 
451                                                 x[tri[Current_face][2]], y[tri[Current_face][2]]);
452                                 gr_line(x[tri[Current_face][2]], y[tri[Current_face][2]], 
453                                                 x[tri[Current_face][0]], y[tri[Current_face][0]]);
454                         }
455                 }
456 }
457
458
459 void draw_tri_3d( int i, int j, int k )
460 {
461         int index[3];
462
463         index[2] = k;
464         index[1] = j;
465         index[0] = i;
466
467         vertex va, vb, vc;
468         vertex * verts[3] = { &va, &vb, &vc };
469         //gr_zbuffering = 0;
470         for (int v=0; v<3; v++ )        {
471                 vector tmp;
472                 
473                 project_2d_onto_sphere( &tmp, 1.0f - i2fl(x[index[v]])/640.0f, i2fl(y[index[v]])/480.0f );
474         
475                 vm_vec_scale( &tmp, 10.0f );
476
477                 g3_rotate_faraway_vertex( verts[v], &tmp );
478                 //g3_rotate_vertex( verts[v], &tmp );
479                 g3_project_vertex( verts[v] );
480
481                 verts[v]->b = (ubyte)(i2fl(l[index[v]]*255)/31.0f);
482         }
483
484         //gr_zbuffering = 0;
485         //gr_set_color_fast( &nebula_color );
486         //gr_set_color( 0, 0, 0 );
487         g3_draw_poly(3, verts, TMAP_FLAG_RAMP | TMAP_FLAG_GOURAUD | TMAP_FLAG_NEBULA );
488 }
489
490 void nebula_draw_3d()
491 {
492         int i;
493         for (i=0; i<num_tris; i++ )     {
494                 draw_tri_3d( tri[i][0], tri[i][1], tri[i][2] );
495         }               
496 }
497
498 void render_frame()
499 {
500         gr_reset_clip();
501
502         gr_set_color(0,0,0);            // set color to black
503         gr_rect(0,0,SCREEN_W,SCREEN_H); // clear screen
504
505         light_reset();
506         light_add_directional( &Global_light_world, 0.1f, 1.0f, 1.0f, 1.0f );
507
508         g3_start_frame(1);
509
510         g3_set_view_matrix(&ViewerPos, &ViewerOrient,ViewerZoom);
511
512         if ( View_mode == 0 )   {
513                 nebula_draw_2d();
514
515                 gr_set_font(Font1);
516                 gr_set_color_fast( &color_green );
517                 gr_printf(10,10,"Nebula Editor. Mode :");
518                 if (Sel_mode ==1) {
519                                 gr_printf(180, 10, "Multiple Vertex Selection Editing");
520                 } else if (Vert_mode ==0 ) {
521                         gr_printf(180,10,"Vertex Editing");
522                         if(Current_point >= 0){
523                                 gr_printf(180, 20, "Current vertex intensity : %d\n", l[Current_point]);
524                         }
525                 } else if (Vert_mode ==1) {
526                         gr_printf(180,10,"Face Editing");
527                 }
528                 char blah[255];
529                 gr_printf(20,30,"# Points:");
530                 gr_printf(100,30, SDL_itoa(num_pts, blah, 10));
531                 gr_printf(220,30,"# Polys:");
532                 gr_printf(300,30, SDL_itoa(num_tris, blah, 10));
533         } else {
534                 nebula_draw_3d();
535                 model_render( test_model, &ModelOrient, &ModelPos );
536         }
537
538         g3_end_frame();
539
540         gr_flip();
541 }
542
543 int get_closest(int mx, int my)
544 {
545         int i, closest = -1, cval = 100000;
546
547         for (i=0; i<num_pts; i++ )      {
548                 int dist;
549                 int dx, dy;
550                 
551                 dx = x[i] - mx;
552                 dy = y[i] - my;
553                 
554                 dist = fl2i(fl_sqrt( i2fl((dx*dx)+(dy*dy)) ));
555
556                 if ( dist < cval )      {
557                         cval = dist;
558                         closest = i;
559                 }
560         }
561
562         return closest;
563 }
564
565 int get_closest_face(int mx, int my)
566 {
567         int i, closest = -1, cval = 100000;
568
569         for (i=0; i<num_tris; i++ )     {
570                 int dist;
571                 int dx, dy;
572                 
573                 dx = x[tri[i][0]] - mx;
574                 dy = y[tri[i][0]] - my;
575
576                 dx += x[tri[i][1]] - mx;
577                 dy += y[tri[i][1]] - my;
578                 
579                 dx += x[tri[i][2]] - mx;
580                 dy += y[tri[i][2]] - my;
581
582                 dist = fl2i(fl_sqrt( i2fl((dx*dx)+(dy*dy)) ));
583 /*
584                 dist += fl2i(fl_sqrt( i2fl((dx*dx)+(dy*dy)) ));
585
586                 dx = x[tri[i][2]] - mx;
587                 dy = y[tri[i][2]] - my;
588                 dist += fl2i(fl_sqrt( i2fl((dx*dx)+(dy*dy)) ));
589 */
590
591                 if ( dist < cval )      {
592                         cval = dist;
593                         closest = i;
594                 }
595         }
596
597         return closest;
598 }
599
600 void delete_face(int i)
601 {
602         for (int j=i;j<num_tris;j++) {
603                 memcpy(tri[j], tri[j+1], sizeof(int)*3);
604         }
605         num_tris--;
606 }
607
608 void delete_vert(int i)
609 {
610         int j;
611
612         for (j=0;j<num_tris;j++) {
613                 if ((tri[j][0]==i)||(tri[j][1]==i)||(tri[j][2]==i)) {
614                         delete_face(j);
615                         j=0;
616                 }
617         }
618         for (j=0;j<num_tris;j++) {
619                 if (tri[j][0]>i) tri[j][0]--;
620                 if (tri[j][1]>i) tri[j][1]--;
621                 if (tri[j][2]>i) tri[j][2]--;
622         }
623         for (j=i;j<num_pts;j++) {
624                 x[j] = x[j+1];
625                 y[j] = y[j+1];
626                 l[j] = l[j+1];
627         }
628         num_pts--;
629 }
630
631 int add_vert(int mx, int my)
632 {
633         SDL_assert(num_pts<300);
634         x[num_pts] = mx;
635         y[num_pts] = my;
636         l[num_pts] = 0;
637         num_pts++;
638         return num_pts-1;
639 }
640
641 void select_by_box(int x1, int y1, int x2, int y2)
642 {
643         if (x1>x2) {
644                 int temp = x1;
645                 x1 = x2;
646                 x2 = temp;
647         }
648         if (y1>y2) {
649                 int temp = y1;
650                 y1 = y2;
651                 y2 = temp;
652         }
653         for (int i=0;i<num_pts;i++) {
654                 if ((x[i]<=x2) && (x[i]>=x1) &&
655                          (y[i]<=y2) && (y[i]>=y1)) {
656                         Selected[i] = true;
657                 }
658         }
659 }
660
661 void sphericalize_nebula()
662 {
663         int idx1, idx2;
664         int px = SCREEN_W / (neb_w - 1);
665         int py = SCREEN_H / (neb_h - 1);
666
667         // flatten out the nebula so that it covers the entire sphere evenly
668         for(idx1=0; idx1<neb_w; idx1++){
669                 for(idx2=0; idx2<neb_h; idx2++){
670                         x[idx1+idx2*neb_w] = px * idx1;
671                         y[idx1+idx2*neb_w] = py * idx2;
672                 }
673         }
674 }
675
676 void controls_read_all(control_info * ci, float sim_time )
677 {
678         float kh;
679
680         {
681                 float temp = ci->heading;
682                 float temp1 = ci->pitch;
683                 memset( ci, 0, sizeof(control_info) );
684                 ci->heading = temp;
685                 ci->pitch = temp1;
686         }
687
688         // From keyboard...
689         kh = (key_down_timef(SDLK_KP_6) - key_down_timef(SDLK_KP_4))/8.0f;
690         if (kh == 0.0f)
691                 ci->heading = 0.0f;
692         else if (kh > 0.0f) {
693                 if (ci->heading < 0.0f)
694                         ci->heading = 0.0f;
695         } else // kh < 0
696                 if (ci->heading > 0.0f)
697                         ci->heading = 0.0f;
698         ci->heading += kh;
699
700         kh = (key_down_timef(SDLK_KP_8) - key_down_timef(SDLK_KP_2))/8.0f;
701         if (kh == 0.0f)
702                 ci->pitch = 0.0f;
703         else if (kh > 0.0f) {
704                 if (ci->pitch < 0.0f)
705                         ci->pitch = 0.0f;
706         } else // kh < 0
707                 if (ci->pitch > 0.0f)
708                         ci->pitch = 0.0f;
709         ci->pitch += kh;
710
711         ci->bank = (key_down_timef(SDLK_KP_7) - key_down_timef(SDLK_KP_9))*.75f;
712         ci->forward = key_down_timef(SDLK_a) - key_down_timef(SDLK_z);
713         ci->sideways = key_down_timef(SDLK_KP_3) - key_down_timef(SDLK_KP_1);
714         ci->vertical = key_down_timef(SDLK_KP_PLUS) - key_down_timef(SDLK_KP_ENTER);
715 }
716
717 int check_keys()
718 {
719         int k;
720
721         while( (k = key_inkey()) != 0 ) {
722 //mprintf(( "Key = %x\n", k ));
723                 if ( k == SDLK_ESCAPE ) {
724                         return 1;
725                 }
726
727                 switch( k )     {
728                 case SDLK_RETURN:
729                         Sel_mode = false;
730                         Vert_mode = !Vert_mode;
731                         Which_vert = 0;
732                         break;
733
734                 case SDLK_DELETE:
735                         if (Sel_mode) break;
736                         if (Vert_mode==1) delete_face(Current_face);
737                         else if (Vert_mode==0) {
738                                 delete_vert(Current_point);
739                         }
740                         break;
741
742                 case SDLK_MINUS:
743                         scale_factor -= 0.05f;
744                         mprintf(( "Scale = %.1f\n", scale_factor ));
745                         break;
746
747
748                 case SDLK_EQUALS:
749                         scale_factor += 0.05f;
750                         mprintf(( "Scale = %.1f\n", scale_factor ));
751                         break;
752
753                 case SDLK_INSERT:
754                         Sel_mode = !Sel_mode;
755                         break;
756
757                 case SDLK_SPACE:
758                         View_mode = !View_mode;
759                         break;
760
761                 case SDLK_COMMA:
762                         if (Sel_mode) {
763                                 int i;
764                                 for (i=0;i<num_pts;i++) if (Selected[i]) {
765                                         if ( l[i] > 0 ) {
766                                                 l[i]--;
767                                         }
768                                 }
769                         } else if (Vert_mode==0) {
770                                 if ( Current_point > -1 )       {
771                                         if ( l[Current_point] > 0 )     {
772                                                 l[Current_point]--;
773                                         }
774                                 }
775                         } else if (Vert_mode ==1) {
776                                 if ( l[tri[Current_face][0]] > 0 )      {
777                                                 l[tri[Current_face][0]]--;
778                                         }
779                                 if ( l[tri[Current_face][1]] > 0 )      {
780                                                 l[tri[Current_face][1]]--;
781                                         }
782                                 if ( l[tri[Current_face][2]] > 0 )      {
783                                                 l[tri[Current_face][2]]--;
784                                         }
785                         }
786                         break;
787
788                 case SDLK_PERIOD:
789                         if (Sel_mode) {
790                                 int i;
791                                 for (i=0;i<num_pts;i++) if (Selected[i]) {
792                                         if ( l[i] < 31 )        {
793                                                 l[i]++;
794                                         }
795                                 }
796                         } else if (Vert_mode==0) {
797                                 if ( Current_point > -1 )       {
798                                         if ( l[Current_point] < 31 )    {
799                                                 l[Current_point]++;
800                                         }
801                                 }
802                         } else if (Vert_mode ==1) {
803                                 if ( l[tri[Current_face][0]] <31 )      {
804                                                 l[tri[Current_face][0]]++;
805                                         }
806                                 if ( l[tri[Current_face][1]] <31)       {
807                                                 l[tri[Current_face][1]]++;
808                                         }
809                                 if ( l[tri[Current_face][2]] <31 )      {
810                                                 l[tri[Current_face][2]]++;
811                                         }
812                         }
813                         
814                         break;          
815
816                 case SDLK_F5:
817                         save_nebula();
818                         break;
819                 case SDLK_F7:
820                         load_nebula();
821                         break;
822
823                 case SDLK_BACKSPACE:
824                         sphericalize_nebula();
825                         break;
826                 }
827         }
828         return 0;
829 }
830
831 void os_close()
832 {
833         exit(1);
834 }
835
836 int newtri[3];
837
838 bool mdflag = false;
839
840 extern "C"
841 int main(int argc, char *argv[])
842 {
843         int i;
844         fix t1, t2;
845         control_info ci;
846         float speed = 20.0f;            // how fast viewer moves        
847
848         // setup the fred exe directory so CFILE can init properly
849         /*
850         char *c = GetCommandLine();
851         SDL_assert(c != NULL);
852         char *tok = strtok(c, " ");
853         SDL_assert(tok != NULL);        
854         */
855
856         Cmdline_window = 1; // always windowed
857
858         timer_init();
859         // cfile_init(tok);
860         cfile_init();
861         os_init( "NebEdit", "NebEdit" );        //SCREEN_W, SCREEN_H );
862         os_set_title("NebEdit");
863         gr_init();
864         palette_load_table( "gamepalette1-01.pcx" );
865         key_init();
866         mouse_init();
867         SDL_ShowCursor(1);
868         Font1 = gr_init_font( "font01.vf" );
869         gr_init_alphacolor( &color_green, 0,255,0,255,AC_TYPE_HUD );
870
871         test_model = model_load( "fighter01.pof", 0, NULL );
872
873         physics_init( &ViewerPhysics );
874         ViewerPhysics.flags |= PF_ACCELERATES | PF_SLIDE_ENABLED;
875
876         ViewerPhysics.max_vel.xyz.x = 2.0f*speed;               //sideways
877         ViewerPhysics.max_vel.xyz.y = 2.0f*speed;               //up/down
878         ViewerPhysics.max_vel.xyz.z = 2.0f*speed;               //forward
879         ViewerPhysics.max_rear_vel = 2.0f*speed;        //backward -- controlled seperately
880         
881         memset( &ci, 0, sizeof(control_info) );
882
883         ModelOrient = vmd_identity_matrix;
884         ModelPos.xyz.x=0.0f; ModelPos.xyz.y = 0.0f; ModelPos.xyz.z = 0.0f;
885
886         ViewerOrient = vmd_identity_matrix;
887         ViewerPos.xyz.x=0.0f; ViewerPos.xyz.y = 0.0f; ViewerPos.xyz.z = -50.0f;
888
889         flFrametime = 0.033f;
890
891         t1 = timer_get_fixed_seconds();
892
893         nebula_init();
894
895         wxApp::SetInstance( new NebeditApp() );
896
897         wxEntryStart(argc, argv);
898
899         //bool some_selected = false;
900
901         while(1)        {
902                 os_poll();
903
904                 /*some_selected = false;
905                 if (Sel_mode) {
906                         for (i=0;i<num_pts;i++) {
907                                 if (Selected[i]) {
908                                         some_selected = true;
909                                         break;
910                                 }
911                         }
912                 }*/
913
914                 mouse_get_pos( &Mouse_x, &Mouse_y );
915
916                 if (Current_face==-1) {
917                         Current_face = get_closest_face(Mouse_x, Mouse_y);
918                 }
919                 
920                 if ( check_keys() ){
921                         break;
922                 }
923
924                 if ( Sel_mode==1 ) {
925                         // Special mouse handlers for multiple selmode
926                         if (mouse_down_count(LOWEST_MOUSE_BUTTON)) {
927                                 Orig_pos_x = Mouse_x;
928                                 Orig_pos_y = Mouse_y;
929                         }
930                         if (mouse_down(LOWEST_MOUSE_BUTTON)) {
931                                 for (i=0;i<num_pts;i++) {
932                                         if (Selected[i]) {
933                                                 x[i]+=Mouse_x - Orig_pos_x;
934                                                 y[i]+=Mouse_y - Orig_pos_y;
935                                         }
936                                 }
937                                 Orig_pos_x = Mouse_x;
938                                 Orig_pos_y = Mouse_y;
939                         }
940                         if (mouse_down_count(MOUSE_RIGHT_BUTTON)) {
941                                 Orig_pos_x = Mouse_x;
942                                 Orig_pos_y = Mouse_y;
943                                 for (i=0;i<num_pts;i++) {
944                                         Selected[i] = FALSE;
945                                 }
946                         }
947                         if (mouse_down(MOUSE_RIGHT_BUTTON)) {
948                                 Draw_sel_box = true;
949                                 End_pos_x = Mouse_x;
950                                 End_pos_y = Mouse_y;
951                         }
952                         if (mouse_up_count(MOUSE_RIGHT_BUTTON)) {
953                                 Draw_sel_box = false;
954                                 End_pos_x = Mouse_x;
955                                 End_pos_y = Mouse_y;
956                                 select_by_box(Orig_pos_x, Orig_pos_y, End_pos_x, End_pos_y);
957                         }
958
959                 } else {
960
961                         if ( mouse_down(LOWEST_MOUSE_BUTTON) )  {
962                                 if ( mdflag )   {
963                                         if (Vert_mode==0) {
964                                                 x[Current_point] = Mouse_x;
965                                                 y[Current_point] = Mouse_y;
966                                         } else if (Vert_mode==1) {
967                                                 x[tri[Current_face][0]] += Mouse_x - Orig_pos_x;
968                                                 y[tri[Current_face][0]] += Mouse_y - Orig_pos_y;
969                                                 x[tri[Current_face][1]] += Mouse_x - Orig_pos_x;
970                                                 y[tri[Current_face][1]] += Mouse_y - Orig_pos_y;
971                                                 x[tri[Current_face][2]] += Mouse_x - Orig_pos_x;
972                                                 y[tri[Current_face][2]] += Mouse_y - Orig_pos_y;
973                                                 Orig_pos_x = Mouse_x;
974                                                 Orig_pos_y = Mouse_y;
975                                         }
976                                 } else {
977                                         if (Vert_mode == 1) {
978                                                 Current_face = get_closest_face(Mouse_x, Mouse_y);
979                                                 Orig_pos_x = Mouse_x;
980                                                 Orig_pos_y = Mouse_y;
981                                         }
982                                         if (Vert_mode==0) {
983                                                 Current_point = get_closest(Mouse_x, Mouse_y);
984                                                 mouse_set_pos(x[Current_point], y[Current_point]);
985                                         }
986                                         mdflag = true;
987                                 }
988                         }
989                         if ( mouse_up_count(LOWEST_MOUSE_BUTTON)) {
990                                 //Current_point = -1;
991                                 //Current_face = -1;
992                                 mdflag = false;
993                         }
994
995                         if ( mouse_up_count(MOUSE_RIGHT_BUTTON) ) {
996                                 if (Vert_mode==0) {
997                                         Current_point = add_vert(Mouse_x, Mouse_y);
998                                 } else if (Vert_mode==1) {
999                                         if ((num_tris<MAX_TRIS-1)) {
1000                                                 tri[num_tris][Which_vert] = get_closest(Mouse_x, Mouse_y);
1001                                                 Which_vert++;
1002                                                 if (Which_vert>2) {
1003                                                         Which_vert = 0;
1004                                                         num_tris++;
1005                                                 }
1006                                         }
1007                                 }
1008                         }
1009                 }
1010                 controls_read_all(&ci, flFrametime );
1011                 physics_read_flying_controls( &ViewerOrient, &ViewerPhysics, &ci, flFrametime );
1012                 physics_sim(&ViewerPos, &ViewerOrient, &ViewerPhysics, flFrametime );           
1013
1014                 render_frame();
1015
1016                 t2 = timer_get_fixed_seconds();
1017                 if ( t2 > t1 )  {
1018                         flFrametime = f2fl(t2 - t1);
1019                 }
1020
1021                 t1 = t2;
1022
1023                 SDL_Delay(10);
1024         }
1025
1026         nebedit_close();
1027
1028         wxEntryCleanup();
1029
1030         return 0;
1031 }
1032
1033 // Stub functions and variables.
1034 // These do nothing but are needed to prevent link errors.
1035 void demo_set_playback_filter() {}
1036
1037 void freespace_menu_background()
1038 {
1039         gr_reset_clip();
1040         gr_clear();
1041 }
1042
1043 int game_check_key()
1044 {
1045         return key_inkey();
1046 }
1047
1048 int game_poll()
1049 {
1050         return key_inkey();
1051 }
1052
1053 vector Camera_pos;
1054 vector Dead_player_last_vel;
1055 // end stubs
1056