2 * $Logfile: /Freespace2/code/nebedit/NebEdit.cpp $
7 * Program to edit nebulas in 2d
10 * Revision 1.2 2002/05/07 03:16:47 theoddone33
11 * The Great Newline Fix
13 * Revision 1.1.1.1 2002/05/03 03:28:10 root
17 * 7 7/15/99 3:07p Dave
18 * 32 bit detection support. Mouse coord commandline.
20 * 6 5/19/99 4:07p Dave
21 * Moved versioning code into a nice isolated common place. Fixed up
22 * updating code on the pxo screen. Fixed several stub problems.
24 * 5 1/08/99 2:06p Dave
25 * Fixed pfoview for software mode.
27 * 4 12/18/98 1:14a Dave
28 * Rough 1024x768 support for Direct3D. Proper detection and usage through
31 * 3 11/13/98 2:32p Dave
32 * Improved commandline parsing for exe pathname.
34 * 2 10/24/98 9:51p Dave
36 * 1 10/24/98 9:39p Dave
38 * 13 4/13/98 10:11a John
39 * Made timer functions thread safe. Made timer_init be called in all
42 * 12 3/23/98 1:35p Sandeep
44 * 11 3/05/98 11:15p Hoffoss
45 * Changed non-game key checking to use game_check_key() instead of
48 * 10 12/29/97 5:10p Allender
49 * fixed problems with speed not being reported properly in multiplayer
50 * games. Made read_flying_controls take frametime as a parameter. More
51 * ship/weapon select stuff
53 * 9 12/04/97 3:47p John
54 * Made joystick move mouse cursor
56 * 8 11/21/97 11:32a John
57 * Added nebulas. Fixed some warpout bugs.
59 * 7 11/19/97 10:15p Adam
60 * upped maxtris to 200
62 * 6 11/19/97 4:28p Sandeep
63 * added poly/vert counter
65 * 5 11/19/97 1:59p Sandeep
66 * Added multiple vertex editing mode
68 * 4 11/16/97 2:29p John
69 * added versioning to nebulas; put nebula code into freespace.
71 * 3 11/13/97 12:04p Sandeep
72 * Added face editing support, deletion support, and a saving and loading
75 * 2 11/10/97 9:59p John
78 * 1 11/10/97 9:42p John
101 #include "linklist.h"
102 #include "lighting.h"
117 physics_info ViewerPhysics;
118 float ViewerZoom = 1.0f;
121 int Fred_running = 0;
122 int Pofview_running = 0;
123 float flFrametime = 0.0f;
129 vector Global_light_world = { 0.208758f, -0.688253f, -0.694782f };
136 #define MAX_POINTS 300
138 int neb_w = 0, neb_h = 0;
140 int nebula_inited = 0;
143 int x[MAX_POINTS], y[MAX_POINTS], l[MAX_POINTS];
144 float scale_factor = 1.0f;
147 int tri[MAX_TRIS][3];
151 int Mouse_x, Mouse_y;
153 BOOL Selected[MAX_POINTS];
154 BOOL Sel_mode = 0; // 0 = 1 point at a time, 1 = select multiple points
157 int View_mode = 0; // 0 = 2d editor, 1 = 3d viewer
159 int Vert_mode = 0; // 0 = Move vertices/Add vertices, 2 = Move face/Add face
161 int Which_vert = 0; // Current vertex of the faceadd
167 BOOL Draw_sel_box = FALSE;
171 int Nebedit_running = 1;
173 extern int load_nebula_sub(char*);
174 extern void project_2d_onto_sphere(vector *, float, float);
176 void create_default_neb()
181 num_pts = neb_w*neb_h;
183 for (j=0; j<neb_h; j++ ) {
184 for (i=0; i<neb_w; i++ ) {
185 x[i+j*neb_w] = ((i+1)*SCREEN_W)/(neb_w+2);
186 y[i+j*neb_w] = ((j+3)*SCREEN_H)/(neb_h+6);
187 if ( (j==0) || (j==neb_h-1)) {
197 for (j=0; j<neb_h-1; j++ ) {
198 for (i=0; i<neb_w-1; i++ ) {
199 tri[num_tris][0] = i+neb_w*j;
200 tri[num_tris][1] = i+neb_w*j+1;
201 tri[num_tris][2] = i+neb_w*(j+1)+1;
204 tri[num_tris][0] = i+neb_w*j;
205 tri[num_tris][1] = i+neb_w*(j+1)+1;
206 tri[num_tris][2] = i+neb_w*(j+1);
214 #define NEBULA_FILE_ID "NEBU"
215 #define NEBULA_MAJOR_VERSION 1 // Can be 1-?
216 #define NEBULA_MINOR_VERSION 0 // Can be 0-99
218 void save_nebula_sub(char *filename)
224 fp = fopen(filename, "wb");
227 fwrite( "NEBU", 4, 1, fp );
228 version = NEBULA_MAJOR_VERSION*100+NEBULA_MINOR_VERSION;
229 fwrite( &version, sizeof(int), 1, fp );
230 fwrite( &num_pts, sizeof(int), 1, fp );
231 fwrite( &num_tris, sizeof(int), 1, fp );
233 for (int i=0; i<num_pts; i++ ) {
234 xf = float(x[i])/640.0f;
235 yf = float(y[i])/480.0f;
236 fwrite( &xf, sizeof(float), 1, fp );
237 fwrite( &yf, sizeof(float), 1, fp );
238 fwrite( &l[i], sizeof(int), 1, fp );
241 for (i=0; i<num_tris; i++ ) {
242 fwrite( &tri[i][0], sizeof(int), 1, fp );
243 fwrite( &tri[i][1], sizeof(int), 1, fp );
244 fwrite( &tri[i][2], sizeof(int), 1, fp );
252 save_nebula_sub( "autosaved.neb" );
257 char filename[255] = "\0";
258 //char filter[255] = "Nebula Files\0
260 memset(&o,0,sizeof(o));
261 o.lStructSize = sizeof(o);
262 //o.hwndOwner = GetActiveWindow();
263 o.lpstrFilter = "Nebula Files\0*.NEB\0\0";
264 o.lpstrFile = filename;
266 o.Flags = OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;
267 o.lpstrDefExt = "*.NEB";
268 if (!GetSaveFileName(&o)) return;
270 save_nebula_sub(filename);
275 char filename[255] = "\0";
277 memset(&o,0,sizeof(o));
278 o.lStructSize = sizeof(OPENFILENAME);
279 //o.hwndOwner = GetActiveWindow();
280 o.lpstrFilter = "Nebula Files\0*.NEB\0\0";
281 o.lpstrFile = filename;
283 o.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
284 o.lpstrDefExt = "*.NEB";
286 int create_default = 0;
287 if (!GetOpenFileName(&o)) {
290 if ( !load_nebula_sub(filename)) {
295 if ( create_default ) {
296 create_default_neb();
304 if ( nebula_inited ) return;
305 memset(Selected, 0, sizeof(BOOL)*MAX_POINTS);
308 create_default_neb();
309 gr_init_alphacolor( &nebula_color, 0, 255, 0, 255 );
314 void draw_tri_2d( int i, int j, int k )
323 vertex * verts[3] = { &va, &vb, &vc };
324 // gr_zbuffering = 0;
325 for (int v=0; v<3; v++ ) {
326 verts[v]->sx = i2fl(x[index[v]]);
327 verts[v]->sy = i2fl(y[index[v]]);
331 verts[v]->r = verts[v]->g = verts[v]->b = (ubyte)(i2fl(l[index[v]])/31.0f);
335 // gr_set_color( 0, 0, 0 );
336 gr_tmapper(3, verts, TMAP_FLAG_RAMP | TMAP_FLAG_GOURAUD | TMAP_FLAG_NEBULA );
338 if ( !keyd_pressed[KEY_LSHIFT] ) {
339 gr_set_color(100,100,100);
340 gr_line( x[i], y[i], x[j], y[j] );
341 gr_line( x[j], y[j], x[k], y[k] );
342 gr_line( x[k], y[k], x[i], y[i] );
346 void nebula_draw_2d()
350 for (i=0; i<num_tris; i++ ) {
351 draw_tri_2d( tri[i][0], tri[i][1], tri[i][2] );
354 gr_set_color(100,0,0);
355 for (i=0; i<num_pts; i++ ) {
356 gr_circle( x[i], y[i], 4 );
358 if ((Sel_mode==1)) { // multiple selection
360 gr_set_color(200,0,200);
361 gr_line(Orig_pos_x, Orig_pos_y, Orig_pos_x, End_pos_y);
362 gr_line(Orig_pos_x, End_pos_y, End_pos_x, End_pos_y);
363 gr_line(End_pos_x, Orig_pos_y, End_pos_x, End_pos_y);
364 gr_line(End_pos_x, Orig_pos_y, Orig_pos_x, Orig_pos_y);
366 gr_set_color(0,100,0);
367 for (int i=0;i<num_pts;i++)
368 if (Selected[i]) gr_circle( x[i], y[i], 5);
370 } else if ((Vert_mode==0)&&(Current_point>-1)) {
371 gr_set_color(0,100,0);
372 gr_circle( x[Current_point], y[Current_point], 5);
373 } else if (Vert_mode == 1) {
374 for (i=0;i<Which_vert;i++) {
375 gr_set_color(0,0,100);
376 gr_circle( x[tri[num_tris][i]], y[tri[num_tris][i]], 6);
378 gr_set_color(200,200,0);
379 if (Current_face>-1) {
380 gr_line(x[tri[Current_face][0]], y[tri[Current_face][0]],
381 x[tri[Current_face][1]], y[tri[Current_face][1]]);
382 gr_line(x[tri[Current_face][1]], y[tri[Current_face][1]],
383 x[tri[Current_face][2]], y[tri[Current_face][2]]);
384 gr_line(x[tri[Current_face][2]], y[tri[Current_face][2]],
385 x[tri[Current_face][0]], y[tri[Current_face][0]]);
391 void draw_tri_3d( int i, int j, int k )
400 vertex * verts[3] = { &va, &vb, &vc };
402 for (int v=0; v<3; v++ ) {
405 project_2d_onto_sphere( &tmp, 1.0f - i2fl(x[index[v]])/640.0f, i2fl(y[index[v]])/480.0f );
407 vm_vec_scale( &tmp, 10.0f );
409 g3_rotate_faraway_vertex( verts[v], &tmp );
410 //g3_rotate_vertex( verts[v], &tmp );
411 g3_project_vertex( verts[v] );
413 verts[v]->r = verts[v]->g = verts[v]->b = (ubyte)(i2fl(l[index[v]])/31.0f);
417 //gr_set_color_fast( &nebula_color );
418 //gr_set_color( 0, 0, 0 );
419 g3_draw_poly(3, verts, TMAP_FLAG_RAMP | TMAP_FLAG_GOURAUD | TMAP_FLAG_NEBULA );
422 void nebula_draw_3d()
425 for (i=0; i<num_tris; i++ ) {
426 draw_tri_3d( tri[i][0], tri[i][1], tri[i][2] );
434 gr_set_color(0,0,0); // set color to black
435 gr_rect(0,0,SCREEN_W,SCREEN_H); // clear screen
438 light_add_directional( &Global_light_world, 0.1f, 1.0f, 1.0f, 1.0f );
442 g3_set_view_matrix(&ViewerPos, &ViewerOrient,ViewerZoom);
444 if ( View_mode == 0 ) {
448 gr_set_color_fast( &color_green );
449 gr_printf(10,10,"Nebula Editor. Mode :");
451 gr_printf(180, 10, "Multiple Vertex Selection Editing");
452 } else if (Vert_mode ==0 ) {
453 gr_printf(180,10,"Vertex Editing");
454 if(Current_point >= 0){
455 gr_printf(180, 20, "Current vertex intensity : %d\n", l[Current_point]);
457 } else if (Vert_mode ==1) {
458 gr_printf(180,10,"Face Editing");
461 gr_printf(20,30,"# Points:");
462 gr_printf(100,30, itoa(num_pts, blah, 10));
463 gr_printf(220,30,"# Polys:");
464 gr_printf(300,30, itoa(num_tris, blah, 10));
467 model_render( test_model, &ModelOrient, &ModelPos );
475 int get_closest(int mx, int my)
477 int i, closest = -1, cval = 100000;
479 for (i=0; i<num_pts; i++ ) {
486 dist = fl2i(fl_sqrt( i2fl((dx*dx)+(dy*dy)) ));
497 int get_closest_face(int mx, int my)
499 int i, closest = -1, cval = 100000;
501 for (i=0; i<num_tris; i++ ) {
505 dx = x[tri[i][0]] - mx;
506 dy = y[tri[i][0]] - my;
508 dx += x[tri[i][1]] - mx;
509 dy += y[tri[i][1]] - my;
511 dx += x[tri[i][2]] - mx;
512 dy += y[tri[i][2]] - my;
514 dist = fl2i(fl_sqrt( i2fl((dx*dx)+(dy*dy)) ));
516 dist += fl2i(fl_sqrt( i2fl((dx*dx)+(dy*dy)) ));
518 dx = x[tri[i][2]] - mx;
519 dy = y[tri[i][2]] - my;
520 dist += fl2i(fl_sqrt( i2fl((dx*dx)+(dy*dy)) ));
532 void delete_face(int i)
534 for (int j=i;j<num_tris;j++) {
535 memcpy(tri[j], tri[j+1], sizeof(int)*3);
540 void delete_vert(int i)
542 for (int j=0;j<num_tris;j++) {
543 if ((tri[j][0]==i)||(tri[j][1]==i)||(tri[j][2]==i)) {
548 for (j=0;j<num_tris;j++) {
549 if (tri[j][0]>i) tri[j][0]--;
550 if (tri[j][1]>i) tri[j][1]--;
551 if (tri[j][2]>i) tri[j][2]--;
553 for (j=i;j<num_pts;j++) {
561 int add_vert(int mx, int my)
571 void select_by_box(int x1, int y1, int x2, int y2)
583 for (int i=0;i<num_pts;i++) {
584 if ((x[i]<=x2) && (x[i]>=x1) &&
585 (y[i]<=y2) && (y[i]>=y1)) {
591 void sphericalize_nebula()
594 int px = SCREEN_W / (neb_w - 1);
595 int py = SCREEN_H / (neb_h - 1);
597 // flatten out the nebula so that it covers the entire sphere evenly
598 for(idx1=0; idx1<neb_w; idx1++){
599 for(idx2=0; idx2<neb_h; idx2++){
600 x[idx1+idx2*neb_w] = px * idx1;
601 y[idx1+idx2*neb_w] = py * idx2;
606 void controls_read_all(control_info * ci, float sim_time )
611 float temp = ci->heading;
612 float temp1 = ci->pitch;
613 memset( ci, 0, sizeof(control_info) );
619 kh = (key_down_timef(KEY_PAD6) - key_down_timef(KEY_PAD4))/8.0f;
622 else if (kh > 0.0f) {
623 if (ci->heading < 0.0f)
626 if (ci->heading > 0.0f)
630 kh = (key_down_timef(KEY_PAD8) - key_down_timef(KEY_PAD2))/8.0f;
633 else if (kh > 0.0f) {
634 if (ci->pitch < 0.0f)
637 if (ci->pitch > 0.0f)
641 ci->bank = (key_down_timef(KEY_PAD7) - key_down_timef(KEY_PAD9))*.75f;
642 ci->forward = key_down_timef(KEY_A) - key_down_timef(KEY_Z);
643 ci->sideways = key_down_timef(KEY_PAD3) - key_down_timef(KEY_PAD1);
644 ci->vertical = key_down_timef(KEY_PADPLUS) - key_down_timef(KEY_PADENTER);
651 while( (k = key_inkey()) != 0 ) {
652 //mprintf(( "Key = %x\n", k ));
653 if ( k == KEY_ESC ) {
660 Vert_mode = !Vert_mode;
666 if (Vert_mode==1) delete_face(Current_face);
667 else if (Vert_mode==0) {
668 delete_vert(Current_point);
673 scale_factor -= 0.05f;
674 mprintf(( "Scale = %.1f\n", scale_factor ));
679 scale_factor += 0.05f;
680 mprintf(( "Scale = %.1f\n", scale_factor ));
684 Sel_mode = !Sel_mode;
688 View_mode = !View_mode;
694 for (i=0;i<num_pts;i++) if (Selected[i]) {
699 } else if (Vert_mode==0) {
700 if ( Current_point > -1 ) {
701 if ( l[Current_point] > 0 ) {
705 } else if (Vert_mode ==1) {
706 if ( l[tri[Current_face][0]] > 0 ) {
707 l[tri[Current_face][0]]--;
709 if ( l[tri[Current_face][1]] > 0 ) {
710 l[tri[Current_face][1]]--;
712 if ( l[tri[Current_face][2]] > 0 ) {
713 l[tri[Current_face][2]]--;
721 for (i=0;i<num_pts;i++) if (Selected[i]) {
726 } else if (Vert_mode==0) {
727 if ( Current_point > -1 ) {
728 if ( l[Current_point] < 31 ) {
732 } else if (Vert_mode ==1) {
733 if ( l[tri[Current_face][0]] <31 ) {
734 l[tri[Current_face][0]]++;
736 if ( l[tri[Current_face][1]] <31) {
737 l[tri[Current_face][1]]++;
739 if ( l[tri[Current_face][2]] <31 ) {
740 l[tri[Current_face][2]]++;
754 sphericalize_nebula();
770 int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
775 float speed = 20.0f; // how fast viewer moves
777 // setup the fred exe directory so CFILE can init properly
779 char *c = GetCommandLine();
781 char *tok = strtok(c, " ");
787 cfile_init(__argv[0]);
788 os_init( "NebEdit", "NebEdit" ); //SCREEN_W, SCREEN_H );
789 palette_load_table( "gamepalette1-01.pcx" );
790 gr_init(GR_640, GR_SOFTWARE, 8);
793 Font1 = gr_init_font( "font01.vf" );
794 gr_init_alphacolor( &color_green, 0,255,0,255 );
796 test_model = model_load( "fighter01.pof", 0, NULL );
798 physics_init( &ViewerPhysics );
799 ViewerPhysics.flags |= PF_ACCELERATES | PF_SLIDE_ENABLED;
801 ViewerPhysics.max_vel.x = 2.0f*speed; //sideways
802 ViewerPhysics.max_vel.y = 2.0f*speed; //up/down
803 ViewerPhysics.max_vel.z = 2.0f*speed; //forward
804 ViewerPhysics.max_rear_vel = 2.0f*speed; //backward -- controlled seperately
806 memset( &ci, 0, sizeof(control_info) );
808 ModelOrient = vmd_identity_matrix;
809 ModelPos.x=0.0f; ModelPos.y = 0.0f; ModelPos.z = 0.0f;
811 ViewerOrient = vmd_identity_matrix;
812 ViewerPos.x=0.0f; ViewerPos.y = 0.0f; ViewerPos.z = -50.0f;
814 flFrametime = 0.033f;
816 t1 = timer_get_fixed_seconds();
820 int some_selected = 0;
823 some_selected = FALSE;
825 for (i=0;i<num_pts;i++) {
827 some_selected = TRUE;
833 mouse_get_pos( &Mouse_x, &Mouse_y );
835 if (Current_face==-1) {
836 Current_face = get_closest_face(Mouse_x, Mouse_y);
844 // Special mouse handlers for multiple selmode
845 if (mouse_down_count(LOWEST_MOUSE_BUTTON)) {
846 Orig_pos_x = Mouse_x;
847 Orig_pos_y = Mouse_y;
849 if (mouse_down(LOWEST_MOUSE_BUTTON)) {
850 for (i=0;i<num_pts;i++) {
852 x[i]+=Mouse_x - Orig_pos_x;
853 y[i]+=Mouse_y - Orig_pos_y;
856 Orig_pos_x = Mouse_x;
857 Orig_pos_y = Mouse_y;
859 if (mouse_down_count(MOUSE_RIGHT_BUTTON)) {
860 Orig_pos_x = Mouse_x;
861 Orig_pos_y = Mouse_y;
862 for (i=0;i<num_pts;i++) {
866 if (mouse_down(MOUSE_RIGHT_BUTTON)) {
871 if (mouse_up_count(MOUSE_RIGHT_BUTTON)) {
872 Draw_sel_box = FALSE;
875 select_by_box(Orig_pos_x, Orig_pos_y, End_pos_x, End_pos_y);
880 if ( mouse_down(LOWEST_MOUSE_BUTTON) ) {
883 x[Current_point] = Mouse_x;
884 y[Current_point] = Mouse_y;
885 } else if (Vert_mode==1) {
886 x[tri[Current_face][0]] += Mouse_x - Orig_pos_x;
887 y[tri[Current_face][0]] += Mouse_y - Orig_pos_y;
888 x[tri[Current_face][1]] += Mouse_x - Orig_pos_x;
889 y[tri[Current_face][1]] += Mouse_y - Orig_pos_y;
890 x[tri[Current_face][2]] += Mouse_x - Orig_pos_x;
891 y[tri[Current_face][2]] += Mouse_y - Orig_pos_y;
892 Orig_pos_x = Mouse_x;
893 Orig_pos_y = Mouse_y;
896 if (Vert_mode == 1) {
897 Current_face = get_closest_face(Mouse_x, Mouse_y);
898 Orig_pos_x = Mouse_x;
899 Orig_pos_y = Mouse_y;
902 Current_point = get_closest(Mouse_x, Mouse_y);
903 mouse_set_pos(x[Current_point], y[Current_point]);
908 if ( mouse_up_count(LOWEST_MOUSE_BUTTON)) {
909 //Current_point = -1;
914 if ( mouse_up_count(MOUSE_RIGHT_BUTTON) ) {
916 Current_point = add_vert(Mouse_x, Mouse_y);
917 } else if (Vert_mode==1) {
918 if ((num_tris<MAX_TRIS-1)) {
919 tri[num_tris][Which_vert] = get_closest(Mouse_x, Mouse_y);
929 controls_read_all(&ci, flFrametime );
930 physics_read_flying_controls( &ViewerOrient, &ViewerPhysics, &ci, flFrametime );
931 physics_sim(&ViewerPos, &ViewerOrient, &ViewerPhysics, flFrametime );
935 t2 = timer_get_fixed_seconds();
937 flFrametime = f2fl(t2 - t1);
948 // Stub functions and variables.
949 // These do nothing but are needed to prevent link errors.
950 void demo_set_playback_filter() {}
952 void freespace_menu_background()
969 vector Dead_player_last_vel;