graph.pp 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by Florian Klaempfl
  4. This file implements the linux GGI support for the graph unit
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit Graph;
  12. interface
  13. uses
  14. { in the interface so the graphh definitions of moveto etc override }
  15. { the ones in the universal interfaces }
  16. cthreads, FPCMacOSAll;
  17. {$linkframework Carbon}
  18. type
  19. TGraphProgram = function(p: pointer): longint;
  20. procedure StartGraphProgram(p: TGraphProgram);
  21. {$i graphh.inc}
  22. Const
  23. { Supported modes }
  24. {(sg) GTEXT deactivated because we need mode #0 as default mode}
  25. {GTEXT = 0; Compatible with VGAlib v1.2 }
  26. G320x200x16 = 1;
  27. G640x200x16 = 2;
  28. G640x350x16 = 3;
  29. G640x480x16 = 4;
  30. G320x200x256 = 5;
  31. G320x240x256 = 6;
  32. G320x400x256 = 7;
  33. G360x480x256 = 8;
  34. G640x480x2 = 9;
  35. G640x480x256 = 10;
  36. G800x600x256 = 11;
  37. G1024x768x256 = 12;
  38. G1280x1024x256 = 13; { Additional modes. }
  39. G320x200x32K = 14;
  40. G320x200x64K = 15;
  41. G320x200x16M = 16;
  42. G640x480x32K = 17;
  43. G640x480x64K = 18;
  44. G640x480x16M = 19;
  45. G800x600x32K = 20;
  46. G800x600x64K = 21;
  47. G800x600x16M = 22;
  48. G1024x768x32K = 23;
  49. G1024x768x64K = 24;
  50. G1024x768x16M = 25;
  51. G1280x1024x32K = 26;
  52. G1280x1024x64K = 27;
  53. G1280x1024x16M = 28;
  54. G800x600x16 = 29;
  55. G1024x768x16 = 30;
  56. G1280x1024x16 = 31;
  57. G720x348x2 = 32; { Hercules emulation mode }
  58. G320x200x16M32 = 33; { 32-bit per pixel modes. }
  59. G640x480x16M32 = 34;
  60. G800x600x16M32 = 35;
  61. G1024x768x16M32 = 36;
  62. G1280x1024x16M32 = 37;
  63. { additional resolutions }
  64. G1152x864x16 = 38;
  65. G1152x864x256 = 39;
  66. G1152x864x32K = 40;
  67. G1152x864x64K = 41;
  68. G1152x864x16M = 42;
  69. G1152x864x16M32 = 43;
  70. G1600x1200x16 = 44;
  71. G1600x1200x256 = 45;
  72. G1600x1200x32K = 46;
  73. G1600x1200x64K = 47;
  74. G1600x1200x16M = 48;
  75. G1600x1200x16M32 = 49;
  76. implementation
  77. uses
  78. { for FOUR_CHAR_CODE }
  79. macpas;
  80. const
  81. InternalDriverName = 'Quartz';
  82. kEventClassFPCGraph = $46504367; // 'FPCg'
  83. kEventInitGraph = $496E6974; // 'Init'
  84. kEventFlush = $466c7368; // 'Flsh'
  85. kEventCloseGraph = $446f6e65; // 'Done'
  86. kEventQuit = $51756974; // 'Quit'
  87. kEventGraphInited = $49746564 ; // Ited;
  88. kEventGraphClosed = $436c6564 ; // Cled;
  89. // initGraphSpec : EventTypeSpec = (eventClass: kEventClassFPCGraph; eventKind: kEventInitGraph);
  90. // flushGraphSpec : EventTypeSpec = (eventClass: kEventClassFPCGraph; eventKind: kEventFlush);
  91. // closeGraphSpec : EventTypeSpec = (eventClass: kEventClassFPCGraph; eventKind: kEventCloseGraph);
  92. allGraphSpec: array[0..3] of EventTypeSpec = ((eventClass: kEventClassFPCGraph; eventKind: kEventInitGraph),
  93. (eventClass: kEventClassFPCGraph; eventKind: kEventFlush),
  94. (eventClass: kEventClassFPCGraph; eventKind: kEventCloseGraph),
  95. (eventClass: kEventClassFPCGraph; eventKind: kEventQuit));
  96. GraphInitedSpec: array[0..0] of EventTypeSpec = ((eventClass: kEventClassFPCGraph; eventKind: kEventGraphInited));
  97. GraphClosedSpec: array[0..0] of EventTypeSpec = ((eventClass: kEventClassFPCGraph; eventKind: kEventGraphClosed));
  98. {$i graph.inc}
  99. type
  100. PByte = ^Byte;
  101. PLongInt = ^LongInt;
  102. PByteArray = ^TByteArray;
  103. TByteArray = array [0..MAXINT - 1] of Byte;
  104. var
  105. graphdrawing: TRTLCriticalSection;
  106. { ---------------------------------------------------------------------
  107. SVGA bindings.
  108. ---------------------------------------------------------------------}
  109. Const
  110. { Text }
  111. WRITEMODE_OVERWRITE = 0;
  112. WRITEMODE_MASKED = 1;
  113. FONT_EXPANDED = 0;
  114. FONT_COMPRESSED = 2;
  115. { Types }
  116. type
  117. PGraphicsContext = ^TGraphicsContext;
  118. TGraphicsContext = record
  119. ModeType: Byte;
  120. ModeFlags: Byte;
  121. Dummy: Byte;
  122. FlipPage: Byte;
  123. Width: LongInt;
  124. Height: LongInt;
  125. BytesPerPixel: LongInt;
  126. Colors: LongInt;
  127. BitsPerPixel: LongInt;
  128. ByteWidth: LongInt;
  129. VBuf: pointer;
  130. Clip: LongInt;
  131. ClipX1: LongInt;
  132. ClipY1: LongInt;
  133. ClipX2: LongInt;
  134. ClipY2: LongInt;
  135. ff: pointer;
  136. end;
  137. Const
  138. GLASTMODE = 49;
  139. ModeNames : Array[0..GLastMode] of string [18] =
  140. ('Text',
  141. 'G320x200x16',
  142. 'G640x200x16',
  143. 'G640x350x16',
  144. 'G640x480x16',
  145. 'G320x200x256',
  146. 'G320x240x256',
  147. 'G320x400x256',
  148. 'G360x480x256',
  149. 'G640x480x2',
  150. 'G640x480x256',
  151. 'G800x600x256',
  152. 'G1024x768x256',
  153. 'G1280x1024x256',
  154. 'G320x200x32K',
  155. 'G320x200x64K',
  156. 'G320x200x16M',
  157. 'G640x480x32K',
  158. 'G640x480x64K',
  159. 'G640x480x16M',
  160. 'G800x600x32K',
  161. 'G800x600x64K',
  162. 'G800x600x16M',
  163. 'G1024x768x32K',
  164. 'G1024x768x64K',
  165. 'G1024x768x16M',
  166. 'G1280x1024x32K',
  167. 'G1280x1024x64K',
  168. 'G1280x1024x16M',
  169. 'G800x600x16',
  170. '1024x768x16',
  171. '1280x1024x16',
  172. 'G720x348x2',
  173. 'G320x200x16M32',
  174. 'G640x480x16M32',
  175. 'G800x600x16M32',
  176. 'G1024x768x16M32',
  177. 'G1280x1024x16M32',
  178. 'G1152x864x16',
  179. 'G1152x864x256',
  180. 'G1152x864x32K',
  181. 'G1152x864x64K',
  182. 'G1152x864x16M',
  183. 'G1152x864x16M32',
  184. 'G1600x1200x16',
  185. 'G1600x1200x256',
  186. 'G1600x1200x32K',
  187. 'G1600x1200x64K',
  188. 'G1600x1200x16M',
  189. 'G1600x1200x16M32');
  190. { ---------------------------------------------------------------------
  191. Mac OS X - specific stuff
  192. ---------------------------------------------------------------------}
  193. var
  194. { where all the drawing occurs }
  195. offscreen: CGContextRef;
  196. { the drawing window's contents to which offscreen is flushed }
  197. graphHIView: HIViewRef;
  198. { the drawing window itself }
  199. myMainWindow: WindowRef;
  200. maineventqueue: EventQueueRef;
  201. updatepending: boolean;
  202. colorpalette: array[0..255,1..3] of single;
  203. { create a new offscreen bitmap context in which we can draw (and from }
  204. { which we can read again) }
  205. function CreateBitmapContext (pixelsWide, pixelsHigh: SInt32) : CGContextRef;
  206. var
  207. colorSpace : CGColorSpaceRef;
  208. bitmapData : Pointer;
  209. bitmapByteCount : SInt32;
  210. bitmapBytesPerRow : SInt32;
  211. begin
  212. CreateBitmapContext := nil;
  213. bitmapBytesPerRow := (pixelsWide * 4);// always draw in 24 bit colour (+ 8 bit alpha)
  214. bitmapByteCount := (bitmapBytesPerRow * pixelsHigh);
  215. colorSpace := CGColorSpaceCreateDeviceRGB;// 2
  216. bitmapData := getmem ( bitmapByteCount );// 3
  217. if (bitmapData = nil) then
  218. exit;
  219. CreateBitmapContext := CGBitmapContextCreate (bitmapData,
  220. pixelsWide,
  221. pixelsHigh,
  222. 8, // bits per component
  223. bitmapBytesPerRow,
  224. colorSpace,
  225. kCGImageAlphaPremultipliedLast);
  226. if (CreateBitmapContext = nil) then
  227. begin
  228. system.freemem (bitmapData);
  229. writeln (stderr, 'Could not create graphics context!');
  230. exit;
  231. end;
  232. CGColorSpaceRelease( colorSpace );
  233. { disable anti-aliasing }
  234. CGContextTranslateCTM(CreateBitmapContext,0.5,0.5);
  235. end;
  236. { dispose the offscreen bitmap context }
  237. procedure DisposeBitmapContext(var bmContext: CGContextRef);
  238. begin
  239. system.freemem(CGBitmapContextGetData(bmContext));
  240. CGContextRelease(bmContext);
  241. bmContext:=nil;
  242. end;
  243. { create a HIView to add to a window, in which we can then draw }
  244. function CreateHIView (inWindow: WindowRef; const inBounds: Rect; var outControl: HIObjectRef): OSStatus;
  245. var
  246. root : ControlRef;
  247. event : EventRef;
  248. err : OSStatus;
  249. label
  250. CantCreate, CantGetRootControl, CantSetParameter, CantCreateEvent{, CantRegister};
  251. begin
  252. // Make an initialization event
  253. err := CreateEvent( nil, kEventClassHIObject, kEventHIObjectInitialize,
  254. GetCurrentEventTime(), 0, event );
  255. if (err <> noErr) then
  256. goto CantCreateEvent;
  257. // If bounds were specified, push the them into the initialization event
  258. // so that they can be used in the initialization handler.
  259. err := SetEventParameter( event, FOUR_CHAR_CODE('boun'), typeQDRectangle,
  260. sizeof( Rect ), @inBounds );
  261. if (err <> noErr) then
  262. goto CantSetParameter;
  263. err := HIObjectCreate( { kHIViewClassID } CFSTR('com.apple.hiview'), event, outControl );
  264. assert(err = noErr);
  265. // If a parent window was specified, place the new view into the
  266. // parent window.
  267. err := GetRootControl( inWindow, root );
  268. if (err <> noErr) then
  269. goto CantGetRootControl;
  270. err := HIViewAddSubview( root, outControl );
  271. if (err <> noErr) then
  272. goto CantGetRootControl;
  273. err := HIViewSetVisible(outControl, true);
  274. CantCreate:
  275. CantGetRootControl:
  276. CantSetParameter:
  277. CantCreateEvent:
  278. ReleaseEvent( event );
  279. CreateHIView := err;
  280. end;
  281. { Event handler which does the actual drawing by copying the offscreen to }
  282. { the HIView of the drawing window }
  283. function MyDrawEventHandler (myHandler: EventHandlerCallRef;
  284. event: EventRef; userData: pointer): OSStatus; mwpascal;
  285. var
  286. myContext: CGContextRef;
  287. bounds: HIRect;
  288. img: CGImageRef;
  289. begin
  290. // writeln('event');
  291. MyDrawEventHandler := GetEventParameter (event, // 1
  292. kEventParamCGContextRef,
  293. typeCGContextRef,
  294. nil,
  295. sizeof (CGContextRef),
  296. nil,
  297. @myContext);
  298. if (MyDrawEventHandler <> noErr) then
  299. exit;
  300. MyDrawEventHandler := HIViewGetBounds (HIViewRef(userData), bounds);
  301. if (MyDrawEventHandler <> noErr) then
  302. exit;
  303. EnterCriticalSection(graphdrawing);
  304. img:=CGBitmapContextCreateImage(offscreen);
  305. CGContextDrawImage(myContext,
  306. bounds,
  307. img);
  308. updatepending:=false;
  309. LeaveCriticalSection(graphdrawing);
  310. CGImageRelease(img);
  311. end;
  312. { force the draw event handler to fire }
  313. procedure UpdateScreen;
  314. var
  315. event : EventRef;
  316. begin
  317. if (updatepending) then
  318. exit;
  319. if (CreateEvent(nil, kEventClassFPCGraph, kEventFlush, GetCurrentEventTime(), 0, event) <> noErr) then
  320. exit;
  321. if (PostEventToQueue(MainEventQueue,event,kEventPriorityLow) <> noErr) then
  322. begin
  323. ReleaseEvent(event);
  324. exit;
  325. end;
  326. updatepending:=true;
  327. end;
  328. { ---------------------------------------------------------------------
  329. Required procedures
  330. ---------------------------------------------------------------------}
  331. var
  332. LastColor: smallint; {Cache the last set color to improve speed}
  333. procedure q_SetColor(color: smallint);
  334. begin
  335. if color <> LastColor then
  336. begin
  337. // writeln('setting color to ',color);
  338. EnterCriticalSection(graphdrawing);
  339. case maxcolor of
  340. 16:
  341. begin
  342. CGContextSetRGBFillColor(offscreen,colorpalette[color,1],colorpalette[color,2],colorpalette[color,3],1);
  343. CGContextSetRGBStrokeColor(offscreen,colorpalette[color,1],colorpalette[color,2],colorpalette[color,3],1);
  344. end;
  345. 256:
  346. begin
  347. CGContextSetRGBFillColor(offscreen,colorpalette[color,1],colorpalette[color,2],colorpalette[color,3],1);
  348. CGContextSetRGBStrokeColor(offscreen,colorpalette[color,1],colorpalette[color,2],colorpalette[color,3],1);
  349. end;
  350. 32678:
  351. begin
  352. CGContextSetRGBFillColor(offscreen,((color and $7ffff) shr 10)/31.0,((color shr 5) and 31)/31.0,(color and 31)/31.0,1);
  353. CGContextSetRGBStrokeColor(offscreen,((color and $7ffff) shr 10)/31.0,((color shr 5) and 31)/31.0,(color and 31)/31.0,1);
  354. end;
  355. 65536:
  356. begin
  357. CGContextSetRGBFillColor(offscreen,(word(color) shr 11)/31.0,((word(color) shr 5) and 63)/63.0,(color and 31)/31.0,1);
  358. CGContextSetRGBStrokeColor(offscreen,(word(color) shr 11)/31.0,((word(color) shr 5) and 63)/63.0,(color and 31)/31.0,1);
  359. end;
  360. else
  361. runerror(218);
  362. end;
  363. LeaveCriticalSection(graphdrawing);
  364. lastcolor:=color;
  365. end
  366. end;
  367. procedure q_savevideostate;
  368. begin
  369. end;
  370. procedure q_restorevideostate;
  371. begin
  372. end;
  373. function CGRectMake(x,y, width, height: single): CGRect; inline;
  374. begin
  375. CGRectMake.origin.x:=x;
  376. CGRectMake.origin.y:=y;
  377. CGRectMake.size.width:=width;
  378. CGRectMake.size.height:=height;
  379. end;
  380. Function ClipCoords (Var X,Y : smallint) : Boolean;
  381. { Adapt to viewport, return TRUE if still in viewport,
  382. false if outside viewport}
  383. begin
  384. X:= X + StartXViewPort;
  385. Y:= Y + StartYViewPort;
  386. ClipCoords:=Not ClipPixels;
  387. if ClipPixels then
  388. Begin
  389. ClipCoords:=(X < StartXViewPort) or (X > (StartXViewPort + ViewWidth));
  390. ClipCoords:=ClipCoords or
  391. ((Y < StartYViewPort) or (Y > (StartYViewPort + ViewHeight)));
  392. ClipCoords:=Not ClipCoords;
  393. end;
  394. end;
  395. procedure q_directpixelproc(X,Y: smallint);
  396. Var Color : Word;
  397. begin
  398. case CurrentWriteMode of
  399. XORPut:
  400. begin
  401. { getpixel wants local/relative coordinates }
  402. Color := GetPixel(x-StartXViewPort,y-StartYViewPort);
  403. Color := CurrentColor Xor Color;
  404. end;
  405. OrPut:
  406. begin
  407. { getpixel wants local/relative coordinates }
  408. Color := GetPixel(x-StartXViewPort,y-StartYViewPort);
  409. Color := CurrentColor Or Color;
  410. end;
  411. AndPut:
  412. begin
  413. { getpixel wants local/relative coordinates }
  414. Color := GetPixel(x-StartXViewPort,y-StartYViewPort);
  415. Color := CurrentColor And Color;
  416. end;
  417. NotPut:
  418. begin
  419. Color := Not CurrentColor;
  420. end
  421. else
  422. Color:=CurrentColor;
  423. end;
  424. q_SetColor(Color);
  425. EnterCriticalSection(graphdrawing);
  426. CGContextBeginPath(offscreen);
  427. CGContextMoveToPoint(offscreen,x,y);
  428. CGContextAddLineToPoint(offscreen,x,y);
  429. CGContextClosePath(offscreen);
  430. CGContextStrokePath(offscreen);
  431. UpdateScreen;
  432. LeaveCriticalSection(graphdrawing);
  433. end;
  434. procedure q_putpixelproc(X,Y: smallint; Color: Word);
  435. begin
  436. if Not ClipCoords(X,Y) Then
  437. exit;
  438. q_setcolor(Color);
  439. EnterCriticalSection(graphdrawing);
  440. CGContextBeginPath(offscreen);
  441. CGContextMoveToPoint(offscreen,x,y);
  442. CGContextAddLineToPoint(offscreen,x,y);
  443. CGContextClosePath(offscreen);
  444. CGContextStrokePath(offscreen);
  445. UpdateScreen;
  446. LeaveCriticalSection(graphdrawing);
  447. end;
  448. function q_getpixelproc (X,Y: smallint): word;
  449. type
  450. pbyte = ^byte;
  451. var
  452. p: pbyte;
  453. rsingle, gsingle, bsingle, dist, closest: single;
  454. count: longint;
  455. red, green, blue: byte;
  456. begin
  457. if not ClipCoords(X,Y) then
  458. exit;
  459. p := pbyte(CGBitmapContextGetData(offscreen));
  460. y:=maxy-y;
  461. inc(p,(y*(maxx+1)+x)*4);
  462. red:=p^;
  463. green:=(p+1)^;
  464. blue:=(p+2)^;
  465. case maxcolor of
  466. 16, 256:
  467. begin
  468. { find closest color using least squares }
  469. rsingle:=red/255.0;
  470. gsingle:=green/255.0;
  471. bsingle:=blue/255.0;
  472. closest:=255.0;
  473. q_getpixelproc:=0;
  474. for count := 0 to maxcolor-1 do
  475. begin
  476. dist:=sqr(colorpalette[count,1]-rsingle) +
  477. sqr(colorpalette[count,2]-gsingle) +
  478. sqr(colorpalette[count,3]-bsingle);
  479. if (dist < closest) then
  480. begin
  481. closest:=dist;
  482. q_getpixelproc:=count;
  483. end;
  484. end;
  485. exit;
  486. end;
  487. 32678:
  488. q_getpixelproc:=((red div 8) shl 7) or ((green div 8) shl 2) or (blue div 8);
  489. 65536:
  490. q_getpixelproc:=((red div 8) shl 8) or ((green div 4) shl 3) or (blue div 8);
  491. end;
  492. end;
  493. procedure q_clrviewproc;
  494. begin
  495. q_SetColor(CurrentBkColor);
  496. EnterCriticalSection(graphdrawing);
  497. CGContextFillRect(offscreen,CGRectMake(StartXViewPort,StartYViewPort,ViewWidth+1,ViewHeight+1));
  498. UpdateScreen;
  499. LeaveCriticalSection(graphdrawing);
  500. { reset coordinates }
  501. CurrentX := 0;
  502. CurrentY := 0;
  503. end;
  504. procedure q_putimageproc (X,Y: smallint; var Bitmap; BitBlt: Word);
  505. begin
  506. {
  507. With TBitMap(BitMap) do
  508. gl_putbox(x, y, width, height, @Data);
  509. }
  510. end;
  511. procedure q_getimageproc (X1,Y1,X2,Y2: smallint; Var Bitmap);
  512. begin
  513. { with TBitmap(Bitmap) do
  514. begin
  515. Width := x2 - x1 + 1;
  516. Height := y2 - y1 + 1;
  517. gl_getbox(x1,y1, x2 - x1 + 1, y2 - y1 + 1, @Data);
  518. end;
  519. }
  520. end;
  521. {
  522. function q_imagesizeproc (X1,Y1,X2,Y2: smallint): longint;
  523. begin
  524. q_imagesizeproc := SizeOf(TBitmap) + (x2 - x1 + 1) * (y2 - y1 + 1) * PhysicalScreen^.BytesPerPixel;
  525. end;
  526. }
  527. procedure q_lineproc_intern (X1, Y1, X2, Y2 : smallint);
  528. begin
  529. if (CurrentWriteMode in [OrPut,AndPut,XorPut]) then
  530. begin
  531. LineDefault(X1,Y1,X2,Y2);
  532. exit
  533. end
  534. else
  535. begin
  536. { Convert to global coordinates. }
  537. x1 := x1 + StartXViewPort;
  538. x2 := x2 + StartXViewPort;
  539. y1 := y1 + StartYViewPort;
  540. y2 := y2 + StartYViewPort;
  541. if ClipPixels then
  542. if LineClipped(x1,y1,x2,y2,StartXViewPort,StartYViewPort,
  543. StartXViewPort+ViewWidth, StartYViewPort+ViewHeight) then
  544. exit;
  545. if (CurrentWriteMode = NotPut) then
  546. q_SetColor(not(currentcolor))
  547. else
  548. q_SetColor(currentcolor);
  549. end;
  550. EnterCriticalSection(graphdrawing);
  551. CGContextBeginPath(offscreen);
  552. CGContextMoveToPoint(offscreen,x1,y1);
  553. CGContextAddLineToPoint(offscreen,x2,y2);
  554. CGContextClosePath(offscreen);
  555. CGContextStrokePath(offscreen);
  556. UpdateScreen;
  557. LeaveCriticalSection(graphdrawing);
  558. end;
  559. procedure q_lineproc (X1, Y1, X2, Y2 : smallint);
  560. begin
  561. if (CurrentWriteMode in [OrPut,AndPut,XorPut]) or
  562. (lineinfo.LineStyle <> SolidLn) or
  563. (lineinfo.Thickness<>NormWidth) then
  564. begin
  565. LineDefault(X1,Y1,X2,Y2);
  566. exit
  567. end
  568. else
  569. begin
  570. { Convert to global coordinates. }
  571. x1 := x1 + StartXViewPort;
  572. x2 := x2 + StartXViewPort;
  573. y1 := y1 + StartYViewPort;
  574. y2 := y2 + StartYViewPort;
  575. if ClipPixels then
  576. if LineClipped(x1,y1,x2,y2,StartXViewPort,StartYViewPort,
  577. StartXViewPort+ViewWidth, StartYViewPort+ViewHeight) then
  578. exit;
  579. if (CurrentWriteMode = NotPut) then
  580. q_SetColor(not(currentcolor))
  581. else
  582. q_SetColor(currentcolor);
  583. end;
  584. EnterCriticalSection(graphdrawing);
  585. CGContextBeginPath(offscreen);
  586. CGContextMoveToPoint(offscreen,x1,y1);
  587. CGContextAddLineToPoint(offscreen,x2,y2);
  588. CGContextClosePath(offscreen);
  589. CGContextStrokePath(offscreen);
  590. UpdateScreen;
  591. LeaveCriticalSection(graphdrawing);
  592. end;
  593. procedure q_hlineproc (x, x2,y : smallint);
  594. begin
  595. if (CurrentWriteMode in [OrPut,AndPut,XorPut]) then
  596. HLineDefault(X,X2,Y)
  597. else
  598. q_lineproc_intern(x,y,x2,y);
  599. end;
  600. procedure q_vlineproc (x,y,y2: smallint);
  601. begin
  602. if (CurrentWriteMode in [OrPut,AndPut,XorPut]) then
  603. VLineDefault(x,y,y2)
  604. else
  605. q_lineproc_intern(x,y,x,y2);
  606. end;
  607. procedure q_patternlineproc (x1,x2,y: smallint);
  608. begin
  609. end;
  610. procedure q_ellipseproc (X,Y: smallint;XRadius: word;
  611. YRadius:word; stAngle,EndAngle: word; fp: PatternLineProc);
  612. begin
  613. end;
  614. procedure q_getscanlineproc (X1,X2,Y : smallint; var data);
  615. begin
  616. end;
  617. procedure q_setactivepageproc (page: word);
  618. begin
  619. end;
  620. procedure q_setvisualpageproc (page: word);
  621. begin
  622. end;
  623. procedure q_savestateproc;
  624. begin
  625. end;
  626. procedure q_restorestateproc;
  627. begin
  628. end;
  629. procedure q_setrgbpaletteproc(ColorNum, RedValue, GreenValue, BlueValue: smallint);
  630. begin
  631. { vga is only 6 bits per channel, palette values go from 0 to 252 }
  632. colorpalette[ColorNum,1]:=RedValue * (1.0/252.0);
  633. colorpalette[ColorNum,2]:=GreenValue * (1.0/252.0);
  634. colorpalette[ColorNum,3]:=BlueValue * (1.0/252.0);
  635. end;
  636. procedure q_getrgbpaletteproc (ColorNum: smallint; var RedValue, GreenValue, BlueValue: smallint);
  637. begin
  638. RedValue:=trunc(colorpalette[ColorNum,1]*252.0);
  639. GreenValue:=trunc(colorpalette[ColorNum,2]*252.0);
  640. BlueValue:=trunc(colorpalette[ColorNum,3]*252.0);
  641. end;
  642. procedure InitColors(nrColors: longint);
  643. var
  644. i: smallint;
  645. begin
  646. for i:=0 to nrColors-1 do
  647. q_setrgbpaletteproc(I,DefaultColors[i].red,
  648. DefaultColors[i].green,DefaultColors[i].blue)
  649. end;
  650. procedure q_initmodeproc;
  651. const
  652. myHIViewSpec : EventTypeSpec = (eventClass: kEventClassControl; eventKind: kEventControlDraw);
  653. var
  654. windowAttrs: WindowAttributes;
  655. contentRect: Rect;
  656. titleKey: CFStringRef;
  657. windowTitle: CFStringRef;
  658. err: OSStatus;
  659. hiviewbounds : HIRect;
  660. b: boolean;
  661. begin
  662. windowAttrs := kWindowStandardDocumentAttributes // 1
  663. or kWindowStandardHandlerAttribute
  664. or kWindowInWindowMenuAttribute
  665. or kWindowCompositingAttribute
  666. or kWindowLiveResizeAttribute
  667. or kWindowInWindowMenuAttribute
  668. or kWindowNoUpdatesAttribute;
  669. SetRect (contentRect, 0, 0,
  670. MaxX+1, MaxY+1);
  671. CreateNewWindow (kDocumentWindowClass, windowAttrs,// 3
  672. contentRect, myMainWindow);
  673. SetRect (contentRect, 0, 50,
  674. MaxX+1, 51+MaxY);
  675. SetWindowBounds(myMainWindow,kWindowContentRgn,contentrect);
  676. titleKey := CFSTR('Graph Window'); // 4
  677. windowTitle := CFCopyLocalizedString(titleKey, nil); // 5
  678. err := SetWindowTitleWithCFString (myMainWindow, windowTitle); // 6
  679. CFRelease (titleKey); // 7
  680. CFRelease (windowTitle);
  681. with contentRect do
  682. begin
  683. top:=0;
  684. left:=0;
  685. bottom:=MaxY+1;
  686. right:=MaxX+1;
  687. end;
  688. offscreen:=CreateBitmapContext(MaxX+1,MaxY+1);
  689. if (offscreen = nil) then
  690. begin
  691. _GraphResult:=grNoLoadMem;
  692. exit;
  693. end;
  694. CGContextSetShouldAntialias(offscreen,0);
  695. if (CreateHIView(myMainWindow,contentRect,graphHIView) <> noErr) then
  696. begin
  697. DisposeBitmapContext(offscreen);
  698. _GraphResult:=grError;
  699. exit;
  700. end;
  701. // HIViewFindByID( HIViewGetRoot( myMainWindow ), kHIViewWindowContentID, graphHIView );
  702. if InstallEventHandler (GetControlEventTarget (graphHIView),
  703. NewEventHandlerUPP (@MyDrawEventHandler),
  704. { GetEventTypeCount (myHIViewSpec)} 1,
  705. @myHIViewSpec,
  706. pointer(graphHIView),
  707. Nil) <> noErr then
  708. begin
  709. DisposeWindow(myMainWindow);
  710. DisposeBitmapContext(offscreen);
  711. _GraphResult:=grError;
  712. exit;
  713. end;
  714. LastColor:=-1;
  715. if (maxcolor=16) or (maxcolor=256) then
  716. InitColors(maxcolor);
  717. CGContextSetLineWidth(offscreen,1.0);
  718. { start with a black background }
  719. CGContextSetRGBStrokeColor(offscreen,0.0,0.0,0.0,1);
  720. CGContextFillRect(offscreen,CGRectMake(0,0,MaxX+1,MaxY+1));
  721. HIViewSetNeedsDisplay(graphHIView, true);
  722. ShowWindow (myMainWindow);
  723. {
  724. write('view is active: ',HIViewIsActive(graphHIView,@b));
  725. writeln(', latent: ',b);
  726. writeln('compositing enabled: ',HIViewIsCompositingEnabled(graphHIView));
  727. writeln('visible before: ',HIViewIsVisible(graphHIView));
  728. write('drawing enabled: ',HIViewIsDrawingEnabled(graphHIView));
  729. writeln(', latent: ',b);
  730. write('view is enabled: ',HIViewIsEnabled(graphHIView,@b));
  731. writeln(', latent: ',b);
  732. err := HIViewGetBounds(graphHIView,hiviewbounds);
  733. writeln('err, ',err,' (',hiviewbounds.origin.x:0:2,',',hiviewbounds.origin.y:0:2,'),(',hiviewbounds.size.width:0:2,',',hiviewbounds.size.height:0:2,')');
  734. }
  735. end;
  736. {************************************************************************}
  737. {* General routines *}
  738. {************************************************************************}
  739. procedure q_donegraph;
  740. begin
  741. If not isgraphmode then
  742. begin
  743. _graphresult := grnoinitgraph;
  744. exit
  745. end;
  746. RestoreVideoState;
  747. DisposeWindow(myMainWindow);
  748. DisposeBitmapContext(offscreen);
  749. isgraphmode := false;
  750. end;
  751. procedure CloseGraph;
  752. var
  753. event : EventRef;
  754. myQueue: EventQueueRef;
  755. begin
  756. if (CreateEvent(nil, kEventClassFPCGraph, kEventCloseGraph, GetCurrentEventTime(), 0, event) <> noErr) then
  757. begin
  758. _GraphResult:=grError;
  759. exit;
  760. end;
  761. myQueue := GetCurrentEventQueue;
  762. if (SetEventParameter(event, FOUR_CHAR_CODE('Src '), typeVoidPtr, sizeof(EventQueueRef), @myQueue) <> noErr) then
  763. begin
  764. ReleaseEvent(event);
  765. _GraphResult:=grError;
  766. end;
  767. if (PostEventToQueue(MainEventQueue,event,kEventPriorityStandard) <> noErr) then
  768. begin
  769. ReleaseEvent(event);
  770. _GraphResult:=grError;
  771. exit;
  772. end;
  773. if (ReceiveNextEvent(length(GraphClosedSpec),@GraphClosedSpec,kEventDurationForever,true,event) <> noErr) then
  774. runerror(218);
  775. ReleaseEvent(event);
  776. end;
  777. procedure SendInitGraph;
  778. var
  779. event : EventRef;
  780. myQueue: EventQueueRef;
  781. begin
  782. if (CreateEvent(nil, kEventClassFPCGraph, kEventInitGraph, GetCurrentEventTime(), 0, event) <> noErr) then
  783. begin
  784. _GraphResult:=grError;
  785. exit;
  786. end;
  787. myQueue := GetCurrentEventQueue;
  788. if (SetEventParameter(event, FOUR_CHAR_CODE('Src '), typeVoidPtr, sizeof(EventQueueRef), @myQueue) <> noErr) then
  789. begin
  790. ReleaseEvent(event);
  791. _GraphResult:=grError;
  792. exit;
  793. end;
  794. if (PostEventToQueue(MainEventQueue,event,kEventPriorityStandard) <> noErr) then
  795. begin
  796. ReleaseEvent(event);
  797. _GraphResult:=grError;
  798. exit;
  799. end;
  800. if (ReceiveNextEvent(length(GraphInitedSpec),@GraphInitedSpec,kEventDurationForever,true,event) <> noErr) then
  801. runerror(218);
  802. ReleaseEvent(event);
  803. end;
  804. function QueryAdapterInfo:PModeInfo;
  805. { This routine returns the head pointer to the list }
  806. { of supported graphics modes. }
  807. { Returns nil if no graphics mode supported. }
  808. { This list is READ ONLY! }
  809. var
  810. mode: TModeInfo;
  811. i : longint;
  812. begin
  813. QueryAdapterInfo := ModeList;
  814. { If the mode listing already exists... }
  815. { simply return it, without changing }
  816. { anything... }
  817. if assigned(ModeList) then
  818. exit;
  819. SaveVideoState:=@q_savevideostate;
  820. RestoreVideoState:=@q_restorevideostate;
  821. // For I:=0 to GLastMode do
  822. i := 10;
  823. begin
  824. begin
  825. InitMode(Mode);
  826. With Mode do
  827. begin
  828. ModeNumber:=I;
  829. ModeName:=ModeNames[i];
  830. // Pretend we are VGA always.
  831. DriverNumber := VGA;
  832. // MaxX is number of pixels in X direction - 1
  833. MaxX:=640-1;
  834. // same for MaxY
  835. MaxY:=480-1;
  836. YAspect:=10000;
  837. if ((MaxX+1)*35=(MaxY+1)*64) then
  838. XAspect:=7750
  839. else if ((MaxX+1)*20=(MaxY+1)*64) then
  840. XAspect:=4500
  841. else if ((MaxX+1)*40=(MaxY+1)*64) then
  842. XAspect:=8333
  843. else { assume 4:3 }
  844. XAspect:=10000;
  845. MaxColor := 256;
  846. PaletteSize := MaxColor;
  847. HardwarePages := 0;
  848. // necessary hooks ...
  849. DirectPutPixel := @q_DirectPixelProc;
  850. GetPixel := @q_GetPixelProc;
  851. PutPixel := @q_PutPixelProc;
  852. { May be implemented later: }
  853. HLine := @q_HLineProc;
  854. VLine := @q_VLineProc;
  855. { GetScanLine := @q_GetScanLineProc;}
  856. ClearViewPort := @q_ClrViewProc;
  857. SetRGBPalette := @q_SetRGBPaletteProc;
  858. GetRGBPalette := @q_GetRGBPaletteProc;
  859. { These are not really implemented yet:
  860. PutImage := @q_PutImageProc;
  861. GetImage := @q_GetImageProc;}
  862. { If you use the default getimage/putimage, you also need the default
  863. imagesize! (JM)
  864. ImageSize := @q_ImageSizeProc; }
  865. { Add later maybe ?
  866. SetVisualPage := SetVisualPageProc;
  867. SetActivePage := SetActivePageProc; }
  868. Line := @q_LineProc;
  869. {
  870. InternalEllipse:= @q_EllipseProc;
  871. PatternLine := @q_PatternLineProc;
  872. }
  873. InitMode := @SendInitGraph;
  874. end;
  875. AddMode(Mode);
  876. end;
  877. end;
  878. end;
  879. { ************************************************* }
  880. function GraphEventHandler (myHandler: EventHandlerCallRef;
  881. event: EventRef; userData: pointer): OSStatus; mwpascal;
  882. var
  883. source: EventQueueRef;
  884. newEvent: EventRef;
  885. begin
  886. // writeln('in GraphEventHandler, event: ',FourCharArray(GetEventKind(event)));
  887. newEvent := nil;
  888. case GetEventKind(event) of
  889. kEventInitGraph:
  890. begin
  891. q_initmodeproc;
  892. if (GetEventParameter(event,FOUR_CHAR_CODE('Src '), typeVoidPtr, nil, sizeof(EventQueueRef), nil, @source) <> noErr) then
  893. runerror(218);
  894. if (CreateEvent(nil, kEventClassFPCGraph, kEventGraphInited, GetCurrentEventTime(), 0, newEvent) <> noErr) then
  895. runerror(218);
  896. end;
  897. kEventCloseGraph:
  898. begin
  899. q_donegraph;
  900. if (GetEventParameter(event,FOUR_CHAR_CODE('Src '), typeVoidPtr, nil, sizeof(EventQueueRef), nil, @source) <> noErr) then
  901. runerror(218);
  902. if (CreateEvent(nil, kEventClassFPCGraph, kEventGraphClosed, GetCurrentEventTime(), 0, newEvent) <> noErr) then
  903. runerror(218);
  904. end;
  905. kEventFlush:
  906. begin
  907. HIViewSetNeedsDisplay(graphHIView, true);
  908. end;
  909. kEventQuit:
  910. begin
  911. QuitApplicationEventLoop;
  912. end;
  913. end;
  914. if assigned(newEvent) then
  915. if PostEventToQueue(source,newEvent,kEventPriorityStandard) <> noErr then
  916. runerror(218);
  917. GraphEventHandler := noErr;
  918. ReleaseEvent(event);
  919. end;
  920. var
  921. proctorun: TGraphProgram;
  922. function wrapper(p: pointer): longint;
  923. (*
  924. var
  925. event : EventRef;
  926. *)
  927. begin
  928. wrapper:=proctorun(nil);
  929. halt(wrapper);
  930. (*
  931. if (CreateEvent(nil, kEventClassFPCGraph, kEventQuit, GetCurrentEventTime(), 0, event) <> noErr) then
  932. exit;
  933. if (PostEventToQueue(MainEventQueue,event,kEventPriorityLow) <> noErr) then
  934. begin
  935. ReleaseEvent(event);
  936. halt(wrapper);
  937. end;
  938. *)
  939. end;
  940. procedure StartGraphProgram(p: TGraphProgram);
  941. var
  942. taskid: mptaskid;
  943. eventRec: eventrecord;
  944. begin
  945. if InstallEventHandler (GetApplicationEventTarget,
  946. NewEventHandlerUPP (@GraphEventHandler),
  947. length(allGraphSpec),
  948. @allGraphSpec,
  949. nil,
  950. nil) <> noErr then
  951. begin
  952. _GraphResult:=grError;
  953. exit;
  954. end;
  955. proctorun:=p;
  956. { main program has to be the first one to access the event queue, see }
  957. { http://lists.apple.com/archives/carbon-dev/2007/Jun/msg00612.html }
  958. eventavail(0,eventRec);
  959. maineventqueue:=GetMainEventQueue;
  960. BeginThread(@wrapper);
  961. RunApplicationEventLoop;
  962. end;
  963. initialization
  964. initcriticalsection(graphdrawing);
  965. InitializeGraph;
  966. finalization
  967. donecriticalsection(graphdrawing);
  968. end.