graph.pp 31 KB

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