home *** CD-ROM | disk | FTP | other *** search
/ Superpower (Alt) / SUPERPOWER.iso / q / source / quakeed.m < prev    next >
Encoding:
Text File  |  1996-08-08  |  17.5 KB  |  1,027 lines

  1.  
  2. #import "qedefs.h"
  3.  
  4. id    quakeed_i;
  5. id    entclasses_i;
  6.  
  7. id    g_cmd_out_i;
  8.  
  9. BOOL    autodirty;
  10. BOOL    filter_light, filter_path, filter_entities;
  11. BOOL    filter_clip_brushes, filter_water_brushes, filter_world;
  12.  
  13. BOOL    running;
  14.  
  15. int bsppid;
  16.  
  17. #if 0
  18. // example command strings
  19.  
  20. char    *fullviscmd = "rsh satan \"/LocalApps/qbsp $1 $2 ; /LocalApps/light $2 ; /LocalApps/vis $2\"";
  21. char    *fastviscmd = "rsh satan \"/LocalApps/qbsp $1 $2 ; /LocalApps/light $2 ; /LocalApps/vis -fast $2\"";
  22. char    *noviscmd = "rsh satan \"/LocalApps/qbsp $1 $2 ; /LocalApps/light $2\"";
  23. char    *relightcmd = "rsh satan \"/LocalApps/light $2\"";
  24. char    *leakcmd = "rsh satan \"/LocalApps/qbsp -mark -notjunc $1 $2\"";
  25. #endif
  26.  
  27. void NopSound (void)
  28. {
  29.     NXBeep ();
  30. }
  31.  
  32. UserPath    *upath;
  33.  
  34.  
  35. void My_Malloc_Error (int code)
  36. {
  37. // recursive toast    Error ("Malloc error: %i\n", code);
  38.     write (1, "malloc error!\n", strlen("malloc error!\n")+1);
  39. }
  40.  
  41. /*
  42. ===============
  43. AutoSave
  44.  
  45. Every five minutes, save a modified map
  46. ===============
  47. */
  48. void AutoSave(DPSTimedEntry tag, double now, void *userData)
  49. {
  50. // automatic backup
  51.     if (autodirty)
  52.     {
  53.         autodirty = NO;
  54.         [map_i writeMapFile: FN_AUTOSAVE useRegion: NO];
  55.     }
  56.     [map_i writeStats];
  57. }
  58.  
  59.  
  60. void DisplayCmdOutput (void)
  61. {
  62.     char    *buffer;
  63.  
  64.     LoadFile (FN_CMDOUT, (void **)&buffer);
  65.     unlink (FN_CMDOUT);
  66.     [project_i addToOutput:buffer];
  67.     free (buffer);
  68.  
  69.     if ([preferences_i getShowBSP])
  70.         [inspcontrol_i changeInspectorTo:i_output];
  71.  
  72.     [preferences_i playBspSound];        
  73.     
  74.     NXPing ();
  75. }
  76.  
  77. /*
  78. ===============
  79. CheckCmdDone
  80.  
  81. See if the BSP is done
  82. ===============
  83. */
  84. DPSTimedEntry    cmdte;
  85. void CheckCmdDone(DPSTimedEntry tag, double now, void *userData)
  86. {
  87.     union wait statusp;
  88.     struct rusage rusage;
  89.     
  90.     if (!wait4(bsppid, &statusp, WNOHANG, &rusage))
  91.         return;
  92.     DisplayCmdOutput ();
  93.     bsppid = 0;
  94.     DPSRemoveTimedEntry( cmdte );    
  95. }
  96.  
  97. //============================================================================
  98.  
  99. @implementation QuakeEd
  100.  
  101. /*
  102. ===============
  103. init
  104. ===============
  105. */
  106. - initContent:(const NXRect *)contentRect
  107. style:(int)aStyle
  108. backing:(int)backingType
  109. buttonMask:(int)mask
  110. defer:(BOOL)flag
  111. {
  112.     [super initContent:contentRect
  113.         style:aStyle
  114.         backing:backingType
  115.         buttonMask:mask
  116.         defer:flag];
  117.  
  118.     [self addToEventMask:
  119.         NX_RMOUSEDRAGGEDMASK|NX_LMOUSEDRAGGEDMASK];    
  120.     
  121.     malloc_error(My_Malloc_Error);
  122.     
  123.     quakeed_i = self;
  124.     dirty = autodirty = NO;
  125.  
  126.     DPSAddTimedEntry(5*60, AutoSave, self, NX_BASETHRESHOLD);
  127.  
  128.     upath = newUserPath ();
  129.  
  130.     return self;
  131. }
  132.  
  133. - setDefaultFilename
  134. {    
  135.     strcpy (filename, FN_TEMPSAVE);
  136.     [self setTitleAsFilename:filename];
  137.     
  138.     return self;
  139. }
  140.  
  141.  
  142. - (BOOL)dirty
  143. {
  144.     return dirty;
  145. }
  146.  
  147. /*
  148. ===============================================================================
  149.  
  150.                 DISPLAY UPDATING (handles both camera and XYView)
  151.  
  152. ===============================================================================
  153. */
  154.  
  155. BOOL    updateinflight;
  156.  
  157. BOOL    clearinstance;
  158.  
  159. BOOL    updatexy;
  160. BOOL    updatez;
  161. BOOL    updatecamera;
  162.  
  163. void postappdefined (void)
  164. {
  165.     NXEvent ev;
  166.  
  167.     if (updateinflight)
  168.         return;
  169.             
  170. // post an event at the end of the que
  171.     ev.type = NX_APPDEFINED;
  172.     if (DPSPostEvent(&ev, 0) == -1)
  173.         printf ("WARNING: DPSPostEvent: full\n");
  174. //printf ("posted\n");
  175.     updateinflight = YES;
  176. }
  177.  
  178.  
  179. int    c_updateall;
  180. - updateAll            // when a model has been changed
  181. {
  182.     updatecamera = updatexy = updatez = YES;
  183.     c_updateall++;
  184.     postappdefined ();
  185.     return self;
  186. }
  187.  
  188. - updateAll:sender
  189. {
  190.     [self updateAll];
  191.     return self;
  192. }
  193.  
  194. - updateCamera        // when the camera has moved
  195. {
  196.     updatecamera = YES;
  197.     clearinstance = YES;
  198.     
  199.     postappdefined ();
  200.     return self;
  201. }
  202.  
  203. - updateXY
  204. {
  205.     updatexy = YES;
  206.     postappdefined ();
  207.     return self;
  208. }
  209.  
  210. - updateZ
  211. {
  212.     updatez = YES;
  213.     postappdefined ();
  214.     return self;
  215. }
  216.  
  217.  
  218. - newinstance
  219. {
  220.     clearinstance = YES;
  221.     return self;
  222. }
  223.  
  224. - redrawInstance
  225. {
  226.     clearinstance = YES;
  227.     [self flushWindow];
  228.     return self;
  229. }
  230.  
  231. /*
  232. ===============
  233. flushWindow
  234.  
  235. instance draw the brush after each flush
  236. ===============
  237. */
  238. -flushWindow
  239. {
  240.     [super flushWindow];
  241.     
  242.     if (!running || in_error)
  243.         return self;        // don't lock focus before nib is finished loading
  244.         
  245.     if (_flushDisabled)
  246.         return self;
  247.         
  248.     [cameraview_i lockFocus];    
  249.     if (clearinstance)
  250.     {
  251.         PSnewinstance ();
  252.         clearinstance = NO;
  253.     }
  254.  
  255.     PSsetinstance (1);
  256.     linestart (0,0,0);
  257.     [map_i makeSelectedPerform: @selector(CameraDrawSelf)];
  258.     [clipper_i cameraDrawSelf];
  259.     lineflush ();
  260.     PSsetinstance (0);
  261.     [cameraview_i unlockFocus];    
  262.  
  263.     [xyview_i lockFocus];
  264.     PSsetinstance (1);
  265.     linestart (0,0,0);
  266.     [map_i makeSelectedPerform: @selector(XYDrawSelf)];
  267.     lineflush ();
  268.     [cameraview_i XYDrawSelf];
  269.     [zview_i XYDrawSelf];
  270.     [clipper_i XYDrawSelf];
  271.     PSsetinstance (0);
  272.     [xyview_i unlockFocus];
  273.  
  274.     [zview_i lockFocus];
  275.     PSsetinstance (1);
  276.     [map_i makeSelectedPerform: @selector(ZDrawSelf)];
  277.     [cameraview_i ZDrawSelf];
  278.     [clipper_i ZDrawSelf];
  279.     PSsetinstance (0);
  280.     [zview_i unlockFocus];
  281.  
  282.     return self;
  283. }
  284.  
  285.  
  286. /*
  287. ==============================================================================
  288.  
  289. App delegate methods
  290.  
  291. ==============================================================================
  292. */
  293.  
  294. - applicationDefined:(NXEvent *)theEvent
  295. {
  296.     NXEvent        ev, *evp;
  297.     
  298.     updateinflight = NO;
  299.  
  300. //printf ("serviced\n");
  301.     
  302. // update screen    
  303.     evp = [NXApp peekNextEvent:-1 into:&ev];
  304.     if (evp)
  305.     {
  306.         postappdefined();
  307.         return self;
  308.     }
  309.  
  310.         
  311.     [self disableFlushWindow];    
  312.  
  313.     if ([map_i count] != [entitycount_i intValue])
  314.         [entitycount_i setIntValue: [map_i count]];
  315.     if ([[map_i currentEntity] count] != [brushcount_i intValue])
  316.         [brushcount_i setIntValue: [[map_i currentEntity] count]];
  317.         
  318.     if (updatecamera)
  319.         [cameraview_i display];
  320.     if (updatexy)
  321.         [xyview_i display];
  322.     if (updatez)
  323.         [zview_i display];
  324.  
  325.     updatecamera = updatexy = updatez = NO;
  326.  
  327.     [self reenableFlushWindow];
  328.     [self flushWindow];
  329.     
  330. //    NXPing ();
  331.     
  332.     return self;
  333. }
  334.  
  335. - appDidInit:sender
  336. {
  337.     NXScreen    const *screens;
  338.     int            screencount;
  339.     
  340.     running = YES;
  341.     g_cmd_out_i = cmd_out_i;    // for qprintf
  342.  
  343.     [preferences_i    readDefaults];
  344.     [project_i        initProject];
  345.  
  346.     [xyview_i setModeRadio: xy_drawmode_i];    // because xy view is inside
  347.                                             // scrollview and can't be
  348.                                             // connected directly in IB
  349.     
  350.     [self setFrameAutosaveName:"EditorWinFrame"];
  351.     [self clear: self];
  352.  
  353. // go to my second monitor
  354.     [NXApp getScreens:&screens count:&screencount];
  355.     if (screencount == 2)
  356.         [self moveTopLeftTo:0 : screens[1].screenBounds.size.height
  357.         screen:screens+1];
  358.     
  359.     [self makeKeyAndOrderFront: self];
  360.  
  361. //[self doOpen: "/raid/quake/id1_/maps/amlev1.map"];    // DEBUG
  362.     [map_i newMap];
  363.         
  364.     qprintf ("ready.");
  365.  
  366. //malloc_debug(-1);        // DEBUG
  367.     
  368.     return self;
  369. }
  370.  
  371. - appWillTerminate:sender
  372. {
  373. // FIXME: save dialog if dirty
  374.     return self;
  375. }
  376.  
  377.  
  378. //===========================================================================
  379.  
  380. - textCommand: sender
  381. {
  382.     char    const *t;
  383.     
  384.     t = [sender stringValue];
  385.     
  386.     if (!strcmp (t, "texname"))
  387.     {
  388.         texturedef_t    *td;
  389.         id                b;
  390.         
  391.         b = [map_i selectedBrush];
  392.         if (!b)
  393.         {
  394.             qprintf ("nothing selected");
  395.             return self;
  396.         }
  397.         td = [b texturedef];
  398.         qprintf (td->texture);
  399.         return self;
  400.     }
  401.     else
  402.         qprintf ("Unknown command\n");
  403.     return self;
  404. }
  405.  
  406.  
  407. - openProject:sender
  408. {
  409.     [project_i    openProject];
  410.     return self;
  411. }
  412.  
  413.  
  414. - clear: sender
  415. {    
  416.     [map_i newMap];
  417.  
  418.     [self updateAll];
  419.     [regionbutton_i setIntValue: 0];
  420.     [self setDefaultFilename];
  421.  
  422.     return self;
  423. }
  424.  
  425.  
  426. - centerCamera: sender
  427. {
  428.     NXRect    sbounds;
  429.     
  430.     [[xyview_i superview] getBounds: &sbounds];
  431.     
  432.     sbounds.origin.x += sbounds.size.width/2;
  433.     sbounds.origin.y += sbounds.size.height/2;
  434.     
  435.     [cameraview_i setXYOrigin: &sbounds.origin];
  436.     [self updateAll];
  437.     
  438.     return self;
  439. }
  440.  
  441. - centerZChecker: sender
  442. {
  443.     NXRect    sbounds;
  444.     
  445.     [[xyview_i superview] getBounds: &sbounds];
  446.     
  447.     sbounds.origin.x += sbounds.size.width/2;
  448.     sbounds.origin.y += sbounds.size.height/2;
  449.     
  450.     [zview_i setPoint: &sbounds.origin];
  451.     [self updateAll];
  452.     
  453.     return self;
  454. }
  455.  
  456. - changeXYLookUp: sender
  457. {
  458.     if ([sender intValue])
  459.     {
  460.         xy_viewnormal[2] = 1;
  461.     }
  462.     else
  463.     {
  464.         xy_viewnormal[2] = -1;
  465.     }
  466.     [self updateAll];
  467.     return self;
  468. }
  469.  
  470. /*
  471. ==============================================================================
  472.  
  473. REGION MODIFICATION
  474.  
  475. ==============================================================================
  476. */
  477.  
  478.  
  479. /*
  480. ==================
  481. applyRegion:
  482. ==================
  483. */
  484. - applyRegion: sender
  485. {
  486.     filter_clip_brushes = [filter_clip_i intValue];
  487.     filter_water_brushes = [filter_water_i intValue];
  488.     filter_light = [filter_light_i intValue];
  489.     filter_path = [filter_path_i intValue];
  490.     filter_entities = [filter_entities_i intValue];
  491.     filter_world = [filter_world_i intValue];
  492.  
  493.     if (![regionbutton_i intValue])
  494.     {
  495.         region_min[0] = region_min[1] = region_min[2] = -9999;
  496.         region_max[0] = region_max[1] = region_max[2] = 9999;
  497.     }
  498.  
  499.     [map_i makeGlobalPerform: @selector(newRegion)];
  500.     
  501.     [self updateAll];
  502.  
  503.     return self;
  504. }
  505.  
  506. - setBrushRegion: sender
  507. {
  508.     id        b;
  509.  
  510. // get the bounds of the current selection
  511.     
  512.     if ([map_i numSelected] != 1)
  513.     {
  514.         qprintf ("must have a single brush selected");
  515.         return self;
  516.     } 
  517.  
  518.     b = [map_i selectedBrush];
  519.     [b getMins: region_min maxs: region_max];
  520.     [b remove];
  521.  
  522. // turn region on
  523.     [regionbutton_i setIntValue: 1];
  524.     [self applyRegion: self];
  525.     
  526.     return self;
  527. }
  528.  
  529. - setXYRegion: sender
  530. {
  531.     NXRect    bounds;
  532.     
  533. // get xy size
  534.     [[xyview_i superview] getBounds: &bounds];
  535.  
  536.     region_min[0] = bounds.origin.x;
  537.     region_min[1] = bounds.origin.y;
  538.     region_min[2] = -99999;
  539.     region_max[0] = bounds.origin.x + bounds.size.width;
  540.     region_max[1] = bounds.origin.y + bounds.size.height;
  541.     region_max[2] = 99999;
  542.     
  543. // turn region on
  544.     [regionbutton_i setIntValue: 1];
  545.     [self applyRegion: self];
  546.     
  547.     return self;
  548. }
  549.  
  550. //
  551. // UI querie for other objects
  552. //
  553. - (BOOL)showCoordinates
  554. {
  555.     return [show_coordinates_i intValue];
  556. }
  557.  
  558. - (BOOL)showNames
  559. {
  560.     return [show_names_i intValue];
  561. }
  562.  
  563.  
  564. /*
  565. ==============================================================================
  566.  
  567. BSP PROCESSING
  568.  
  569. ==============================================================================
  570. */
  571.  
  572. void ExpandCommand (char *in, char *out, char *src, char *dest)
  573. {
  574.     while (*in)
  575.     {
  576.         if (in[0] == '$')
  577.         {
  578.             if (in[1] == '1')
  579.             {
  580.                 strcpy (out, src);
  581.                 out += strlen(src);
  582.             }
  583.             else if (in[1] == '2')
  584.             {
  585.                 strcpy (out, dest);
  586.                 out += strlen(dest);
  587.             }
  588.             in += 2;            
  589.             continue;
  590.         }
  591.         *out++ = *in++;
  592.     }
  593.     *out = 0;
  594. }
  595.  
  596.  
  597. /*
  598. =============
  599. saveBSP
  600. =============
  601. */
  602. - saveBSP:(char *)cmdline dialog:(BOOL)wt
  603. {
  604.     char    expandedcmd[1024];
  605.     char    mappath[1024];
  606.     char    bsppath[1024];
  607.     int        oldLightFilter;
  608.     int        oldPathFilter;
  609.     char    *destdir;
  610.     
  611.     if (bsppid)
  612.     {
  613.         NXBeep();
  614.         return self;
  615.     }
  616.  
  617. //
  618. // turn off the filters so all entities get saved
  619. //
  620.     oldLightFilter = [filter_light_i intValue];
  621.     oldPathFilter = [filter_path_i intValue];
  622.     [filter_light_i setIntValue:0];
  623.     [filter_path_i setIntValue:0];
  624.     [self applyRegion: self];
  625.     
  626.     if ([regionbutton_i intValue])
  627.     {
  628.         strcpy (mappath, filename);
  629.         StripExtension (mappath);
  630.         strcat (mappath, ".reg");
  631.         [map_i writeMapFile: mappath useRegion: YES];
  632.         wt = YES;        // allways pop the dialog on region ops
  633.     }
  634.     else
  635.         strcpy (mappath, filename);
  636.         
  637. // save the entire thing, just in case there is a problem
  638.     [self save: self];
  639.  
  640.     [filter_light_i setIntValue:oldLightFilter];
  641.     [filter_path_i setIntValue:oldPathFilter];
  642.     [self applyRegion: self];
  643.  
  644. //
  645. // write the command to the bsp host
  646. //    
  647.     destdir = [project_i getFinalMapDirectory];
  648.  
  649.     strcpy (bsppath, destdir);
  650.     strcat (bsppath, "/");
  651.     ExtractFileBase (mappath, bsppath + strlen(bsppath));
  652.     strcat (bsppath, ".bsp");
  653.     
  654.     ExpandCommand (cmdline, expandedcmd, mappath, bsppath);
  655.  
  656.     strcat (expandedcmd, " > ");
  657.     strcat (expandedcmd, FN_CMDOUT);
  658.     strcat (expandedcmd, "\n");
  659.     printf ("system: %s", expandedcmd);
  660.  
  661.     [project_i addToOutput: "\n\n========= BUSY =========\n\n"];
  662.     [project_i addToOutput: expandedcmd];
  663.  
  664.     if ([preferences_i getShowBSP])
  665.         [inspcontrol_i changeInspectorTo:i_output];
  666.     
  667.     if (wt)
  668.     {
  669.         id        panel;
  670.         
  671.         panel = NXGetAlertPanel("BSP In Progress",expandedcmd,NULL,NULL,NULL);
  672.         [panel makeKeyAndOrderFront:NULL];
  673.         system(expandedcmd);
  674.         NXFreeAlertPanel(panel);
  675.         [self makeKeyAndOrderFront:NULL];
  676.         DisplayCmdOutput ();
  677.     }
  678.     else
  679.     {
  680.         cmdte = DPSAddTimedEntry(1, CheckCmdDone, self, NX_BASETHRESHOLD);
  681.         if (! (bsppid = fork ()) )
  682.         {
  683.             system (expandedcmd);
  684.             exit (0);
  685.         }
  686.     }
  687.     
  688.     return self;
  689. }
  690.  
  691.  
  692. - BSP_Full: sender
  693. {
  694.     [self saveBSP:[project_i getFullVisCmd] dialog: NO];
  695.     return self;
  696. }
  697.  
  698. - BSP_FastVis: sender
  699. {
  700.     [self saveBSP:[project_i getFastVisCmd] dialog: NO];
  701.     return self;
  702. }
  703.  
  704. - BSP_NoVis: sender
  705. {
  706.     [self saveBSP:[project_i getNoVisCmd] dialog: NO];
  707.     return self;
  708. }
  709.  
  710. - BSP_relight: sender
  711. {
  712.     [self saveBSP:[project_i getRelightCmd] dialog: NO];
  713.     return self;
  714. }
  715.  
  716. - BSP_entities: sender
  717. {
  718.     [self saveBSP:[project_i getEntitiesCmd] dialog: NO];
  719.     return self;
  720. }
  721.  
  722. - BSP_stop: sender
  723. {
  724.     if (!bsppid)
  725.     {
  726.         NXBeep();
  727.         return self;
  728.     }
  729.     
  730.     kill (bsppid, 9);
  731.     CheckCmdDone (cmdte, 0, NULL);
  732.     [project_i addToOutput: "\n\n========= STOPPED =========\n\n"];
  733.     
  734.     return self;
  735. }
  736.  
  737.  
  738.  
  739. /*
  740. ==============
  741. doOpen:
  742.  
  743. Called by open or the project panel
  744. ==============
  745. */
  746. - doOpen: (char *)fname;
  747. {    
  748.     strcpy (filename, fname);
  749.     
  750.     [map_i readMapFile:filename];
  751.     
  752.     [regionbutton_i setIntValue: 0];
  753.     [self setTitleAsFilename:fname];
  754.     [self updateAll];
  755.  
  756.     qprintf ("%s loaded\n", fname);
  757.     
  758.     return self;
  759. }
  760.  
  761.  
  762. /*
  763. ==============
  764. open
  765. ==============
  766. */
  767. - open: sender;
  768. {
  769.     id            openpanel;
  770.     static char    *suffixlist[] = {"map", 0};
  771.  
  772.     openpanel = [OpenPanel new];
  773.  
  774.     if ( [openpanel 
  775.             runModalForDirectory: [project_i getMapDirectory] 
  776.             file: ""
  777.             types: suffixlist] != NX_OKTAG)
  778.         return self;
  779.  
  780.     [self doOpen: (char *)[openpanel filename]];
  781.     
  782.     return self;
  783. }
  784.  
  785.  
  786. /*
  787. ==============
  788. save:
  789. ==============
  790. */
  791. - save: sender;
  792. {
  793.     char        backup[1024];
  794.  
  795. // force a name change if using tempname
  796.     if (!strcmp (filename, FN_TEMPSAVE) )
  797.         return [self saveAs: self];
  798.         
  799.     dirty = autodirty = NO;
  800.  
  801.     strcpy (backup, filename);
  802.     StripExtension (backup);
  803.     strcat (backup, ".bak");
  804.     rename (filename, backup);        // copy old to .bak
  805.  
  806.     [map_i writeMapFile: filename useRegion: NO];
  807.  
  808.     return self;
  809. }
  810.  
  811.  
  812. /*
  813. ==============
  814. saveAs
  815. ==============
  816. */
  817. - saveAs: sender;
  818. {
  819.     id        panel_i;
  820.     char    dir[1024];
  821.     
  822.     panel_i = [SavePanel new];
  823.     ExtractFileBase (filename, dir);
  824.     [panel_i setRequiredFileType: "map"];
  825.     if ( [panel_i runModalForDirectory:[project_i getMapDirectory] file: dir] != NX_OKTAG)
  826.         return self;
  827.     
  828.     strcpy (filename, [panel_i filename]);
  829.     
  830.     [self setTitleAsFilename:filename];
  831.     
  832.     [self save: self];    
  833.     
  834.     return self;
  835. }
  836.  
  837.  
  838. /*
  839. ===============================================================================
  840.  
  841.                         OTHER METHODS
  842.  
  843. ===============================================================================
  844. */
  845.  
  846.  
  847. //
  848. //    AJR - added this for Project info
  849. //
  850. - (char *)currentFilename
  851. {
  852.     return filename;
  853. }
  854.  
  855. - deselect: sender
  856. {
  857.     if ([clipper_i hide])    // first click hides clipper only
  858.         return [self updateAll];
  859.  
  860.     [map_i setCurrentEntity: [map_i objectAt: 0]];    // make world selected
  861.     [map_i makeSelectedPerform: @selector(deselect)];
  862.     [self updateAll];
  863.     
  864.     return self;
  865. }
  866.  
  867.  
  868. /*
  869. ===============
  870. keyDown
  871. ===============
  872. */
  873.  
  874. #define    KEY_RIGHTARROW        0xae
  875. #define    KEY_LEFTARROW        0xac
  876. #define    KEY_UPARROW            0xad
  877. #define    KEY_DOWNARROW        0xaf
  878.  
  879. - keyDown:(NXEvent *)theEvent
  880. {
  881.     int        ch;
  882.     
  883. // function keys
  884.     switch (theEvent->data.key.keyCode)
  885.     {
  886.     case 60:    // F2
  887.         [cameraview_i setDrawMode: dr_wire];
  888.         qprintf ("wire draw mode");
  889.         return self;
  890.     case 61:    // F3
  891.         [cameraview_i setDrawMode: dr_flat];
  892.         qprintf ("flat draw mode");
  893.         return self;
  894.     case 62:    // F4
  895.         [cameraview_i setDrawMode: dr_texture];
  896.         qprintf ("texture draw mode");
  897.         return self;
  898.  
  899.     case 63:    // F5
  900.         [xyview_i setDrawMode: dr_wire];
  901.         qprintf ("wire draw mode");
  902.         return self;
  903.     case 64:    // F6
  904.         qprintf ("texture draw mode");
  905.         return self;
  906.         
  907.     case 66:    // F8
  908.         [cameraview_i homeView: self];
  909.         return self;
  910.         
  911.     case 88:    // F12
  912.         [map_i subtractSelection: self];
  913.         return self;
  914.  
  915.     case 106:    // page up
  916.         [cameraview_i upFloor: self];
  917.         return self;
  918.         
  919.     case 107:    // page down
  920.         [cameraview_i downFloor: self];
  921.         return self;
  922.         
  923.     case 109:    // end
  924.         [self deselect: self];
  925.         return self;
  926.     }
  927.  
  928. // portable things
  929.     ch = tolower(theEvent->data.key.charCode);
  930.         
  931.     switch (ch)
  932.     {
  933.     case KEY_RIGHTARROW:
  934.     case KEY_LEFTARROW:
  935.     case KEY_UPARROW:
  936.     case KEY_DOWNARROW:
  937.     case 'a':
  938.     case 'z':
  939.     case 'd':
  940.     case 'c':
  941.     case '.':
  942.     case ',':
  943.         [cameraview_i _keyDown: theEvent];
  944.         break;
  945.  
  946.     case 27:    // escape
  947.         autodirty = dirty = YES;
  948.         [self deselect: self];
  949.         return self;
  950.         
  951.     case 127:    // delete
  952.         autodirty = dirty = YES;
  953.         [map_i makeSelectedPerform: @selector(remove)];
  954.         [clipper_i hide];
  955.         [self updateAll];
  956.         break;
  957.  
  958.     case '/':
  959.         [clipper_i flipNormal];
  960.         [self updateAll];
  961.         break;
  962.         
  963.     case 13:    // enter
  964.         [clipper_i carve];
  965.         [self updateAll];
  966.         qprintf ("carved brush");
  967.         break;
  968.         
  969.     case ' ':
  970.         [map_i cloneSelection: self];
  971.         break;
  972.         
  973.  
  974. //
  975. // move selection keys
  976. //        
  977.     case '2':
  978.         VectorCopy (vec3_origin, sb_translate);
  979.         sb_translate[1] = -[xyview_i gridsize];
  980.         [map_i makeSelectedPerform: @selector(translate)];
  981.         [self updateAll];
  982.         break;
  983.     case '8':
  984.         VectorCopy (vec3_origin, sb_translate);
  985.         sb_translate[1] = [xyview_i gridsize];
  986.         [map_i makeSelectedPerform: @selector(translate)];
  987.         [self updateAll];
  988.         break;
  989.  
  990.     case '4':
  991.         VectorCopy (vec3_origin, sb_translate);
  992.         sb_translate[0] = -[xyview_i gridsize];
  993.         [map_i makeSelectedPerform: @selector(translate)];
  994.         [self updateAll];
  995.         break;
  996.     case '6':
  997.         VectorCopy (vec3_origin, sb_translate);
  998.         sb_translate[0] = [xyview_i gridsize];
  999.         [map_i makeSelectedPerform: @selector(translate)];
  1000.         [self updateAll];
  1001.         break;
  1002.  
  1003.     case '-':
  1004.         VectorCopy (vec3_origin, sb_translate);
  1005.         sb_translate[2] = -[xyview_i gridsize];
  1006.         [map_i makeSelectedPerform: @selector(translate)];
  1007.         [self updateAll];
  1008.         break;
  1009.     case '+':
  1010.         VectorCopy (vec3_origin, sb_translate);
  1011.         sb_translate[2] = [xyview_i gridsize];
  1012.         [map_i makeSelectedPerform: @selector(translate)];
  1013.         [self updateAll];
  1014.         break;
  1015.  
  1016.     default:
  1017.         qprintf ("undefined keypress");
  1018.         NopSound ();
  1019.         break;
  1020.     }
  1021.  
  1022.     return self;
  1023. }
  1024.  
  1025.  
  1026. @end
  1027.