]> icculus.org git repositories - taylor/freespace2.git/blob - src/nebedit/nebedit.cpp
nebedit first pass; still needs some work
[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 #ifndef PLAT_UNIX
96 #include <windows.h>
97 #include <dos.h>
98 #endif
99 #include <stdio.h>
100 #include <stdlib.h>
101 #include <string.h>
102 #include <ctype.h>
103
104 #include "pstypes.h"
105 #include "2d.h"
106 #include "3d.h"
107 #include "key.h"
108 #include "palman.h"
109 #include "bmpman.h"
110 #include "timer.h"
111 #include "floating.h"
112 #include "osapi.h"
113 #include "cfile.h"
114 #include "linklist.h"
115 #include "lighting.h"
116 #include "mouse.h"
117 #include "vecmat.h"
118 #include "physics.h"
119 #include "model.h"
120 #include "font.h"
121 #include "cmdline.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 float flFrametime = 0.0f;
138
139 int Font1 = -1;
140
141 color color_green;
142
143 vector Global_light_world = { 0.208758f, -0.688253f, -0.694782f };
144
145 // nebula stuff
146
147 #define NEB_W 6
148 #define NEB_H 6
149 #define MAX_TRIS 200
150 #define MAX_POINTS 300
151
152 int neb_w = 0, neb_h = 0;
153
154 int nebula_inited = 0;
155 int num_pts = 0;
156
157 int x[MAX_POINTS], y[MAX_POINTS], l[MAX_POINTS];
158 float scale_factor = 1.0f;
159
160 int num_tris = 0;
161 int tri[MAX_TRIS][3];
162
163 color nebula_color;
164
165 int Mouse_x, Mouse_y;
166 int Current_point;
167 BOOL Selected[MAX_POINTS];
168 BOOL Sel_mode = 0;   // 0 = 1 point at a time, 1 = select multiple points
169 int Current_face;
170
171 int View_mode = 0;      // 0 = 2d editor, 1 = 3d viewer
172
173 int Vert_mode = 0;   // 0 = Move vertices/Add vertices, 2 = Move face/Add face
174
175 int Which_vert = 0;  // Current vertex of the faceadd
176
177 int Orig_pos_x;
178 int Orig_pos_y;
179 int End_pos_x;
180 int End_pos_y;
181 BOOL Draw_sel_box = FALSE;
182
183 int Neb_created = 0;
184
185 int Nebedit_running = 1;
186
187 extern void project_2d_onto_sphere(vector *, float, float);
188
189
190 void create_default_neb()
191 {
192         int i,j;
193         neb_w = NEB_W;
194         neb_h = NEB_H;
195         num_pts = neb_w*neb_h;
196
197         for (j=0; j<neb_h; j++ )        {
198                 for (i=0; i<neb_w; i++ )        {
199                         x[i+j*neb_w] = ((i+1)*SCREEN_W)/(neb_w+2);
200                         y[i+j*neb_w] = ((j+3)*SCREEN_H)/(neb_h+6);
201                         if ( (j==0) || (j==neb_h-1))    {
202                                 l[i+j*neb_w] = 0;
203                         } else {
204                                 l[i+j*neb_w] = 31;
205                         }
206                 }
207         }
208
209         num_tris = 0;
210
211         for (j=0; j<neb_h-1; j++ )      {
212                 for (i=0; i<neb_w-1; i++ )      {
213                         tri[num_tris][0] = i+neb_w*j;
214                         tri[num_tris][1] = i+neb_w*j+1;
215                         tri[num_tris][2] = i+neb_w*(j+1)+1;
216                         num_tris++;
217
218                         tri[num_tris][0] = i+neb_w*j;
219                         tri[num_tris][1] = i+neb_w*(j+1)+1;
220                         tri[num_tris][2] = i+neb_w*(j+1);
221                         num_tris++;
222                 }
223         }
224
225         Neb_created = 1;
226 }
227
228 #define NEBULA_FILE_ID "NEBU"                   
229 #define NEBULA_MAJOR_VERSION 1          // Can be 1-?
230 #define NEBULA_MINOR_VERSION 0          // Can be 0-99
231
232 void save_nebula_sub(const char *filename)
233 {
234         FILE *fp;
235         float xf, yf;
236         int version;
237         int i;
238         int tmp;
239
240         fp = fopen(filename, "wb");
241
242         // ID of NEBU
243         fwrite( "NEBU", 4, 1, fp );
244         version = NEBULA_MAJOR_VERSION*100+NEBULA_MINOR_VERSION;
245         tmp = INTEL_INT(version);
246         fwrite( &tmp, sizeof(int), 1, fp );
247         tmp = INTEL_INT(num_pts);
248         fwrite( &tmp, sizeof(int), 1, fp );
249         tmp = INTEL_INT(num_tris);
250         fwrite( &tmp, sizeof(int), 1, fp );
251
252
253         for (i=0; i<num_pts; i++ )      {
254                 xf = INTEL_FLOAT(float(x[i])/640.0f);
255                 yf = INTEL_FLOAT(float(y[i])/480.0f);
256                 fwrite( &xf, sizeof(float), 1, fp );
257                 fwrite( &yf, sizeof(float), 1, fp );
258                 tmp = INTEL_INT(l[i]);
259                 fwrite( &tmp, sizeof(int), 1, fp );
260         }
261
262         for (i=0; i<num_tris; i++ )     {
263                 tmp = INTEL_INT(tri[i][0]);
264                 fwrite( &tmp, sizeof(int), 1, fp );
265                 tmp = INTEL_INT(tri[i][1]);
266                 fwrite( &tmp, sizeof(int), 1, fp );
267                 tmp = INTEL_INT(tri[i][2]);
268                 fwrite( &tmp, sizeof(int), 1, fp );
269         }
270
271         fclose(fp);
272 }
273
274 // returns 0 if failed
275 int load_nebula_sub(const char *filename)
276 {
277         FILE *fp;
278         char id[16];
279         int version, major, minor;
280
281         fp = fopen(filename, "rb");
282
283         if ( !fp )      {
284                 return 0;
285         }
286
287         // ID of NEBU
288         fread( id, 4, 1, fp );
289         if ( strncmp( id, NEBULA_FILE_ID, 4))   {
290                 mprintf(( "Not a valid nebula file.\n" ));
291                 return 0;
292         }
293
294         fread( &version, sizeof(int), 1, fp );
295         version = INTEL_INT(version);
296         major = version / 100;
297         minor = version % 100;
298
299         if ( (major != NEBULA_MAJOR_VERSION) && (minor != NEBULA_MINOR_VERSION) ) {
300                 mprintf(( "An out of date nebula file.\n" ));
301                 return 0;
302         }
303
304         fread( &num_pts, sizeof(int), 1, fp );
305         num_pts = INTEL_INT(num_pts);
306         SDL_assert( num_pts < MAX_POINTS );
307         fread( &num_tris, sizeof(int), 1, fp );
308         num_tris = INTEL_INT(num_tris);
309         SDL_assert( num_tris < MAX_TRIS );
310
311         for (int i=0; i<num_pts; i++ )  {
312                 float xf, yf;
313                 int li;
314
315                 fread( &xf, sizeof(float), 1, fp );
316                 fread( &yf, sizeof(float), 1, fp );
317                 fread( &li, sizeof(int), 1, fp );
318
319                 xf = INTEL_FLOAT(xf);
320                 yf = INTEL_FLOAT(yf);
321                 li = INTEL_INT(li);
322
323                 x[i] = (int)(xf*640.0f);
324                 y[i] = (int)(yf*480.0f);
325                 l[i] = li;
326         }
327
328         for (int i=0; i<num_tris; i++ ) {
329                 fread( &tri[i][0], sizeof(int), 1, fp );
330                 fread( &tri[i][1], sizeof(int), 1, fp );
331                 fread( &tri[i][2], sizeof(int), 1, fp );
332                 tri[i][0] = INTEL_INT(tri[i][0]);
333                 tri[i][1] = INTEL_INT(tri[i][1]);
334                 tri[i][2] = INTEL_INT(tri[i][2]);
335         }
336
337         fclose(fp);
338
339         return 1;
340 }
341
342 void nebedit_close()
343 {
344         save_nebula_sub( "autosaved.neb" );
345 }
346
347 void save_nebula()
348 {
349 #ifdef PLAT_UNIX
350         STUB_FUNCTION;
351 #else
352         char filename[255] = "\0";
353         //char filter[255] = "Nebula Files\0
354         OPENFILENAME o;
355         memset(&o,0,sizeof(o));
356         o.lStructSize = sizeof(o);
357         //o.hwndOwner = GetActiveWindow();
358         o.lpstrFilter = "Nebula Files\0*.NEB\0\0";
359         o.lpstrFile = filename;
360         o.nMaxFile = 256;
361         o.Flags = OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;
362         o.lpstrDefExt = "*.NEB";
363         if (!GetSaveFileName(&o)) return;
364
365         save_nebula_sub(filename);
366 #endif
367 }
368
369 void load_nebula()
370 {
371 #ifdef PLAT_UNIX
372         STUB_FUNCTION;
373
374         int create_default = 0;
375
376         if ( !load_nebula_sub("nebula01.neb"))  {
377                 create_default = 1;
378         }
379
380         if ( create_default )   {
381                 create_default_neb();
382         }
383
384         Neb_created = 1;
385 #else
386         char filename[255] = "\0";
387         OPENFILENAME o;
388         memset(&o,0,sizeof(o));
389         o.lStructSize = sizeof(OPENFILENAME);
390         //o.hwndOwner = GetActiveWindow();
391         o.lpstrFilter = "Nebula Files\0*.NEB\0\0";
392         o.lpstrFile = filename;
393         o.nMaxFile = 256;
394         o.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
395         o.lpstrDefExt = "*.NEB";
396
397         int create_default = 0;
398         if (!GetOpenFileName(&o)) {
399                 create_default = 1;
400         } else {
401                 if ( !load_nebula_sub(filename))        {
402                         create_default = 1;
403                 }
404         }
405
406         if ( create_default )   {       
407                 create_default_neb();   
408         }
409
410         Neb_created = 1;
411 #endif
412 }
413
414 void nebula_init()
415 {
416         if ( nebula_inited ) return;
417         memset(Selected, 0, sizeof(BOOL)*MAX_POINTS);
418         nebula_inited++;
419
420         create_default_neb();   
421         gr_init_alphacolor( &nebula_color, 0, 255, 0, 255, AC_TYPE_HUD );
422
423         return;
424 }
425
426 void draw_tri_2d( int i, int j, int k )
427 {
428         int index[3];
429
430         index[0] = i;
431         index[1] = j;
432         index[2] = k;
433
434         vertex va, vb, vc;
435         vertex * verts[3] = { &va, &vb, &vc };
436 //      gr_zbuffering = 0;
437         for (int v=0; v<3; v++ )        {
438                 verts[v]->sx = i2fl(x[index[v]]);   
439                 verts[v]->sy = i2fl(y[index[v]]);
440                 verts[v]->u = 0.0f;
441                 verts[v]->v = 0.0f;
442                 verts[v]->sw = 1.0f; 
443                 verts[v]->b = (ubyte)(i2fl(l[index[v]]*255)/31.0f);
444         }
445
446 //      gr_set_color( 0, 0, 0 );
447         gr_tmapper(3, verts, TMAP_FLAG_RAMP | TMAP_FLAG_GOURAUD | TMAP_FLAG_NEBULA );
448
449         if ( !key_pressed(SDLK_LSHIFT) )        {
450                 gr_set_color(100,100,100);
451                 gr_line( x[i], y[i], x[j], y[j] );
452                 gr_line( x[j], y[j], x[k], y[k] );
453                 gr_line( x[k], y[k], x[i], y[i] );
454         }
455 }
456
457 void nebula_draw_2d()
458 {
459         int i;
460         
461         for (i=0; i<num_tris; i++ )     {
462                 draw_tri_2d( tri[i][0], tri[i][1], tri[i][2] );
463         }               
464
465                 gr_set_color(100,0,0);
466                 for (i=0; i<num_pts; i++ )      {
467                         gr_circle( x[i], y[i], 4 );
468                 }
469                 if ((Sel_mode==1)) { // multiple selection
470                         if (Draw_sel_box) {
471                                 gr_set_color(200,0,200);
472                                 gr_line(Orig_pos_x, Orig_pos_y, Orig_pos_x, End_pos_y);
473                                 gr_line(Orig_pos_x, End_pos_y, End_pos_x, End_pos_y);
474                                 gr_line(End_pos_x, Orig_pos_y, End_pos_x, End_pos_y);
475                                 gr_line(End_pos_x, Orig_pos_y, Orig_pos_x, Orig_pos_y);
476                         } else {
477                                 gr_set_color(0,100,0);
478                                 for (int i=0;i<num_pts;i++)
479                                         if (Selected[i]) gr_circle( x[i], y[i], 5);
480                         }
481                 } else if ((Vert_mode==0)&&(Current_point>-1)) {
482                         gr_set_color(0,100,0);
483                         gr_circle( x[Current_point], y[Current_point], 5);
484                 } else if (Vert_mode == 1) {
485                         for (i=0;i<Which_vert;i++) {
486                                 gr_set_color(0,0,100);
487                                 gr_circle( x[tri[num_tris][i]], y[tri[num_tris][i]], 6);
488                         }
489                         gr_set_color(200,200,0);
490                         if (Current_face>-1) {
491                                 gr_line(x[tri[Current_face][0]], y[tri[Current_face][0]], 
492                                                 x[tri[Current_face][1]], y[tri[Current_face][1]]);
493                                 gr_line(x[tri[Current_face][1]], y[tri[Current_face][1]], 
494                                                 x[tri[Current_face][2]], y[tri[Current_face][2]]);
495                                 gr_line(x[tri[Current_face][2]], y[tri[Current_face][2]], 
496                                                 x[tri[Current_face][0]], y[tri[Current_face][0]]);
497                         }
498                 }
499 }
500
501
502 void draw_tri_3d( int i, int j, int k )
503 {
504         int index[3];
505
506         index[2] = k;
507         index[1] = j;
508         index[0] = i;
509
510         vertex va, vb, vc;
511         vertex * verts[3] = { &va, &vb, &vc };
512         //gr_zbuffering = 0;
513         for (int v=0; v<3; v++ )        {
514                 vector tmp;
515                 
516                 project_2d_onto_sphere( &tmp, 1.0f - i2fl(x[index[v]])/640.0f, i2fl(y[index[v]])/480.0f );
517         
518                 vm_vec_scale( &tmp, 10.0f );
519
520                 g3_rotate_faraway_vertex( verts[v], &tmp );
521                 //g3_rotate_vertex( verts[v], &tmp );
522                 g3_project_vertex( verts[v] );
523
524                 verts[v]->b = (ubyte)(i2fl(l[index[v]]*255)/31.0f);
525         }
526
527         //gr_zbuffering = 0;
528         //gr_set_color_fast( &nebula_color );
529         //gr_set_color( 0, 0, 0 );
530         g3_draw_poly(3, verts, TMAP_FLAG_RAMP | TMAP_FLAG_GOURAUD | TMAP_FLAG_NEBULA );
531 }
532
533 void nebula_draw_3d()
534 {
535         int i;
536         for (i=0; i<num_tris; i++ )     {
537                 draw_tri_3d( tri[i][0], tri[i][1], tri[i][2] );
538         }               
539 }
540
541 void render_frame()
542 {
543         gr_reset_clip();
544
545         gr_set_color(0,0,0);            // set color to black
546         gr_rect(0,0,SCREEN_W,SCREEN_H); // clear screen
547
548         light_reset();
549         light_add_directional( &Global_light_world, 0.1f, 1.0f, 1.0f, 1.0f );
550
551         g3_start_frame(1);
552
553         g3_set_view_matrix(&ViewerPos, &ViewerOrient,ViewerZoom);
554
555         if ( View_mode == 0 )   {
556                 nebula_draw_2d();
557
558                 gr_set_font(Font1);
559                 gr_set_color_fast( &color_green );
560                 gr_printf(10,10,"Nebula Editor. Mode :");
561                 if (Sel_mode ==1) {
562                                 gr_printf(180, 10, "Multiple Vertex Selection Editing");
563                 } else if (Vert_mode ==0 ) {
564                         gr_printf(180,10,"Vertex Editing");
565                         if(Current_point >= 0){
566                                 gr_printf(180, 20, "Current vertex intensity : %d\n", l[Current_point]);
567                         }
568                 } else if (Vert_mode ==1) {
569                         gr_printf(180,10,"Face Editing");
570                 }
571                 char blah[255];
572                 gr_printf(20,30,"# Points:");
573                 gr_printf(100,30, SDL_itoa(num_pts, blah, 10));
574                 gr_printf(220,30,"# Polys:");
575                 gr_printf(300,30, SDL_itoa(num_tris, blah, 10));
576         } else {
577                 nebula_draw_3d();
578                 model_render( test_model, &ModelOrient, &ModelPos );
579         }
580
581         g3_end_frame();
582
583         gr_flip();
584 }
585
586 int get_closest(int mx, int my)
587 {
588         int i, closest = -1, cval = 100000;
589
590         for (i=0; i<num_pts; i++ )      {
591                 int dist;
592                 int dx, dy;
593                 
594                 dx = x[i] - mx;
595                 dy = y[i] - my;
596                 
597                 dist = fl2i(fl_sqrt( i2fl((dx*dx)+(dy*dy)) ));
598
599                 if ( dist < cval )      {
600                         cval = dist;
601                         closest = i;
602                 }
603         }
604
605         return closest;
606 }
607
608 int get_closest_face(int mx, int my)
609 {
610         int i, closest = -1, cval = 100000;
611
612         for (i=0; i<num_tris; i++ )     {
613                 int dist;
614                 int dx, dy;
615                 
616                 dx = x[tri[i][0]] - mx;
617                 dy = y[tri[i][0]] - my;
618
619                 dx += x[tri[i][1]] - mx;
620                 dy += y[tri[i][1]] - my;
621                 
622                 dx += x[tri[i][2]] - mx;
623                 dy += y[tri[i][2]] - my;
624
625                 dist = fl2i(fl_sqrt( i2fl((dx*dx)+(dy*dy)) ));
626 /*
627                 dist += fl2i(fl_sqrt( i2fl((dx*dx)+(dy*dy)) ));
628
629                 dx = x[tri[i][2]] - mx;
630                 dy = y[tri[i][2]] - my;
631                 dist += fl2i(fl_sqrt( i2fl((dx*dx)+(dy*dy)) ));
632 */
633
634                 if ( dist < cval )      {
635                         cval = dist;
636                         closest = i;
637                 }
638         }
639
640         return closest;
641 }
642
643 void delete_face(int i)
644 {
645         for (int j=i;j<num_tris;j++) {
646                 memcpy(tri[j], tri[j+1], sizeof(int)*3);
647         }
648         num_tris--;
649 }
650
651 void delete_vert(int i)
652 {
653         int j;
654
655         for (j=0;j<num_tris;j++) {
656                 if ((tri[j][0]==i)||(tri[j][1]==i)||(tri[j][2]==i)) {
657                         delete_face(j);
658                         j=0;
659                 }
660         }
661         for (j=0;j<num_tris;j++) {
662                 if (tri[j][0]>i) tri[j][0]--;
663                 if (tri[j][1]>i) tri[j][1]--;
664                 if (tri[j][2]>i) tri[j][2]--;
665         }
666         for (j=i;j<num_pts;j++) {
667                 x[j] = x[j+1];
668                 y[j] = y[j+1];
669                 l[j] = l[j+1];
670         }
671         num_pts--;
672 }
673
674 int add_vert(int mx, int my)
675 {
676         SDL_assert(num_pts<300);
677         x[num_pts] = mx;
678         y[num_pts] = my;
679         l[num_pts] = 0;
680         num_pts++;
681         return num_pts-1;
682 }
683
684 void select_by_box(int x1, int y1, int x2, int y2)
685 {
686         if (x1>x2) {
687                 int temp = x1;
688                 x1 = x2;
689                 x2 = temp;
690         }
691         if (y1>y2) {
692                 int temp = y1;
693                 y1 = y2;
694                 y2 = temp;
695         }
696         for (int i=0;i<num_pts;i++) {
697                 if ((x[i]<=x2) && (x[i]>=x1) &&
698                          (y[i]<=y2) && (y[i]>=y1)) {
699                         Selected[i] = TRUE;
700                 }
701         }
702 }
703
704 void sphericalize_nebula()
705 {
706         int idx1, idx2;
707         int px = SCREEN_W / (neb_w - 1);
708         int py = SCREEN_H / (neb_h - 1);
709
710         // flatten out the nebula so that it covers the entire sphere evenly
711         for(idx1=0; idx1<neb_w; idx1++){
712                 for(idx2=0; idx2<neb_h; idx2++){
713                         x[idx1+idx2*neb_w] = px * idx1;
714                         y[idx1+idx2*neb_w] = py * idx2;
715                 }
716         }
717 }
718
719 void controls_read_all(control_info * ci, float sim_time )
720 {
721         float kh;
722
723         {
724                 float temp = ci->heading;
725                 float temp1 = ci->pitch;
726                 memset( ci, 0, sizeof(control_info) );
727                 ci->heading = temp;
728                 ci->pitch = temp1;
729         }
730
731         // From keyboard...
732         kh = (key_down_timef(SDLK_KP_6) - key_down_timef(SDLK_KP_4))/8.0f;
733         if (kh == 0.0f)
734                 ci->heading = 0.0f;
735         else if (kh > 0.0f) {
736                 if (ci->heading < 0.0f)
737                         ci->heading = 0.0f;
738         } else // kh < 0
739                 if (ci->heading > 0.0f)
740                         ci->heading = 0.0f;
741         ci->heading += kh;
742
743         kh = (key_down_timef(SDLK_KP_8) - key_down_timef(SDLK_KP_2))/8.0f;
744         if (kh == 0.0f)
745                 ci->pitch = 0.0f;
746         else if (kh > 0.0f) {
747                 if (ci->pitch < 0.0f)
748                         ci->pitch = 0.0f;
749         } else // kh < 0
750                 if (ci->pitch > 0.0f)
751                         ci->pitch = 0.0f;
752         ci->pitch += kh;
753
754         ci->bank = (key_down_timef(SDLK_KP_7) - key_down_timef(SDLK_KP_9))*.75f;
755         ci->forward = key_down_timef(SDLK_a) - key_down_timef(SDLK_z);
756         ci->sideways = key_down_timef(SDLK_KP_3) - key_down_timef(SDLK_KP_1);
757         ci->vertical = key_down_timef(SDLK_KP_PLUS) - key_down_timef(SDLK_KP_ENTER);
758 }
759
760 int check_keys()
761 {
762         int k;
763
764         while( (k = key_inkey()) != 0 ) {
765 //mprintf(( "Key = %x\n", k ));
766                 if ( k == SDLK_ESCAPE ) {
767                         return 1;
768                 }
769
770                 switch( k )     {
771                 case SDLK_RETURN:
772                         Sel_mode = FALSE;
773                         Vert_mode = !Vert_mode;
774                         Which_vert = 0;
775                         break;
776
777                 case SDLK_DELETE:
778                         if (Sel_mode) break;
779                         if (Vert_mode==1) delete_face(Current_face);
780                         else if (Vert_mode==0) {
781                                 delete_vert(Current_point);
782                         }
783                         break;
784
785                 case SDLK_MINUS:
786                         scale_factor -= 0.05f;
787                         mprintf(( "Scale = %.1f\n", scale_factor ));
788                         break;
789
790
791                 case SDLK_EQUALS:
792                         scale_factor += 0.05f;
793                         mprintf(( "Scale = %.1f\n", scale_factor ));
794                         break;
795
796                 case SDLK_INSERT:
797                         Sel_mode = !Sel_mode;
798                         break;
799
800                 case SDLK_SPACE:
801                         View_mode = !View_mode;
802                         break;
803
804                 case SDLK_COMMA:
805                         if (Sel_mode) {
806                                 int i;
807                                 for (i=0;i<num_pts;i++) if (Selected[i]) {
808                                         if ( l[i] > 0 ) {
809                                                 l[i]--;
810                                         }
811                                 }
812                         } else if (Vert_mode==0) {
813                                 if ( Current_point > -1 )       {
814                                         if ( l[Current_point] > 0 )     {
815                                                 l[Current_point]--;
816                                         }
817                                 }
818                         } else if (Vert_mode ==1) {
819                                 if ( l[tri[Current_face][0]] > 0 )      {
820                                                 l[tri[Current_face][0]]--;
821                                         }
822                                 if ( l[tri[Current_face][1]] > 0 )      {
823                                                 l[tri[Current_face][1]]--;
824                                         }
825                                 if ( l[tri[Current_face][2]] > 0 )      {
826                                                 l[tri[Current_face][2]]--;
827                                         }
828                         }
829                         break;
830
831                 case SDLK_PERIOD:
832                         if (Sel_mode) {
833                                 int i;
834                                 for (i=0;i<num_pts;i++) if (Selected[i]) {
835                                         if ( l[i] < 31 )        {
836                                                 l[i]++;
837                                         }
838                                 }
839                         } else if (Vert_mode==0) {
840                                 if ( Current_point > -1 )       {
841                                         if ( l[Current_point] < 31 )    {
842                                                 l[Current_point]++;
843                                         }
844                                 }
845                         } else if (Vert_mode ==1) {
846                                 if ( l[tri[Current_face][0]] <31 )      {
847                                                 l[tri[Current_face][0]]++;
848                                         }
849                                 if ( l[tri[Current_face][1]] <31)       {
850                                                 l[tri[Current_face][1]]++;
851                                         }
852                                 if ( l[tri[Current_face][2]] <31 )      {
853                                                 l[tri[Current_face][2]]++;
854                                         }
855                         }
856                         
857                         break;          
858
859                 case SDLK_F5:
860                         save_nebula();
861                         break;
862                 case SDLK_F7:
863                         load_nebula();
864                         break;
865
866                 case SDLK_BACKSPACE:
867                         sphericalize_nebula();
868                         break;
869                 }
870         }
871         return 0;
872 }
873
874 void os_close()
875 {
876         exit(1);
877 }
878
879 int newtri[3];
880
881 int mdflag = 0;
882
883 int main(int argc, char *argv[])
884 {
885         int i;
886         fix t1, t2;
887         control_info ci;
888         float speed = 20.0f;            // how fast viewer moves        
889
890         // setup the fred exe directory so CFILE can init properly
891         /*
892         char *c = GetCommandLine();
893         SDL_assert(c != NULL);
894         char *tok = strtok(c, " ");
895         SDL_assert(tok != NULL);        
896         */
897
898         Cmdline_window = 1; // always windowed
899
900         timer_init();
901         // cfile_init(tok);
902         cfile_init(argv[0]);
903         os_init( "NebEdit", "NebEdit" );        //SCREEN_W, SCREEN_H );
904         os_set_title("NebEdit");
905         gr_init(GR_640, GR_OPENGL, 16);
906         palette_load_table( "gamepalette1-01.pcx" );
907         key_init();
908         mouse_init();
909         SDL_ShowCursor(1);
910         Font1 = gr_init_font( "font01.vf" );
911         gr_init_alphacolor( &color_green, 0,255,0,255,AC_TYPE_HUD );
912
913         test_model = model_load( "fighter01.pof", 0, NULL );
914
915         physics_init( &ViewerPhysics );
916         ViewerPhysics.flags |= PF_ACCELERATES | PF_SLIDE_ENABLED;
917
918         ViewerPhysics.max_vel.xyz.x = 2.0f*speed;               //sideways
919         ViewerPhysics.max_vel.xyz.y = 2.0f*speed;               //up/down
920         ViewerPhysics.max_vel.xyz.z = 2.0f*speed;               //forward
921         ViewerPhysics.max_rear_vel = 2.0f*speed;        //backward -- controlled seperately
922         
923         memset( &ci, 0, sizeof(control_info) );
924
925         ModelOrient = vmd_identity_matrix;
926         ModelPos.xyz.x=0.0f; ModelPos.xyz.y = 0.0f; ModelPos.xyz.z = 0.0f;
927
928         ViewerOrient = vmd_identity_matrix;
929         ViewerPos.xyz.x=0.0f; ViewerPos.xyz.y = 0.0f; ViewerPos.xyz.z = -50.0f;
930
931         flFrametime = 0.033f;
932
933         t1 = timer_get_fixed_seconds();
934
935         nebula_init();
936
937         int some_selected = 0;
938
939         while(1)        {
940                 os_poll();
941
942                 some_selected = FALSE;
943                 if (Sel_mode==1) {
944                         for (i=0;i<num_pts;i++) {
945                                 if (Selected[i]) {
946                                         some_selected = TRUE;
947                                         break;
948                                 }
949                         }
950                 }
951
952                 mouse_get_pos( &Mouse_x, &Mouse_y );
953
954                 if (Current_face==-1) {
955                         Current_face = get_closest_face(Mouse_x, Mouse_y);
956                 }
957                 
958                 if ( check_keys() ){
959                         break;
960                 }
961
962                 if ( Sel_mode==1 ) {
963                         // Special mouse handlers for multiple selmode
964                         if (mouse_down_count(LOWEST_MOUSE_BUTTON)) {
965                                 Orig_pos_x = Mouse_x;
966                                 Orig_pos_y = Mouse_y;
967                         }
968                         if (mouse_down(LOWEST_MOUSE_BUTTON)) {
969                                 for (i=0;i<num_pts;i++) {
970                                         if (Selected[i]) {
971                                                 x[i]+=Mouse_x - Orig_pos_x;
972                                                 y[i]+=Mouse_y - Orig_pos_y;
973                                         }
974                                 }
975                                 Orig_pos_x = Mouse_x;
976                                 Orig_pos_y = Mouse_y;
977                         }
978                         if (mouse_down_count(MOUSE_RIGHT_BUTTON)) {
979                                 Orig_pos_x = Mouse_x;
980                                 Orig_pos_y = Mouse_y;
981                                 for (i=0;i<num_pts;i++) {
982                                         Selected[i] = FALSE;
983                                 }
984                         }
985                         if (mouse_down(MOUSE_RIGHT_BUTTON)) {
986                                 Draw_sel_box = TRUE;
987                                 End_pos_x = Mouse_x;
988                                 End_pos_y = Mouse_y;
989                         }
990                         if (mouse_up_count(MOUSE_RIGHT_BUTTON)) {
991                                 Draw_sel_box = FALSE;
992                                 End_pos_x = Mouse_x;
993                                 End_pos_y = Mouse_y;
994                                 select_by_box(Orig_pos_x, Orig_pos_y, End_pos_x, End_pos_y);
995                         }
996
997                 } else {
998
999                 if ( mouse_down(LOWEST_MOUSE_BUTTON) )  {
1000                         if ( mdflag )   {
1001                                 if (Vert_mode==0) {
1002                                         x[Current_point] = Mouse_x;
1003                                         y[Current_point] = Mouse_y;
1004                                 } else if (Vert_mode==1) {
1005                                         x[tri[Current_face][0]] += Mouse_x - Orig_pos_x;
1006                                         y[tri[Current_face][0]] += Mouse_y - Orig_pos_y;
1007                                         x[tri[Current_face][1]] += Mouse_x - Orig_pos_x;
1008                                         y[tri[Current_face][1]] += Mouse_y - Orig_pos_y;
1009                                         x[tri[Current_face][2]] += Mouse_x - Orig_pos_x;
1010                                         y[tri[Current_face][2]] += Mouse_y - Orig_pos_y;
1011                                         Orig_pos_x = Mouse_x;
1012                                         Orig_pos_y = Mouse_y;
1013                                 }
1014                         } else {
1015                                 if (Vert_mode == 1) {
1016                                         Current_face = get_closest_face(Mouse_x, Mouse_y);
1017                                         Orig_pos_x = Mouse_x;
1018                                         Orig_pos_y = Mouse_y;
1019                                 }
1020                                 if (Vert_mode==0) {
1021                                         Current_point = get_closest(Mouse_x, Mouse_y);
1022                                         mouse_set_pos(x[Current_point], y[Current_point]);
1023                                 }
1024                                 mdflag = TRUE;
1025                         }
1026                 }
1027                 if ( mouse_up_count(LOWEST_MOUSE_BUTTON)) {
1028                         //Current_point = -1;
1029                         //Current_face = -1;
1030                         mdflag = FALSE;
1031                 }
1032
1033                 if ( mouse_up_count(MOUSE_RIGHT_BUTTON) ) {
1034                         if (Vert_mode==0) {
1035                                 Current_point = add_vert(Mouse_x, Mouse_y);
1036                         } else if (Vert_mode==1) {
1037                                 if ((num_tris<MAX_TRIS-1)) { 
1038                                         tri[num_tris][Which_vert] = get_closest(Mouse_x, Mouse_y);
1039                                         Which_vert++;
1040                                         if (Which_vert>2) {
1041                                                 Which_vert = 0;
1042                                                 num_tris++;
1043                                         }
1044                                 }
1045                         }
1046                 }
1047                 }
1048                 controls_read_all(&ci, flFrametime );
1049                 physics_read_flying_controls( &ViewerOrient, &ViewerPhysics, &ci, flFrametime );
1050                 physics_sim(&ViewerPos, &ViewerOrient, &ViewerPhysics, flFrametime );           
1051
1052                 render_frame();
1053
1054                 t2 = timer_get_fixed_seconds();
1055                 if ( t2 > t1 )  {
1056                         flFrametime = f2fl(t2 - t1);
1057                 }
1058
1059                 t1 = t2;
1060
1061                 SDL_Delay(10);
1062         }
1063
1064         nebedit_close();
1065
1066         return 0;
1067 }
1068
1069 // Stub functions and variables.
1070 // These do nothing but are needed to prevent link errors.
1071 void demo_set_playback_filter() {}
1072
1073 void freespace_menu_background()
1074 {
1075         gr_reset_clip();
1076         gr_clear();
1077 }
1078
1079 int game_check_key()
1080 {
1081         return key_inkey();
1082 }
1083
1084 int game_poll()
1085 {
1086         return key_inkey();
1087 }
1088
1089 vector Camera_pos;
1090 vector Dead_player_last_vel;
1091 // end stubs
1092