video.pp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by Florian Klaempfl
  5. member of the Free Pascal development team
  6. Video unit for Win32
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. **********************************************************************}
  13. unit Video;
  14. interface
  15. {$i videoh.inc}
  16. implementation
  17. uses
  18. windows,dos;
  19. {$i video.inc}
  20. var
  21. OldVideoBuf : PVideoBuf;
  22. ConsoleInfo : TConsoleScreenBufferInfo;
  23. ConsoleCursorInfo : TConsoleCursorInfo;
  24. MaxVideoBufSize : DWord;
  25. procedure InitVideo;
  26. begin
  27. ScreenColor:=true;
  28. GetConsoleScreenBufferInfo(TextRec(Output).Handle, ConsoleInfo);
  29. GetConsoleCursorInfo(TextRec(Output).Handle, ConsoleCursorInfo);
  30. with ConsoleInfo.srWindow do
  31. begin
  32. ScreenWidth:=right-left+1;
  33. ScreenHeight:=bottom-top+1;
  34. end;
  35. { srWindow is sometimes bigger then dwMaximumWindowSize
  36. this led to wrong ScreenWidth and ScreenHeight values PM }
  37. { damned: its also sometimes less !! PM }
  38. with ConsoleInfo.dwMaximumWindowSize do
  39. begin
  40. {if ScreenWidth>X then}
  41. ScreenWidth:=X;
  42. {if ScreenHeight>Y then}
  43. ScreenHeight:=Y;
  44. end;
  45. { TDrawBuffer only has FVMaxWidth elements
  46. larger values lead to crashes }
  47. if ScreenWidth> FVMaxWidth then
  48. ScreenWidth:=FVMaxWidth;
  49. CursorX:=ConsoleInfo.dwCursorPosition.x;
  50. CursorY:=ConsoleInfo.dwCursorPosition.y;
  51. if not ConsoleCursorInfo.bvisible then
  52. CursorLines:=0
  53. else
  54. CursorLines:=ConsoleCursorInfo.dwSize;
  55. { allocate back buffer }
  56. MaxVideoBufSize:= ScreenWidth * ScreenHeight * 2;
  57. VideoBufSize:=ScreenWidth*ScreenHeight*2;
  58. GetMem(VideoBuf,MaxVideoBufSize);
  59. GetMem(OldVideoBuf,MaxVideoBufSize);
  60. {ClearScreen; not needed PM }
  61. end;
  62. procedure DoneVideo;
  63. begin
  64. { ClearScreen; also not needed PM }
  65. SetCursorType(crUnderLine);
  66. { SetCursorPos(0,0); also not needed PM }
  67. FreeMem(VideoBuf,MaxVideoBufSize);
  68. FreeMem(OldVideoBuf,MaxVideoBufSize);
  69. VideoBufSize:=0;
  70. end;
  71. function GetCapabilities: Word;
  72. begin
  73. GetCapabilities:=cpColor or cpChangeCursor;
  74. end;
  75. procedure SetCursorPos(NewCursorX, NewCursorY: Word);
  76. var
  77. pos : COORD;
  78. begin
  79. pos.x:=NewCursorX;
  80. pos.y:=NewCursorY;
  81. SetConsoleCursorPosition(TextRec(Output).Handle,pos);
  82. CursorX:=pos.x;
  83. CursorY:=pos.y;
  84. end;
  85. function GetCursorType: Word;
  86. begin
  87. GetConsoleCursorInfo(TextRec(Output).Handle,ConsoleCursorInfo);
  88. if not ConsoleCursorInfo.bvisible then
  89. GetCursorType:=crHidden
  90. else
  91. case ConsoleCursorInfo.dwSize of
  92. 1..30:
  93. GetCursorType:=crUnderline;
  94. 31..70:
  95. GetCursorType:=crHalfBlock;
  96. 71..100:
  97. GetCursorType:=crBlock;
  98. end;
  99. end;
  100. procedure SetCursorType(NewType: Word);
  101. begin
  102. GetConsoleCursorInfo(TextRec(Output).Handle,ConsoleCursorInfo);
  103. if newType=crHidden then
  104. ConsoleCursorInfo.bvisible:=false
  105. else
  106. begin
  107. ConsoleCursorInfo.bvisible:=true;
  108. case NewType of
  109. crUnderline:
  110. ConsoleCursorInfo.dwSize:=10;
  111. crHalfBlock:
  112. ConsoleCursorInfo.dwSize:=50;
  113. crBlock:
  114. ConsoleCursorInfo.dwSize:=99;
  115. end
  116. end;
  117. SetConsoleCursorInfo(TextRec(Output).Handle,ConsoleCursorInfo);
  118. end;
  119. function DefaultVideoModeSelector(const VideoMode: TVideoMode; Params: Longint): Boolean;
  120. begin
  121. end;
  122. procedure ClearScreen;
  123. begin
  124. FillWord(VideoBuf^,VideoBufSize div 2,$0720);
  125. UpdateScreen(true);
  126. end;
  127. {$IFDEF FPC}
  128. function WriteConsoleOutput(hConsoleOutput:HANDLE; lpBuffer:pointer; dwBufferSize:COORD; dwBufferCoord:COORD;
  129. var lpWriteRegion:SMALL_RECT):WINBOOL; external 'kernel32' name 'WriteConsoleOutputA';
  130. {$ENDIF}
  131. procedure UpdateScreen(Force: Boolean);
  132. type TmpRec = Array[0..(1024*32) - 1] of TCharInfo;
  133. type WordRec = record
  134. One, Two: Byte;
  135. end; { wordrec }
  136. var
  137. BufSize,
  138. BufCoord : COORD;
  139. WriteRegion : SMALL_RECT;
  140. LineBuf : ^TmpRec;
  141. BufCounter : Longint;
  142. LineCounter,
  143. ColCounter : Longint;
  144. smallforce : boolean;
  145. {
  146. begin
  147. if LockUpdateScreen<>0 then
  148. exit;
  149. if not force then
  150. begin
  151. asm
  152. movl VideoBuf,%esi
  153. movl OldVideoBuf,%edi
  154. movl VideoBufSize,%ecx
  155. shrl $2,%ecx
  156. repe
  157. cmpsl
  158. setne force
  159. end;
  160. end;
  161. if Force then
  162. begin
  163. BufSize.X := ScreenWidth;
  164. BufSize.Y := ScreenHeight;
  165. BufCoord.X := 0;
  166. BufCoord.Y := 0;
  167. with WriteRegion do
  168. begin
  169. Top :=0;
  170. Left :=0;
  171. Bottom := ScreenHeight-1;
  172. Right := ScreenWidth-1;
  173. end;
  174. New(LineBuf);
  175. BufCounter := 0;
  176. for LineCounter := 1 to ScreenHeight do
  177. begin
  178. for ColCounter := 1 to ScreenWidth do
  179. begin
  180. LineBuf^[BufCounter].UniCodeChar := WordRec(VideoBuf^[BufCounter]).One;
  181. LineBuf^[BufCounter].Attributes := WordRec(VideoBuf^[BufCounter]).Two;
  182. Inc(BufCounter);
  183. end; { for }
  184. end; { for }
  185. WriteConsoleOutput(TextRec(Output).Handle, LineBuf, BufSize, BufCoord, WriteRegion);
  186. Dispose(LineBuf);
  187. move(VideoBuf^,OldVideoBuf^,VideoBufSize);
  188. end;
  189. end;
  190. }
  191. var
  192. x1,y1,x2,y2 : longint;
  193. begin
  194. if LockUpdateScreen<>0 then
  195. exit;
  196. if force then
  197. smallforce:=true
  198. else
  199. begin
  200. asm
  201. movl VideoBuf,%esi
  202. movl OldVideoBuf,%edi
  203. movl VideoBufSize,%ecx
  204. shrl $2,%ecx
  205. repe
  206. cmpsl
  207. orl %ecx,%ecx
  208. jz .Lno_update
  209. movb $1,smallforce
  210. .Lno_update:
  211. end;
  212. end;
  213. if SmallForce then
  214. begin
  215. BufSize.X := ScreenWidth;
  216. BufSize.Y := ScreenHeight;
  217. BufCoord.X := 0;
  218. BufCoord.Y := 0;
  219. with WriteRegion do
  220. begin
  221. Top :=0;
  222. Left :=0;
  223. Bottom := ScreenHeight-1;
  224. Right := ScreenWidth-1;
  225. end;
  226. New(LineBuf);
  227. BufCounter := 0;
  228. x1:=ScreenWidth+1;
  229. x2:=-1;
  230. y1:=ScreenHeight+1;
  231. y2:=-1;
  232. for LineCounter := 1 to ScreenHeight do
  233. begin
  234. for ColCounter := 1 to ScreenWidth do
  235. begin
  236. if (WordRec(VideoBuf^[BufCounter]).One<>WordRec(OldVideoBuf^[BufCounter]).One) or
  237. (WordRec(VideoBuf^[BufCounter]).Two<>WordRec(OldVideoBuf^[BufCounter]).Two) then
  238. begin
  239. if ColCounter<x1 then
  240. x1:=ColCounter;
  241. if ColCounter>x2 then
  242. x2:=ColCounter;
  243. if LineCounter<y1 then
  244. y1:=LineCounter;
  245. if LineCounter>y2 then
  246. y2:=LineCounter;
  247. end;
  248. LineBuf^[BufCounter].UniCodeChar := WordRec(VideoBuf^[BufCounter]).One;
  249. { If (WordRec(VideoBuf^[BufCounter]).Two and $80)<>0 then
  250. LineBuf^[BufCounter].Attributes := $100+WordRec(VideoBuf^[BufCounter]).Two
  251. else }
  252. LineBuf^[BufCounter].Attributes := WordRec(VideoBuf^[BufCounter]).Two;
  253. Inc(BufCounter);
  254. end; { for }
  255. end; { for }
  256. BufSize.X := ScreenWidth;
  257. BufSize.Y := ScreenHeight;
  258. with WriteRegion do
  259. begin
  260. if force then
  261. begin
  262. Top := 0;
  263. Left :=0;
  264. Bottom := ScreenHeight-1;
  265. Right := ScreenWidth-1;
  266. BufCoord.X := 0;
  267. BufCoord.Y := 0;
  268. end
  269. else
  270. begin
  271. Top := y1-1;
  272. Left :=x1-1;
  273. Bottom := y2-1;
  274. Right := x2-1;
  275. BufCoord.X := x1-1;
  276. BufCoord.Y := y1-1;
  277. end;
  278. end;
  279. {
  280. writeln('X1: ',x1);
  281. writeln('Y1: ',y1);
  282. writeln('X2: ',x2);
  283. writeln('Y2: ',y2);
  284. }
  285. WriteConsoleOutput(TextRec(Output).Handle, LineBuf, BufSize, BufCoord, WriteRegion);
  286. Dispose(LineBuf);
  287. move(VideoBuf^,OldVideoBuf^,VideoBufSize);
  288. end;
  289. end;
  290. procedure RegisterVideoModes;
  291. begin
  292. { don't know what to do for win32 (FK) }
  293. RegisterVideoMode(80, 25, True, @DefaultVideoModeSelector, $00000003);
  294. end;
  295. initialization
  296. RegisterVideoModes;
  297. finalization
  298. UnRegisterVideoModes;
  299. end.
  300. {
  301. $Log$
  302. Revision 1.1 2001-01-13 11:03:59 peter
  303. * API 2 RTL commit
  304. }