graph.pp 30 KB

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