video.pp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2006 by Karoly Balogh
  4. member of the Free Pascal development team
  5. Video unit for Amiga and MorphOS
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit Video;
  13. {.$define VIDEODEBUG}
  14. {.$define WITHBUFFERING}
  15. {
  16. Date: 2013-01-09
  17. What: Adjusted FPC video unit for AROS (/AmigaOS?)
  18. goal:
  19. ---------------------------------------------------------------------------
  20. Attempt to add user-on-demand support for AROS Fullscreen to the FPC video
  21. unit.
  22. }
  23. interface
  24. uses
  25. amigados, intuition, utility, sysutils;
  26. {$i videoh.inc}
  27. { Amiga specific calls, to help interaction between Keyboard, Mouse and
  28. Video units, and Free Vision }
  29. procedure GotCloseWindow;
  30. function HasCloseWindow: boolean;
  31. procedure GotResizeWindow;
  32. function HasResizeWindow(var winw:longint; var winh: longint): boolean;
  33. var
  34. VideoWindow: PWindow;
  35. implementation
  36. uses
  37. exec, agraphics;
  38. {$i video.inc}
  39. {$i videodata.inc}
  40. const
  41. VIDEOSCREENNAME = 'FPC Video Screen Output';
  42. var
  43. OS_Screen : PScreen = nil; // To hold our screen, when necessary
  44. FPC_VIDEO_FULLSCREEN : Boolean = False; // Global that defines when we need to attempt opening on own scren
  45. var
  46. VideoColorMap : PColorMap;
  47. VideoPens : array[0..15] of LongInt;
  48. OldCursorX,
  49. OldCursorY : LongInt;
  50. CursorType : Word;
  51. OldCursorType : Word;
  52. {$ifdef WITHBUFFERING}
  53. BitmapWidth, BitmapHeight: Integer;
  54. BufRp: PRastPort;
  55. {$endif}
  56. GotCloseWindowMsg : Boolean;
  57. GotResizeWindowMsg : Boolean;
  58. LastL, LastT: Integer;
  59. LastW, LastH: Integer;
  60. WindowForReqSave: PWindow;
  61. Process: PProcess;
  62. (*
  63. GetScreen: pScreen;
  64. Tries to open a custom screen, which attempt to clone the workbench,
  65. and returns the pointer to the screen. Result can be nil when failed
  66. otherwise the screen got opened correctly.
  67. *)
  68. function _OpenScreenTags(a: Pointer; tags: array of PtrUInt): pScreen;
  69. begin
  70. _OpenScreenTags:=OpenScreenTagList(a, @tags);
  71. end;
  72. Function GetScreen: pScreen;
  73. begin
  74. GetScreen:=_OpenScreenTags(nil,[
  75. SA_Title , PtrUInt(PChar(VIDEOSCREENNAME)),
  76. SA_Left , 0,
  77. SA_Top , 0,
  78. SA_ShowTitle , 0, // Do not show the screen's TitleBar
  79. SA_Type , PUBLICSCREEN_F, // pubscreen
  80. SA_PubName , PtrUInt(PChar(VIDEOSCREENNAME)),
  81. SA_Quiet , 1,
  82. SA_LikeWorkbench , 1 // Let OS
  83. ]);
  84. {$ifdef VIDEODEBUG}
  85. if (GetScreen <> nil) then
  86. Writeln('DEBUG: Opened a new screen')
  87. else
  88. Writeln('ERROR: Failed to open new screen');
  89. {$endif}
  90. end;
  91. (*
  92. GetWindow: pWindow;
  93. Tries to create and open a window. Returns the pointer to
  94. the window or nil in case of failure.
  95. The routine keeps the global FPC_FULL_SCREEM option into
  96. account and act accordingly.
  97. In windowed mode it returns a window with another kind of
  98. settings then when it has to reside on it's own customscreen.
  99. *)
  100. function _OpenWindowTags(a: Pointer; tags: array of PtrUInt): pWindow;
  101. begin
  102. _OpenWindowTags:=OpenWindowTagList(a, @tags);
  103. end;
  104. Function GetWindow: PWindow;
  105. begin
  106. if FPC_VIDEO_FULLSCREEN then
  107. begin
  108. OS_Screen := GetScreen;
  109. If OS_Screen = nil then
  110. Exit;
  111. {$ifdef VIDEODEBUG}
  112. WriteLn('DEBUG: Opened customscreen succesfully');
  113. {$endif}
  114. GetWindow:=_OpenWindowTags(nil, [
  115. WA_CustomScreen, PtrUint(OS_Screen),
  116. WA_Left , 0,
  117. WA_Top , 0,
  118. WA_InnerWidth , (OS_Screen^.Width div 8) * 8,
  119. WA_InnerHeight, (OS_Screen^.Height div 16) * 16,
  120. WA_AutoAdjust , 1,
  121. WA_Activate , 1,
  122. WA_Borderless , 1,
  123. WA_BackDrop , 1,
  124. WA_FLAGS , (WFLG_GIMMEZEROZERO or WFLG_REPORTMOUSE or WFLG_RMBTRAP or
  125. WFLG_SMART_REFRESH or WFLG_NOCAREREFRESH),
  126. WA_IDCMP , (IDCMP_RAWKEY or
  127. IDCMP_MOUSEMOVE or IDCMP_MOUSEBUTTONS or
  128. IDCMP_CHANGEWINDOW or IDCMP_CLOSEWINDOW)
  129. ]);
  130. end else
  131. begin // Windowed Mode
  132. GetWindow:=_OpenWindowTags(nil, [
  133. WA_Left , LastL,
  134. WA_Top , LastT,
  135. WA_InnerWidth , LastW*8,
  136. WA_InnerHeight, LastH*16,
  137. WA_MaxWidth , 32768,
  138. WA_MaxHeight , 32768,
  139. WA_Title , PtrUInt(PChar('FPC Video Window Output')),
  140. WA_Activate , 1,
  141. WA_FLAGS , (WFLG_GIMMEZEROZERO or WFLG_REPORTMOUSE or
  142. WFLG_SMART_REFRESH or WFLG_NOCAREREFRESH or
  143. WFLG_DRAGBAR or WFLG_DEPTHGADGET or WFLG_SIZEGADGET or
  144. WFLG_SIZEBBOTTOM or WFLG_RMBTRAP or WFLG_CLOSEGADGET),
  145. WA_IDCMP , (IDCMP_RAWKEY or
  146. IDCMP_MOUSEMOVE or IDCMP_MOUSEBUTTONS or
  147. IDCMP_CHANGEWINDOW or IDCMP_CLOSEWINDOW)//,
  148. ]);
  149. end;
  150. Process := PProcess(FindTask(nil));
  151. WindowForReqSave := Process^.pr_WindowPtr;
  152. Process^.pr_WindowPtr := GetWindow;
  153. {$ifdef VIDEODEBUG}
  154. If GetWindow <> nil then
  155. WriteLn('DEBUG: Sucessfully opened videounit Window')
  156. else
  157. WriteLn('ERROR: Failed to open videounit Window');
  158. {$endif}
  159. end;
  160. // ==========================================================================
  161. // ==
  162. // == Original source code continues, with minor adjustments
  163. // ==
  164. // ==========================================================================
  165. procedure SysInitVideo;
  166. var
  167. Counter: LongInt;
  168. begin
  169. {$ifdef VIDEODEBUG}
  170. WriteLn('FULLSCREEN VIDEO UNIT MODIFICATION v2');
  171. if FPC_VIDEO_FULLSCREEN then
  172. WriteLn('DEBUG: Recognized fullscreen mode')
  173. else
  174. WriteLn('DEBUG: Recognized windowed mode');
  175. {$endif}
  176. // fill videobuf and oldvideobuf with different bytes, to allow proper first draw
  177. FillDword(VideoBuf^, VideoBufSize div 4, $1234D3AD);
  178. FillDword(OldVideoBuf^, VideoBufSize div 4, $4321BEEF);
  179. VideoWindow := GetWindow;
  180. // nice hardcode values are probably going to screw up things
  181. // so wee neeed a way to detrmined how many chars could be on
  182. // the screen in both directions. And a bit accurate.
  183. if FPC_VIDEO_FULLSCREEN then
  184. begin
  185. // just to make sure that we are going to use the window width
  186. // and height instead of the one from the screen.
  187. // This is to circumvent that the window (or virtual window from
  188. // vision based on characters pixels * characters in both
  189. // dimensions) is actually smaller then the window it resides on.
  190. //
  191. // Can happen for instance when the window does not hide it's
  192. // borders or title as intended.
  193. ScreenWidth := VideoWindow^.GZZWidth div 8;
  194. ScreenHeight := VideoWindow^.GZZHeight div 16;
  195. ScreenColor := False;
  196. {$ifdef VIDEODEBUG}
  197. Writeln('DEBUG: Fullscreen - windowed - Width * Heigth = ',ScreenWidth,' * ',ScreenHeight);
  198. {$endif}
  199. end else
  200. begin
  201. ScreenWidth := LastW;
  202. ScreenHeight := LastH;
  203. ScreenColor := True;
  204. end;
  205. {$ifdef WITHBUFFERING}
  206. BufRp^.Bitmap := AllocBitmap(VideoWindow^.GZZWidth, VideoWindow^.GZZHeight, VideoWindow^.RPort^.Bitmap^.Depth, BMF_CLEAR, VideoWindow^.RPort^.Bitmap);
  207. BitmapWidth := VideoWindow^.GZZWidth;
  208. BitmapHeight := VideoWindow^.GZZHeight;
  209. {$endif}
  210. { viewpostcolormap info }
  211. videoColorMap := pScreen(videoWindow^.WScreen)^.ViewPort.ColorMap;
  212. for Counter := 0 to 15 do
  213. begin
  214. VideoPens[Counter] := ObtainBestPenA(VideoColorMap,
  215. vgacolors[counter, 0] shl 24, vgacolors[counter, 1] shl 24, vgacolors[counter, 2] shl 24, nil);
  216. {$ifdef VIDEODEBUG}
  217. If VideoPens[Counter] = -1 then
  218. WriteLn('errr color[',Counter,'] = ', VideoPens[Counter])
  219. else
  220. WriteLn('good color[',Counter,'] = ', VideoPens[Counter]);
  221. {$endif}
  222. end;
  223. CursorX := 0;
  224. CursorY := 0;
  225. OldCursorX := 0;
  226. OldCursorY := 0;
  227. CursorType := crHidden;
  228. OldCursorType := crHidden;
  229. GotCloseWindowMsg := false;
  230. GotResizeWindowMsg := false;
  231. end;
  232. procedure SysDoneVideo;
  233. var
  234. Counter: LongInt;
  235. begin
  236. if VideoWindow <> nil then
  237. begin
  238. Process^.pr_WindowPtr := WindowForReqSave;
  239. if not FPC_VIDEO_FULLSCREEN then
  240. begin
  241. LastL := VideoWindow^.LeftEdge;
  242. LastT := VideoWindow^.TopEdge;
  243. end;
  244. CloseWindow(videoWindow);
  245. end;
  246. {$ifdef WITHBUFFERING}
  247. FreeBitmap(BufRp^.Bitmap);
  248. BufRp^.Bitmap := nil;
  249. {$endif}
  250. VideoWindow := nil;
  251. for Counter := 0 to 15 do
  252. ReleasePen(VideoColorMap, VideoPens[Counter]);
  253. if ((FPC_VIDEO_FULLSCREEN) and (OS_Screen <> nil)) then
  254. begin
  255. CloseScreen(OS_Screen);
  256. end;
  257. end;
  258. function SysSetVideoMode(const Mode: TVideoMode): Boolean;
  259. var
  260. dx: integer;
  261. dy: integer;
  262. begin
  263. if ScreenColor <> Mode.Color then
  264. begin
  265. SysDoneVideo;
  266. FPC_VIDEO_FULLSCREEN := not Mode.color;
  267. if not FPC_VIDEO_FULLSCREEN then
  268. begin
  269. LastT := 50;
  270. LastL := 50;
  271. LastW := 80;
  272. LastH := 25;
  273. end;
  274. SysInitVideo;
  275. end else
  276. if not FPC_VIDEO_FULLSCREEN then
  277. begin
  278. dx := (Mode.col * 8) - VideoWindow^.GZZWidth;
  279. dy := (Mode.row * 16) - VideoWindow^.GZZHeight;
  280. SizeWindow(videoWindow, dx, dy);
  281. end;
  282. ScreenWidth := Mode.col;
  283. ScreenHeight := Mode.row;
  284. LastW := Mode.Col;
  285. LastH := Mode.Row;
  286. ScreenColor := Mode.color;
  287. SysSetVideoMode := True;
  288. end;
  289. var
  290. OldSH, OldSW : longint;
  291. procedure SysClearScreen;
  292. begin
  293. oldSH := -1;
  294. oldSW := -1;
  295. UpdateScreen(True);
  296. end;
  297. procedure DrawChar(rp: PRastPort; x, y: LongInt; crType: Word);
  298. var
  299. TmpCharData: Word;
  300. TmpChar: Byte;
  301. TmpFGColor: Byte;
  302. TmpBGColor: Byte;
  303. sX, sY: LongInt;
  304. begin
  305. TmpCharData := VideoBuf^[y * ScreenWidth + x];
  306. TmpChar := TmpCharData and $0ff;
  307. TmpFGColor := (TmpCharData shr 8) and %00001111;
  308. TmpBGColor := (TmpCharData shr 12) and %00000111;
  309. sX := x * 8;
  310. sY := y * 16;
  311. if crType <> crBlock then
  312. begin
  313. SetABPenDrMd(rp, VideoPens[TmpFGColor], VideoPens[tmpBGColor], JAM2);
  314. end else
  315. begin
  316. { in case of block cursor, swap fg/bg colors
  317. and BltTemplate() below will take care of everything }
  318. SetABPenDrMd(rp, VideoPens[tmpBGColor], VideoPens[tmpFGColor], JAM2);
  319. end;
  320. BltTemplate(@Vgafont[tmpChar, 0], 0, 1, rp, sX, sY, 8, 16);
  321. if crType = crUnderLine then
  322. begin
  323. { draw two lines at the bottom of the char, in case of underline cursor }
  324. GfxMove(rp, sX, sY + 14); Draw(rp, sX + 7, sY + 14);
  325. GfxMove(rp, sX, sY + 15); Draw(rp, sX + 7, sY + 15);
  326. end;
  327. end;
  328. procedure SysUpdateScreen(Force: Boolean);
  329. var
  330. BufCounter: Longint;
  331. SmallForce: Boolean;
  332. Counter, CounterX, CounterY: LongInt;
  333. //BufRp: PRastPort;
  334. t: Double;
  335. NumChanged: Integer;
  336. begin
  337. SmallForce := False;
  338. // override forced update when screen dimensions haven't changed
  339. if Force then
  340. begin
  341. if (OldSH = ScreenHeight) and (OldSW = ScreenWidth) then
  342. Force:=false
  343. else
  344. begin
  345. OldSH := ScreenHeight;
  346. OldSW := ScreenWidth;
  347. end;
  348. end;
  349. if Force then
  350. begin
  351. SmallForce:=true;
  352. end else
  353. begin
  354. Counter:=0;
  355. while not smallforce and (Counter < (VideoBufSize div 4) - 1) do
  356. begin
  357. SmallForce := (PDWord(VideoBuf)[Counter] <> PDWord(OldVideoBuf)[Counter]);
  358. inc(Counter);
  359. end;
  360. end;
  361. {$ifdef WITHBUFFERING}
  362. if (VideoWindow^.GZZWidth > BitmapWidth) or (VideoWindow^.GZZHeight > BitmapHeight) then
  363. begin
  364. FreeBitmap(BufRp^.Bitmap);
  365. BufRp^.Bitmap := AllocBitmap(VideoWindow^.GZZWidth, VideoWindow^.GZZHeight, VideoWindow^.RPort^.Bitmap^.Depth, BMF_CLEAR, VideoWindow^.RPort^.Bitmap);
  366. BitmapWidth := VideoWindow^.GZZWidth;
  367. BitmapHeight := VideoWindow^.GZZHeight;
  368. Force := True;
  369. Smallforce := True;
  370. end;
  371. {$endif}
  372. BufCounter:=0;
  373. NumChanged:=0;
  374. if Smallforce then
  375. begin
  376. //t := now();
  377. for CounterY := 0 to ScreenHeight - 1 do
  378. begin
  379. for CounterX := 0 to ScreenWidth - 1 do
  380. begin
  381. if (VideoBuf^[BufCounter] <> OldVideoBuf^[BufCounter]) or Force then
  382. begin
  383. {$ifdef WITHBUFFERING}
  384. DrawChar(BufRp, CounterX, CounterY, crHidden);
  385. {$else}
  386. DrawChar(VideoWindow^.RPort, CounterX, CounterY, crHidden);
  387. {$endif}
  388. OldVideoBuf^[BufCounter] := VideoBuf^[BufCounter];
  389. Inc(NumChanged);
  390. end;
  391. Inc(BufCounter);
  392. end;
  393. end;
  394. //if NumChanged > 100 then
  395. // writeln('redraw time: ', floattoStrF((Now-t)* 24 * 60 * 60 * 1000000 / NumChanged, fffixed, 8,3), ' us/char' ); // ms
  396. end;
  397. if (CursorType <> OldCursorType) or
  398. (CursorX <> OldCursorX) or (CursorY <> OldCursorY) or
  399. SmallForce then
  400. begin
  401. {$ifdef WITHBUFFERING}
  402. DrawChar(BufRp, OldCursorY, OldCursorX, crHidden);
  403. DrawChar(BufRp, CursorY, CursorX, CursorType);
  404. {$else}
  405. DrawChar(VideoWindow^.RPort, OldCursorY, OldCursorX, crHidden);
  406. DrawChar(VideoWindow^.RPort, CursorY, CursorX, CursorType);
  407. {$endif}
  408. OldCursorX := CursorX;
  409. OldCursorY := CursorY;
  410. OldcursorType := CursorType;
  411. end;
  412. {$ifdef WITHBUFFERING}
  413. BltBitMapRastPort(BufRp^.Bitmap, 0, 0, VideoWindow^.RPort, 0, 0, ScreenWidth * 8, ScreenHeight * 16, $00C0);
  414. {$endif}
  415. end;
  416. procedure SysSetCursorPos(NewCursorX, NewCursorY: Word);
  417. begin
  418. CursorX := NewCursorY;
  419. CursorY := NewCursorX;
  420. SysUpdateScreen(False);
  421. end;
  422. function SysGetCapabilities: Word;
  423. begin
  424. SysGetCapabilities := cpColor or cpChangeCursor;
  425. end;
  426. function SysGetCursorType: Word;
  427. begin
  428. SysGetCursorType := cursorType;
  429. end;
  430. procedure SysSetCursorType(NewType: Word);
  431. begin
  432. cursorType := newType;
  433. { FIXME: halfBlock cursors are not supported for now
  434. by the rendering code }
  435. if CursorType = crHalfBlock then
  436. cursorType := crBlock;
  437. SysUpdateScreen(False);
  438. end;
  439. // Amiga specific calls
  440. procedure GotCloseWindow;
  441. begin
  442. GotCloseWindowMsg := True;
  443. end;
  444. function HasCloseWindow: Boolean;
  445. begin
  446. HasCloseWindow := GotCloseWindowMsg;
  447. GotCloseWindowMsg := False;
  448. end;
  449. procedure GotResizeWindow;
  450. begin
  451. GotResizeWindowMsg := True;
  452. end;
  453. function HasResizeWindow(var WinW: LongInt; var WinH: LongInt): Boolean;
  454. begin
  455. //writeln('Has resize ', GotResizeWindowMsg);
  456. WinW := 0;
  457. WinH := 0;
  458. HasResizeWindow := GotResizeWindowMsg;
  459. if Assigned(VideoWindow) then
  460. begin
  461. //writeln('resize');
  462. WinW := VideoWindow^.GZZWidth div 8;
  463. WinH := VideoWindow^.GZZHeight div 16;
  464. LastW := WinW;
  465. LastH := WinH;
  466. end;
  467. GotResizeWindowMsg := False;
  468. end;
  469. function SysGetVideoModeCount: Word;
  470. begin
  471. SysGetVideoModeCount := 2;
  472. end;
  473. function SysGetVideoModeData(Index: Word; var Mode: TVideoMode): Boolean;
  474. var
  475. Screen: PScreen;
  476. begin
  477. case Index of
  478. 0: begin
  479. Mode.Col := 80;
  480. Mode.Row := 25;
  481. Mode.Color := True;
  482. end;
  483. 1: begin
  484. Screen := LockPubScreen('Workbench');
  485. Mode.Col := Screen^.Width div 8;
  486. Mode.Row := Screen^.Height div 16;
  487. UnlockPubScreen('Workbench', Screen);
  488. Mode.Color := False;
  489. end;
  490. end;
  491. SysGetVideoModeData := True;
  492. end;
  493. const
  494. SysVideoDriver : TVideoDriver = (
  495. InitDriver : @SysInitVideo;
  496. DoneDriver : @SysDoneVideo;
  497. UpdateScreen : @SysUpdateScreen;
  498. ClearScreen : @SysClearScreen;
  499. SetVideoMode : @SysSetVideoMode;
  500. GetVideoModeCount : @SysGetVideoModeCount;
  501. GetVideoModeData : @SysGetVideoModeData;
  502. SetCursorPos : @SysSetCursorPos;
  503. GetCursorType : @SysGetCursorType;
  504. SetCursorType : @SysSetCursorType;
  505. GetCapabilities : @SysGetCapabilities
  506. );
  507. initialization
  508. SetVideoDriver(SysVideoDriver);
  509. LastT := 50;
  510. LastL := 50;
  511. LastW := 80;
  512. LastH := 25;
  513. {$ifdef WITHBUFFERING}
  514. BufRp := CreateRastPort;
  515. BufRp^.Layer := nil;
  516. BufRp^.Bitmap := nil;
  517. {$endif}
  518. finalization
  519. {$ifdef WITHBUFFERING}
  520. if Assigned(BufRp^.Bitmap) then
  521. FreeBitmap(BufRp^.Bitmap);
  522. FreeRastPort(BufRp);
  523. {$endif}
  524. end.