XYView.m 25 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385
  1. #import "qedefs.h"
  2. id xyview_i;
  3. id scalemenu_i, gridmenu_i, scrollview_i, gridbutton_i, scalebutton_i;
  4. vec3_t xy_viewnormal; // v_forward for xy view
  5. float xy_viewdist; // clip behind this plane
  6. @implementation XYView
  7. /*
  8. ==================
  9. initFrame:
  10. ==================
  11. */
  12. - initFrame:(const NXRect *)frameRect
  13. {
  14. [super initFrame:frameRect];
  15. [self allocateGState];
  16. NXSetRect (&realbounds, 0,0,0,0);
  17. gridsize = 16;
  18. scale = 1.0;
  19. xyview_i = self;
  20. xy_viewnormal[2] = -1;
  21. xy_viewdist = -1024;
  22. //
  23. // initialize the pop up menus
  24. //
  25. scalemenu_i = [[PopUpList alloc] init];
  26. [scalemenu_i setTarget: self];
  27. [scalemenu_i setAction: @selector(scaleMenuTarget:)];
  28. [scalemenu_i addItem: "12.5%"];
  29. [scalemenu_i addItem: "25%"];
  30. [scalemenu_i addItem: "50%"];
  31. [scalemenu_i addItem: "75%"];
  32. [scalemenu_i addItem: "100%"];
  33. [scalemenu_i addItem: "200%"];
  34. [scalemenu_i addItem: "300%"];
  35. [[scalemenu_i itemList] selectCellAt: 4 : 0];
  36. scalebutton_i = NXCreatePopUpListButton(scalemenu_i);
  37. gridmenu_i = [[PopUpList alloc] init];
  38. [gridmenu_i setTarget: self];
  39. [gridmenu_i setAction: @selector(gridMenuTarget:)];
  40. [gridmenu_i addItem: "grid 1"];
  41. [gridmenu_i addItem: "grid 2"];
  42. [gridmenu_i addItem: "grid 4"];
  43. [gridmenu_i addItem: "grid 8"];
  44. [gridmenu_i addItem: "grid 16"];
  45. [gridmenu_i addItem: "grid 32"];
  46. [gridmenu_i addItem: "grid 64"];
  47. [[gridmenu_i itemList] selectCellAt: 4 : 0];
  48. gridbutton_i = NXCreatePopUpListButton(gridmenu_i);
  49. // initialize the scroll view
  50. scrollview_i = [[PopScrollView alloc]
  51. initFrame: frameRect
  52. button1: scalebutton_i
  53. button2: gridbutton_i
  54. ];
  55. [scrollview_i setLineScroll: 64];
  56. [scrollview_i setAutosizing: NX_WIDTHSIZABLE | NX_HEIGHTSIZABLE];
  57. // link objects together
  58. [[scrollview_i setDocView: self] free];
  59. return scrollview_i;
  60. }
  61. - (BOOL)acceptsFirstResponder
  62. {
  63. return YES;
  64. }
  65. - setModeRadio: m
  66. { // this should be set from IB, but because I toss myself in a popscrollview
  67. // the connection gets lost
  68. mode_radio_i = m;
  69. [mode_radio_i setTarget: self];
  70. [mode_radio_i setAction: @selector(drawMode:)];
  71. return self;
  72. }
  73. - drawMode: sender
  74. {
  75. drawmode = [sender selectedCol];
  76. [quakeed_i updateXY];
  77. return self;
  78. }
  79. - setDrawMode: (drawmode_t)mode
  80. {
  81. drawmode = mode;
  82. [mode_radio_i selectCellAt:0: mode];
  83. [quakeed_i updateXY];
  84. return self;
  85. }
  86. - (float)currentScale
  87. {
  88. return scale;
  89. }
  90. /*
  91. ===================
  92. setOrigin:scale:
  93. ===================
  94. */
  95. - setOrigin: (NXPoint *)pt scale: (float)sc
  96. {
  97. NXRect sframe;
  98. NXRect newbounds;
  99. //
  100. // calculate the area visible in the cliprect
  101. //
  102. scale = sc;
  103. [superview getFrame: &sframe];
  104. [superview getFrame: &newbounds];
  105. newbounds.origin = *pt;
  106. newbounds.size.width /= scale;
  107. newbounds.size.height /= scale;
  108. //
  109. // union with the realbounds
  110. //
  111. NXUnionRect (&realbounds, &newbounds);
  112. //
  113. // redisplay everything
  114. //
  115. [quakeed_i disableDisplay];
  116. //
  117. // size this view
  118. //
  119. [self sizeTo: newbounds.size.width : newbounds.size.height];
  120. [self setDrawOrigin: newbounds.origin.x : newbounds.origin.y];
  121. [self moveTo: newbounds.origin.x : newbounds.origin.y];
  122. //
  123. // scroll and scale the clip view
  124. //
  125. [superview setDrawSize
  126. : sframe.size.width/scale
  127. : sframe.size.height/scale];
  128. [superview setDrawOrigin: pt->x : pt->y];
  129. [quakeed_i reenableDisplay];
  130. [scrollview_i display];
  131. return self;
  132. }
  133. - centerOn: (vec3_t)org
  134. {
  135. NXRect sbounds;
  136. NXPoint mid, delta;
  137. [[xyview_i superview] getBounds: &sbounds];
  138. mid.x = sbounds.origin.x + sbounds.size.width/2;
  139. mid.y = sbounds.origin.y + sbounds.size.height/2;
  140. delta.x = org[0] - mid.x;
  141. delta.y = org[1] - mid.y;
  142. sbounds.origin.x += delta.x;
  143. sbounds.origin.y += delta.y;
  144. [self setOrigin: &sbounds.origin scale: scale];
  145. return self;
  146. }
  147. /*
  148. ==================
  149. newSuperBounds
  150. When superview is resized
  151. ==================
  152. */
  153. - newSuperBounds
  154. {
  155. NXRect r;
  156. [superview getBounds: &r];
  157. [self newRealBounds: &r];
  158. return self;
  159. }
  160. /*
  161. ===================
  162. newRealBounds
  163. Called when the realbounds rectangle is changed.
  164. Should only change the scroll bars, not cause any redraws.
  165. If realbounds has shrunk, nothing will change.
  166. ===================
  167. */
  168. - newRealBounds: (NXRect *)nb
  169. {
  170. NXRect sbounds;
  171. realbounds = *nb;
  172. //
  173. // calculate the area visible in the cliprect
  174. //
  175. [superview getBounds: &sbounds];
  176. NXUnionRect (nb, &sbounds);
  177. //
  178. // size this view
  179. //
  180. [quakeed_i disableDisplay];
  181. [self suspendNotifyAncestorWhenFrameChanged:YES];
  182. [self sizeTo: sbounds.size.width : sbounds.size.height];
  183. [self setDrawOrigin: sbounds.origin.x : sbounds.origin.y];
  184. [self moveTo: sbounds.origin.x : sbounds.origin.y];
  185. [self suspendNotifyAncestorWhenFrameChanged:NO];
  186. [scrollview_i reflectScroll: superview];
  187. [quakeed_i reenableDisplay];
  188. [[scrollview_i horizScroller] display];
  189. [[scrollview_i vertScroller] display];
  190. return self;
  191. }
  192. /*
  193. ====================
  194. scaleMenuTarget:
  195. Called when the scaler popup on the window is used
  196. ====================
  197. */
  198. - scaleMenuTarget: sender
  199. {
  200. char const *item;
  201. NXRect visrect, sframe;
  202. float nscale;
  203. item = [[sender selectedCell] title];
  204. sscanf (item,"%f",&nscale);
  205. nscale /= 100;
  206. if (nscale == scale)
  207. return NULL;
  208. // keep the center of the view constant
  209. [superview getBounds: &visrect];
  210. [superview getFrame: &sframe];
  211. visrect.origin.x += visrect.size.width/2;
  212. visrect.origin.y += visrect.size.height/2;
  213. visrect.origin.x -= sframe.size.width/2/nscale;
  214. visrect.origin.y -= sframe.size.height/2/nscale;
  215. [self setOrigin: &visrect.origin scale: nscale];
  216. return self;
  217. }
  218. /*
  219. ==============
  220. zoomIn
  221. ==============
  222. */
  223. - zoomIn: (NXPoint *)constant
  224. {
  225. id itemlist;
  226. int selected, numrows, numcollumns;
  227. NXRect visrect;
  228. NXPoint ofs, new;
  229. //
  230. // set the popup
  231. //
  232. itemlist = [scalemenu_i itemList];
  233. [itemlist getNumRows: &numrows numCols:&numcollumns];
  234. selected = [itemlist selectedRow] + 1;
  235. if (selected >= numrows)
  236. return NULL;
  237. [itemlist selectCellAt: selected : 0];
  238. [scalebutton_i setTitle: [[itemlist selectedCell] title]];
  239. //
  240. // zoom the view
  241. //
  242. [superview getBounds: &visrect];
  243. ofs.x = constant->x - visrect.origin.x;
  244. ofs.y = constant->y - visrect.origin.y;
  245. new.x = constant->x - ofs.x / 2;
  246. new.y = constant->y - ofs.y / 2;
  247. [self setOrigin: &new scale: scale*2];
  248. return self;
  249. }
  250. /*
  251. ==============
  252. zoomOut
  253. ==============
  254. */
  255. - zoomOut: (NXPoint *)constant
  256. {
  257. id itemlist;
  258. int selected, numrows, numcollumns;
  259. NXRect visrect;
  260. NXPoint ofs, new;
  261. //
  262. // set the popup
  263. //
  264. itemlist = [scalemenu_i itemList];
  265. [itemlist getNumRows: &numrows numCols:&numcollumns];
  266. selected = [itemlist selectedRow] - 1;
  267. if (selected < 0)
  268. return NULL;
  269. [itemlist selectCellAt: selected : 0];
  270. [scalebutton_i setTitle: [[itemlist selectedCell] title]];
  271. //
  272. // zoom the view
  273. //
  274. [superview getBounds: &visrect];
  275. ofs.x = constant->x - visrect.origin.x;
  276. ofs.y = constant->y - visrect.origin.y;
  277. new.x = constant->x - ofs.x * 2;
  278. new.y = constant->y - ofs.y * 2;
  279. [self setOrigin: &new scale: scale/2];
  280. return self;
  281. }
  282. /*
  283. ====================
  284. gridMenuTarget:
  285. Called when the scaler popup on the window is used
  286. ====================
  287. */
  288. - gridMenuTarget: sender
  289. {
  290. char const *item;
  291. int grid;
  292. item = [[sender selectedCell] title];
  293. sscanf (item,"grid %d",&grid);
  294. if (grid == gridsize)
  295. return NULL;
  296. gridsize = grid;
  297. [quakeed_i updateAll];
  298. return self;
  299. }
  300. /*
  301. ====================
  302. snapToGrid
  303. ====================
  304. */
  305. - (float) snapToGrid: (float)f
  306. {
  307. int i;
  308. i = rint(f/gridsize);
  309. return i*gridsize;
  310. }
  311. - (int)gridsize
  312. {
  313. return gridsize;
  314. }
  315. /*
  316. ===================
  317. addToScrollRange::
  318. ===================
  319. */
  320. - addToScrollRange: (float)x :(float)y;
  321. {
  322. if (x < newrect.origin.x)
  323. {
  324. newrect.size.width += newrect.origin.x - x;
  325. newrect.origin.x = x;
  326. }
  327. if (y < newrect.origin.y)
  328. {
  329. newrect.size.height += newrect.origin.y - y;
  330. newrect.origin.y = y;
  331. }
  332. if (x > newrect.origin.x + newrect.size.width)
  333. newrect.size.width += x - (newrect.origin.x+newrect.size.width);
  334. if (y > newrect.origin.y + newrect.size.height)
  335. newrect.size.height += y - (newrect.origin.y+newrect.size.height);
  336. return self;
  337. }
  338. /*
  339. ===================
  340. superviewChanged
  341. ===================
  342. */
  343. - superviewChanged
  344. {
  345. [self newRealBounds: &realbounds];
  346. return self;
  347. }
  348. /*
  349. ===============================================================================
  350. DRAWING METHODS
  351. ===============================================================================
  352. */
  353. vec3_t cur_linecolor;
  354. void linestart (float r, float g, float b)
  355. {
  356. beginUserPath (upath,NO);
  357. cur_linecolor[0] = r;
  358. cur_linecolor[1] = g;
  359. cur_linecolor[2] = b;
  360. }
  361. void lineflush (void)
  362. {
  363. if (!upath->numberOfPoints)
  364. return;
  365. endUserPath (upath, dps_ustroke);
  366. PSsetrgbcolor (cur_linecolor[0], cur_linecolor[1], cur_linecolor[2]);
  367. sendUserPath (upath);
  368. beginUserPath (upath,NO);
  369. }
  370. void linecolor (float r, float g, float b)
  371. {
  372. if (cur_linecolor[0] == r && cur_linecolor[1] == g && cur_linecolor[2] == b)
  373. return; // do nothing
  374. lineflush ();
  375. cur_linecolor[0] = r;
  376. cur_linecolor[1] = g;
  377. cur_linecolor[2] = b;
  378. }
  379. void XYmoveto (vec3_t pt)
  380. {
  381. if (upath->numberOfPoints > 2048)
  382. lineflush ();
  383. UPmoveto (upath, pt[0], pt[1]);
  384. }
  385. void XYlineto (vec3_t pt)
  386. {
  387. UPlineto (upath, pt[0], pt[1]);
  388. }
  389. /*
  390. ============
  391. drawGrid
  392. Draws tile markings every 64 units, and grid markings at the grid scale if
  393. the grid lines are greater than or equal to 4 pixels apart
  394. Rect is in global world (unscaled) coordinates
  395. ============
  396. */
  397. - drawGrid: (const NXRect *)rect
  398. {
  399. int x,y, stopx, stopy;
  400. float top,bottom,right,left;
  401. char text[10];
  402. BOOL showcoords;
  403. showcoords = [quakeed_i showCoordinates];
  404. left = rect->origin.x-1;
  405. bottom = rect->origin.y-1;
  406. right = rect->origin.x+rect->size.width+2;
  407. top = rect->origin.y+rect->size.height+2;
  408. PSsetlinewidth (0.15);
  409. //
  410. // grid
  411. //
  412. // can't just divide by grid size because of negetive coordinate
  413. // truncating direction
  414. //
  415. if (gridsize >= 4/scale)
  416. {
  417. y = floor(bottom/gridsize);
  418. stopy = floor(top/gridsize);
  419. x = floor(left/gridsize);
  420. stopx = floor(right/gridsize);
  421. y *= gridsize;
  422. stopy *= gridsize;
  423. x *= gridsize;
  424. stopx *= gridsize;
  425. if (y<bottom)
  426. y+= gridsize;
  427. if (x<left)
  428. x+= gridsize;
  429. if (stopx >= right)
  430. stopx -= gridsize;
  431. if (stopy >= top)
  432. stopy -= gridsize;
  433. beginUserPath (upath,NO);
  434. for ( ; y<=stopy ; y+= gridsize)
  435. if (y&63)
  436. {
  437. UPmoveto (upath, left, y);
  438. UPlineto (upath, right, y);
  439. }
  440. for ( ; x<=stopx ; x+= gridsize)
  441. if (x&63)
  442. {
  443. UPmoveto (upath, x, top);
  444. UPlineto (upath, x, bottom);
  445. }
  446. endUserPath (upath, dps_ustroke);
  447. PSsetrgbcolor (0.8,0.8,1.0); // thin grid color
  448. sendUserPath (upath);
  449. }
  450. //
  451. // tiles
  452. //
  453. PSsetgray (0); // for text
  454. if (scale > 4.0/64)
  455. {
  456. y = floor(bottom/64);
  457. stopy = floor(top/64);
  458. x = floor(left/64);
  459. stopx = floor(right/64);
  460. y *= 64;
  461. stopy *= 64;
  462. x *= 64;
  463. stopx *= 64;
  464. if (y<bottom)
  465. y+= 64;
  466. if (x<left)
  467. x+= 64;
  468. if (stopx >= right)
  469. stopx -= 64;
  470. if (stopy >= top)
  471. stopy -= 64;
  472. beginUserPath (upath,NO);
  473. for ( ; y<=stopy ; y+= 64)
  474. {
  475. if (showcoords)
  476. {
  477. sprintf (text, "%i",y);
  478. PSmoveto(left,y);
  479. PSshow(text);
  480. }
  481. UPmoveto (upath, left, y);
  482. UPlineto (upath, right, y);
  483. }
  484. for ( ; x<=stopx ; x+= 64)
  485. {
  486. if (showcoords)
  487. {
  488. sprintf (text, "%i",x);
  489. PSmoveto(x,bottom+2);
  490. PSshow(text);
  491. }
  492. UPmoveto (upath, x, top);
  493. UPlineto (upath, x, bottom);
  494. }
  495. endUserPath (upath, dps_ustroke);
  496. PSsetgray (12.0/16);
  497. sendUserPath (upath);
  498. }
  499. return self;
  500. }
  501. /*
  502. ==================
  503. drawWire
  504. ==================
  505. */
  506. - drawWire: (const NXRect *)rects
  507. {
  508. NXRect visRect;
  509. int i,j, c, c2;
  510. id ent, brush;
  511. vec3_t mins, maxs;
  512. BOOL drawnames;
  513. drawnames = [quakeed_i showNames];
  514. if ([quakeed_i showCoordinates]) // if coords are showing, update everything
  515. {
  516. [self getVisibleRect:&visRect];
  517. rects = &visRect;
  518. xy_draw_rect = *rects;
  519. }
  520. NXRectClip(rects);
  521. // erase window
  522. NXEraseRect (rects);
  523. // draw grid
  524. [self drawGrid: rects];
  525. // draw all entities, world first so entities take priority
  526. linestart (0,0,0);
  527. c = [map_i count];
  528. for (i=0 ; i<c ; i++)
  529. {
  530. ent = [map_i objectAt: i];
  531. c2 = [ent count];
  532. for (j = c2-1 ; j >=0 ; j--)
  533. {
  534. brush = [ent objectAt: j];
  535. if ( [brush selected] )
  536. continue;
  537. if ([brush regioned])
  538. continue;
  539. [brush XYDrawSelf];
  540. }
  541. if (i > 0 && drawnames)
  542. { // draw entity names
  543. brush = [ent objectAt: 0];
  544. if (![brush regioned])
  545. {
  546. [brush getMins: mins maxs: maxs];
  547. PSmoveto(mins[0], mins[1]);
  548. PSsetrgbcolor (0,0,0);
  549. PSshow([ent valueForQKey: "classname"]);
  550. }
  551. }
  552. }
  553. lineflush ();
  554. // resize if needed
  555. newrect.origin.x -= gridsize;
  556. newrect.origin.y -= gridsize;
  557. newrect.size.width += 2*gridsize;
  558. newrect.size.height += 2*gridsize;
  559. if (!NXEqualRect (&newrect, &realbounds))
  560. [self newRealBounds: &newrect];
  561. return self;
  562. }
  563. /*
  564. =============
  565. drawSolid
  566. =============
  567. */
  568. - drawSolid
  569. {
  570. unsigned char *planes[5];
  571. NXRect visRect;
  572. [self getVisibleRect:&visRect];
  573. //
  574. // draw the image into imagebuffer
  575. //
  576. r_origin[0] = visRect.origin.x;
  577. r_origin[1] = visRect.origin.y;
  578. r_origin[2] = scale/2; // using Z as a scale for the 2D projection
  579. r_width = visRect.size.width*r_origin[2];
  580. r_height = visRect.size.height*r_origin[2];
  581. if (r_width != xywidth || r_height != xyheight)
  582. {
  583. xywidth = r_width;
  584. xyheight = r_height;
  585. if (xypicbuffer)
  586. {
  587. free (xypicbuffer);
  588. free (xyzbuffer);
  589. }
  590. xypicbuffer = malloc (r_width*(r_height+1)*4);
  591. xyzbuffer = malloc (r_width*(r_height+1)*4);
  592. }
  593. r_picbuffer = xypicbuffer;
  594. r_zbuffer = xyzbuffer;
  595. REN_BeginXY ();
  596. REN_ClearBuffers ();
  597. //
  598. // render the entities
  599. //
  600. [map_i makeAllPerform: @selector(XYRenderSelf)];
  601. //
  602. // display the output
  603. //
  604. [self lockFocus];
  605. [[self window] setBackingType:NX_RETAINED];
  606. planes[0] = (unsigned char *)r_picbuffer;
  607. NXDrawBitmap(
  608. &visRect,
  609. r_width,
  610. r_height,
  611. 8,
  612. 3,
  613. 32,
  614. r_width*4,
  615. NO,
  616. NO,
  617. NX_RGBColorSpace,
  618. planes
  619. );
  620. NXPing ();
  621. [[self window] setBackingType:NX_BUFFERED];
  622. [self unlockFocus];
  623. return self;
  624. }
  625. /*
  626. ===================
  627. drawSelf
  628. ===================
  629. */
  630. NXRect xy_draw_rect;
  631. - drawSelf:(const NXRect *)rects :(int)rectCount
  632. {
  633. static float drawtime; // static to shut up compiler warning
  634. if (timedrawing)
  635. drawtime = I_FloatTime ();
  636. xy_draw_rect = *rects;
  637. newrect.origin.x = newrect.origin.y = 99999;
  638. newrect.size.width = newrect.size.height = -2*99999;
  639. // setup for text
  640. PSselectfont("Helvetica-Medium",10/scale);
  641. PSrotate(0);
  642. if (drawmode == dr_texture || drawmode == dr_flat)
  643. [self drawSolid];
  644. else
  645. [self drawWire: rects];
  646. if (timedrawing)
  647. {
  648. NXPing ();
  649. drawtime = I_FloatTime() - drawtime;
  650. printf ("CameraView drawtime: %5.3f\n", drawtime);
  651. }
  652. return self;
  653. }
  654. /*
  655. ===============================================================================
  656. USER INTERACTION
  657. ===============================================================================
  658. */
  659. /*
  660. ================
  661. dragLoop:
  662. ================
  663. */
  664. static NXPoint oldreletive;
  665. - dragFrom: (NXEvent *)startevent
  666. useGrid: (BOOL)ug
  667. callback: (void (*) (float dx, float dy)) callback
  668. {
  669. NXEvent *event;
  670. NXPoint startpt, newpt;
  671. NXPoint reletive, delta;
  672. startpt = startevent->location;
  673. [self convertPoint:&startpt fromView:NULL];
  674. oldreletive.x = oldreletive.y = 0;
  675. if (ug)
  676. {
  677. startpt.x = [self snapToGrid: startpt.x];
  678. startpt.y = [self snapToGrid: startpt.y];
  679. }
  680. while (1)
  681. {
  682. event = [NXApp getNextEvent: NX_LMOUSEUPMASK | NX_LMOUSEDRAGGEDMASK
  683. | NX_RMOUSEUPMASK | NX_RMOUSEDRAGGEDMASK | NX_APPDEFINEDMASK];
  684. if (event->type == NX_LMOUSEUP || event->type == NX_RMOUSEUP)
  685. break;
  686. if (event->type == NX_APPDEFINED)
  687. { // doesn't work. grrr.
  688. [quakeed_i applicationDefined:event];
  689. continue;
  690. }
  691. newpt = event->location;
  692. [self convertPoint:&newpt fromView:NULL];
  693. if (ug)
  694. {
  695. newpt.x = [self snapToGrid: newpt.x];
  696. newpt.y = [self snapToGrid: newpt.y];
  697. }
  698. reletive.x = newpt.x - startpt.x;
  699. reletive.y = newpt.y - startpt.y;
  700. if (reletive.x == oldreletive.x && reletive.y == oldreletive.y)
  701. continue;
  702. delta.x = reletive.x - oldreletive.x;
  703. delta.y = reletive.y - oldreletive.y;
  704. oldreletive = reletive;
  705. callback (delta.x , delta.y );
  706. }
  707. return self;
  708. }
  709. //============================================================================
  710. void DragCallback (float dx, float dy)
  711. {
  712. sb_translate[0] = dx;
  713. sb_translate[1] = dy;
  714. sb_translate[2] = 0;
  715. [map_i makeSelectedPerform: @selector(translate)];
  716. [quakeed_i redrawInstance];
  717. }
  718. - selectionDragFrom: (NXEvent*)theEvent
  719. {
  720. qprintf ("dragging selection");
  721. [self dragFrom: theEvent
  722. useGrid: YES
  723. callback: DragCallback ];
  724. [quakeed_i updateAll];
  725. qprintf ("");
  726. return self;
  727. }
  728. //============================================================================
  729. void ScrollCallback (float dx, float dy)
  730. {
  731. NXRect basebounds;
  732. NXPoint neworg;
  733. float scale;
  734. [ [xyview_i superview] getBounds: &basebounds];
  735. [xyview_i convertRectFromSuperview: &basebounds];
  736. neworg.x = basebounds.origin.x - dx;
  737. neworg.y = basebounds.origin.y - dy;
  738. scale = [xyview_i currentScale];
  739. oldreletive.x -= dx;
  740. oldreletive.y -= dy;
  741. [xyview_i setOrigin: &neworg scale: scale];
  742. }
  743. - scrollDragFrom: (NXEvent*)theEvent
  744. {
  745. qprintf ("scrolling view");
  746. [self dragFrom: theEvent
  747. useGrid: YES
  748. callback: ScrollCallback ];
  749. qprintf ("");
  750. return self;
  751. }
  752. //============================================================================
  753. vec3_t direction;
  754. void DirectionCallback (float dx, float dy)
  755. {
  756. vec3_t org;
  757. float ya;
  758. direction[0] += dx;
  759. direction[1] += dy;
  760. [cameraview_i getOrigin: org];
  761. if (direction[0] == org[0] && direction[1] == org[1])
  762. return;
  763. ya = atan2 (direction[1] - org[1], direction[0] - org[0]);
  764. [cameraview_i setOrigin: org angle: ya];
  765. [quakeed_i newinstance];
  766. [cameraview_i display];
  767. }
  768. - directionDragFrom: (NXEvent*)theEvent
  769. {
  770. NXPoint pt;
  771. qprintf ("changing camera direction");
  772. pt= theEvent->location;
  773. [self convertPoint:&pt fromView:NULL];
  774. direction[0] = pt.x;
  775. direction[1] = pt.y;
  776. DirectionCallback (0,0);
  777. [self dragFrom: theEvent
  778. useGrid: NO
  779. callback: DirectionCallback ];
  780. qprintf ("");
  781. return self;
  782. }
  783. //============================================================================
  784. id newbrush;
  785. vec3_t neworg, newdrag;
  786. void NewCallback (float dx, float dy)
  787. {
  788. vec3_t min, max;
  789. int i;
  790. newdrag[0] += dx;
  791. newdrag[1] += dy;
  792. for (i=0 ; i<3 ; i++)
  793. {
  794. if (neworg[i] < newdrag[i])
  795. {
  796. min[i] = neworg[i];
  797. max[i] = newdrag[i];
  798. }
  799. else
  800. {
  801. min[i] = newdrag[i];
  802. max[i] = neworg[i];
  803. }
  804. }
  805. [newbrush setMins: min maxs: max];
  806. [quakeed_i redrawInstance];
  807. }
  808. - newBrushDragFrom: (NXEvent*)theEvent
  809. {
  810. id owner;
  811. texturedef_t td;
  812. NXPoint pt;
  813. qprintf ("sizing new brush");
  814. pt= theEvent->location;
  815. [self convertPoint:&pt fromView:NULL];
  816. neworg[0] = [self snapToGrid: pt.x];
  817. neworg[1] = [self snapToGrid: pt.y];
  818. neworg[2] = [map_i currentMinZ];
  819. newdrag[0] = neworg[0];
  820. newdrag[1] = neworg[1];
  821. newdrag[2] = [map_i currentMaxZ];
  822. owner = [map_i currentEntity];
  823. [texturepalette_i getTextureDef: &td];
  824. newbrush = [[SetBrush alloc] initOwner: owner
  825. mins: neworg maxs: newdrag texture: &td];
  826. [owner addObject: newbrush];
  827. [newbrush setSelected: YES];
  828. [self dragFrom: theEvent
  829. useGrid: YES
  830. callback: NewCallback ];
  831. [newbrush removeIfInvalid];
  832. [quakeed_i updateCamera];
  833. qprintf ("");
  834. return self;
  835. }
  836. //============================================================================
  837. void ControlCallback (float dx, float dy)
  838. {
  839. int i;
  840. for (i=0 ; i<numcontrolpoints ; i++)
  841. {
  842. controlpoints[i][0] += dx;
  843. controlpoints[i][1] += dy;
  844. }
  845. [[map_i selectedBrush] calcWindings];
  846. [quakeed_i redrawInstance];
  847. }
  848. - (BOOL)planeDragFrom: (NXEvent*)theEvent
  849. {
  850. NXPoint pt;
  851. vec3_t dragpoint;
  852. if ([map_i numSelected] != 1)
  853. return NO;
  854. pt= theEvent->location;
  855. [self convertPoint:&pt fromView:NULL];
  856. dragpoint[0] = pt.x;
  857. dragpoint[1] = pt.y;
  858. dragpoint[2] = 2048;
  859. [[map_i selectedBrush] getXYdragface: dragpoint];
  860. if (!numcontrolpoints)
  861. return NO;
  862. qprintf ("dragging brush plane");
  863. pt= theEvent->location;
  864. [self convertPoint:&pt fromView:NULL];
  865. [self dragFrom: theEvent
  866. useGrid: YES
  867. callback: ControlCallback ];
  868. [[map_i selectedBrush] removeIfInvalid];
  869. [quakeed_i updateAll];
  870. qprintf ("");
  871. return YES;
  872. }
  873. - (BOOL)shearDragFrom: (NXEvent*)theEvent
  874. {
  875. NXPoint pt;
  876. vec3_t dragpoint;
  877. vec3_t p1, p2;
  878. float time;
  879. id br;
  880. int face;
  881. if ([map_i numSelected] != 1)
  882. return NO;
  883. br = [map_i selectedBrush];
  884. pt= theEvent->location;
  885. [self convertPoint:&pt fromView:NULL];
  886. // if the XY point is inside the brush, make the point on top
  887. p1[0] = pt.x;
  888. p1[1] = pt.y;
  889. VectorCopy (p1, p2);
  890. p1[2] = -2048*xy_viewnormal[2];
  891. p2[2] = 2048*xy_viewnormal[2];
  892. VectorCopy (p1, dragpoint);
  893. [br hitByRay: p1 : p2 : &time : &face];
  894. if (time > 0)
  895. {
  896. dragpoint[2] = p1[2] + (time-0.01)*xy_viewnormal[2];
  897. }
  898. else
  899. {
  900. [br getMins: p1 maxs: p2];
  901. dragpoint[2] = (p1[2] + p2[2])/2;
  902. }
  903. [br getXYShearPoints: dragpoint];
  904. if (!numcontrolpoints)
  905. return NO;
  906. qprintf ("dragging brush plane");
  907. pt= theEvent->location;
  908. [self convertPoint:&pt fromView:NULL];
  909. [self dragFrom: theEvent
  910. useGrid: YES
  911. callback: ControlCallback ];
  912. [br removeIfInvalid];
  913. [quakeed_i updateAll];
  914. qprintf ("");
  915. return YES;
  916. }
  917. /*
  918. ===============================================================================
  919. INPUT METHODS
  920. ===============================================================================
  921. */
  922. /*
  923. ===================
  924. mouseDown
  925. ===================
  926. */
  927. - mouseDown:(NXEvent *)theEvent
  928. {
  929. NXPoint pt;
  930. id ent;
  931. vec3_t p1, p2;
  932. int flags;
  933. pt= theEvent->location;
  934. [self convertPoint:&pt fromView:NULL];
  935. p1[0] = p2[0] = pt.x;
  936. p1[1] = p2[1] = pt.y;
  937. p1[2] = xy_viewnormal[2] * -4096;
  938. p2[2] = xy_viewnormal[2] * 4096;
  939. flags = theEvent->flags & (NX_SHIFTMASK | NX_CONTROLMASK | NX_ALTERNATEMASK | NX_COMMANDMASK);
  940. //
  941. // shift click to select / deselect a brush from the world
  942. //
  943. if (flags == NX_SHIFTMASK)
  944. {
  945. [map_i selectRay: p1 : p2 : YES];
  946. return self;
  947. }
  948. //
  949. // cmd-shift click to set a target/targetname entity connection
  950. //
  951. if (flags == (NX_SHIFTMASK|NX_COMMANDMASK) )
  952. {
  953. [map_i entityConnect: p1 : p2];
  954. return self;
  955. }
  956. //
  957. // bare click to either drag selection, or rubber band a new brush
  958. //
  959. if ( flags == 0 )
  960. {
  961. // if double click, position Z checker
  962. if (theEvent->data.mouse.click > 1)
  963. {
  964. qprintf ("positioned Z checker");
  965. [zview_i setPoint: &pt];
  966. [quakeed_i newinstance];
  967. [quakeed_i updateZ];
  968. return self;
  969. }
  970. // check eye
  971. if ( [cameraview_i XYmouseDown: &pt flags: theEvent->flags] )
  972. return self; // camera move
  973. // check z post
  974. if ( [zview_i XYmouseDown: &pt] )
  975. return self; // z view move
  976. // check clippers
  977. if ( [clipper_i XYDrag: &pt] )
  978. return self;
  979. // check single plane dragging
  980. if ( [self planeDragFrom: theEvent] )
  981. return self;
  982. // check selection
  983. ent = [map_i grabRay: p1 : p2];
  984. if (ent)
  985. return [self selectionDragFrom: theEvent];
  986. if ([map_i numSelected])
  987. {
  988. qprintf ("missed");
  989. return self;
  990. }
  991. return [self newBrushDragFrom: theEvent];
  992. }
  993. //
  994. // control click = position and drag camera
  995. //
  996. if (flags == NX_CONTROLMASK)
  997. {
  998. [cameraview_i setXYOrigin: &pt];
  999. [quakeed_i newinstance];
  1000. [cameraview_i display];
  1001. [cameraview_i XYmouseDown: &pt flags: theEvent->flags];
  1002. qprintf ("");
  1003. return self;
  1004. }
  1005. //
  1006. // command click = drag Z checker
  1007. //
  1008. if (flags == NX_COMMANDMASK)
  1009. {
  1010. // check single plane dragging
  1011. [self shearDragFrom: theEvent];
  1012. return self;
  1013. qprintf ("moving Z checker");
  1014. [zview_i setXYOrigin: &pt];
  1015. [quakeed_i updateAll];
  1016. [zview_i XYmouseDown: &pt];
  1017. qprintf ("");
  1018. return self;
  1019. }
  1020. //
  1021. // alt click = set entire brush texture
  1022. //
  1023. if (flags == NX_ALTERNATEMASK)
  1024. {
  1025. if (drawmode != dr_texture)
  1026. {
  1027. qprintf ("No texture setting except in texture mode!\n");
  1028. NopSound ();
  1029. return self;
  1030. }
  1031. [map_i setTextureRay: p1 : p2 : YES];
  1032. [quakeed_i updateAll];
  1033. return self;
  1034. }
  1035. //
  1036. // ctrl-alt click = set single face texture
  1037. //
  1038. if (flags == (NX_CONTROLMASK | NX_ALTERNATEMASK) )
  1039. {
  1040. if (drawmode != dr_texture)
  1041. {
  1042. qprintf ("No texture setting except in texture mode!\n");
  1043. NopSound ();
  1044. return self;
  1045. }
  1046. [map_i setTextureRay: p1 : p2 : NO];
  1047. [quakeed_i updateAll];
  1048. return self;
  1049. }
  1050. qprintf ("bad flags for click");
  1051. NopSound ();
  1052. return self;
  1053. }
  1054. /*
  1055. ===================
  1056. rightMouseDown
  1057. ===================
  1058. */
  1059. - rightMouseDown:(NXEvent *)theEvent
  1060. {
  1061. NXPoint pt;
  1062. int flags;
  1063. pt= theEvent->location;
  1064. [self convertPoint:&pt fromView:NULL];
  1065. flags = theEvent->flags & (NX_SHIFTMASK | NX_CONTROLMASK | NX_ALTERNATEMASK | NX_COMMANDMASK);
  1066. if (flags == NX_COMMANDMASK)
  1067. {
  1068. return [self scrollDragFrom: theEvent];
  1069. }
  1070. if (flags == NX_ALTERNATEMASK)
  1071. {
  1072. return [clipper_i XYClick: pt];
  1073. }
  1074. if (flags == 0 || flags == NX_CONTROLMASK)
  1075. {
  1076. return [self directionDragFrom: theEvent];
  1077. }
  1078. qprintf ("bad flags for click");
  1079. NopSound ();
  1080. return self;
  1081. }
  1082. @end