modes.inc 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by the Free Pascal development team
  5. This include implements video mode management.
  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. {-----------------------------------------------------------------------}
  13. { Internal routines }
  14. {-----------------------------------------------------------------------}
  15. {$ifdef newmodes}
  16. procedure res2Mode(x, y, maxColor: longint; var driver,mode: smallInt);
  17. var
  18. l: longint;
  19. begin
  20. case maxColor of
  21. 2: driver := D1bit;
  22. 4: driver := D2bit;
  23. 16: driver := D4bit;
  24. 256: driver := D8bit;
  25. 32768: driver := D15bit;
  26. 65536: driver := D16bit;
  27. { not yet supported
  28. 65536*256: driver := D24bit;
  29. 65536*65536: driver := D32bit;}
  30. else
  31. begin
  32. driver := maxint;
  33. exit;
  34. end;
  35. end;
  36. { Check whether this is known/predefined mode }
  37. for l := lowNewMode to highNewMode do
  38. if (resolutions[l].x = x) and
  39. (resolutions[l].y = y) then
  40. begin
  41. { Found! }
  42. mode := l;
  43. exit;
  44. end;
  45. { Not Found }
  46. mode := maxint;
  47. end;
  48. function mode2res(modeNr: smallInt; var x,y: longint): boolean;
  49. begin
  50. if (modeNr < lowNewMode) or
  51. (modeNr > highNewMode) then
  52. begin
  53. mode2res := false;
  54. exit;
  55. end;
  56. mode2res := true;
  57. x := resolutions[modeNr].x;
  58. y := resolutions[modeNr].y;
  59. end;
  60. {$endif newmodes}
  61. procedure addmode(const mode: TModeInfo);
  62. {********************************************************}
  63. { Procedure AddMode() }
  64. {--------------------------------------------------------}
  65. { This routine adds <mode> to the list of recognized }
  66. { modes. Duplicates are allowed. }
  67. {********************************************************}
  68. var
  69. {$ifdef newmodes}
  70. driverNr, modeNr: smallint;
  71. prev: PModeInfo;
  72. {$endif newmodes}
  73. list: PModeInfo;
  74. newlst : PModeInfo;
  75. begin
  76. {$ifdef newmodes}
  77. res2Mode(mode.maxx+1,mode.maxy+1,mode.maxColor,driverNr,ModeNr);
  78. { bitdepth supported? }
  79. if (driverNr <> maxint) then
  80. { Yes, add the mode }
  81. if not assigned(newModeList.modeinfo[driverNr]) then
  82. begin
  83. new(newModeList.modeinfo[driverNr]);
  84. newModeList.modeinfo[driverNr]^ := mode;
  85. with newModeList.modeinfo[driverNr]^ do
  86. begin
  87. driverNumber := driverNr;
  88. modeNumber := 1;
  89. next := nil;
  90. end;
  91. newModeList.loHiModeNr[driverNr].lo := 1;
  92. newModeList.loHiModeNr[driverNr].hi := 1;
  93. end
  94. else
  95. begin
  96. prev := nil;
  97. list := newModeList.modeinfo[driverNr];
  98. { sort first by x resolution, then by yresolution }
  99. while assigned(list) and
  100. ((list^.maxx < mode.maxx) or
  101. ((list^.maxx = mode.maxx) and
  102. (list^.maxy < mode.maxy))) do
  103. begin
  104. prev := list;
  105. list := list^.next;
  106. end;
  107. { mode already exists? -> replace (assume later added modes are }
  108. { better) }
  109. if assigned(list) and
  110. (list^.maxx = mode.maxx) and
  111. (list^.maxy = mode.maxy) then
  112. begin
  113. { save/restore next, drivernr and drivermode in list }
  114. driverNr := list^.driverNumber;
  115. modeNr := list^.modeNumber;
  116. prev := list^.next;
  117. list^ := mode;
  118. list^.driverNumber := driverNr;
  119. list^.modeNumber := modeNr;
  120. list^.next := prev;
  121. end
  122. else
  123. begin
  124. new(newLst);
  125. { Increase the number of modes for this driver }
  126. inc(newModeList.loHiModeNr[driverNr].hi);
  127. newLst^ := mode;
  128. newLst^.driverNumber := driverNr;
  129. if assigned(list) then
  130. newLst^.next := list^.next
  131. else
  132. newLst^.next := nil;
  133. if assigned(prev) then
  134. begin
  135. prev^.next := newLst;
  136. newLst^.modeNumber := succ(prev^.modeNumber)
  137. end
  138. else
  139. begin
  140. newModeList.modeinfo[driverNr] := newLst;
  141. newLst^.modeNumber := 1;
  142. end;
  143. { Increase the modenumbers of all modes coming after this one }
  144. { with 1 }
  145. newLst := newLst^.next;
  146. while assigned(newLst) do
  147. begin
  148. inc(newLst^.modeNumber);
  149. newLst := newLst^.next;
  150. end;
  151. end;
  152. end;
  153. {$endif newmodes}
  154. { TP-like mode stuff }
  155. if not assigned(ModeList) then
  156. begin
  157. new(ModeList);
  158. move(mode, ModeList^, sizeof(Mode));
  159. end
  160. else
  161. begin
  162. list := ModeList;
  163. { go to the end of the list }
  164. while assigned(list^.next) do
  165. list:=list^.next;
  166. new(NewLst);
  167. list^.next := NewLst;
  168. move(mode, NewLst^, sizeof(Mode));
  169. end;
  170. end;
  171. procedure initmode(var mode: TModeInfo);
  172. {********************************************************}
  173. { Procedure InitMode() }
  174. {--------------------------------------------------------}
  175. { This routine initialized the mode to default values. }
  176. {********************************************************}
  177. begin
  178. FillChar(mode,sizeof(Mode),#0);
  179. end;
  180. function searchmode(ReqDriver : smallint; var reqmode: smallint): PModeInfo;
  181. {********************************************************}
  182. { Procedure SearchMode() }
  183. {--------------------------------------------------------}
  184. { This routine searches the list of recognized modes, }
  185. { and tries to find the <reqmode> in the <reqdriver> }
  186. { return nil if not found, otherwise returns the found }
  187. { structure. }
  188. { note: if reqmode = -32768, the first mode available }
  189. { for reqdriver is returned (JM) }
  190. { if reqmode = -32767, the last mode available }
  191. { for reqdriver is returned (JM) }
  192. {********************************************************}
  193. var
  194. list, lastModeInfo: PModeInfo;
  195. x,y: longint;
  196. begin
  197. {$ifdef logging}
  198. LogLn('Searching for driver '+strf(reqdriver)+' and mode '+strf(reqmode));
  199. {$endif logging}
  200. {$ifdef newmodes}
  201. if (reqDriver >= lowNewDriver) and
  202. (reqDriver <= highNewDriver) then
  203. begin
  204. case reqMode of
  205. -32768:
  206. begin
  207. reqMode := newModeList.loHiModeNr[reqDriver].lo;
  208. searchMode := newModeList.modeinfo[reqDriver];
  209. end;
  210. -32767:
  211. begin
  212. reqMode := newModeList.loHiModeNr[reqDriver].hi;
  213. searchMode := nil;
  214. { Are there any modes available for this driver? }
  215. if reqMode <> -1 then
  216. begin
  217. list := newModeList.modeinfo[reqDriver];
  218. while assigned(list^.next) do
  219. list := list^.next;
  220. searchMode := list;
  221. end;
  222. end;
  223. else
  224. begin
  225. list := newModeList.modeinfo[reqDriver];
  226. searchMode := nil;
  227. if not assigned(list) then
  228. exit;
  229. if mode2res(reqMode,x,y) then
  230. begin
  231. x := pred(x);
  232. y := pred(y);
  233. while assigned(list) and
  234. ((list^.maxx < x) or
  235. ((list^.maxx = x) and
  236. (list^.maxy < y))) do
  237. list := list^.next;
  238. if not assigned(list) or
  239. (list^.maxx <> x) or
  240. (list^.maxy <> y) then
  241. list := nil;
  242. searchmode := list;
  243. end
  244. else
  245. begin
  246. while assigned(list) and
  247. (list^.modeNumber <> reqMode) do
  248. list := list^.next;
  249. searchMode := list;
  250. end;
  251. end;
  252. end;
  253. exit;
  254. end;
  255. {$endif newmodes}
  256. searchmode := nil;
  257. list := ModeList;
  258. If assigned(list) then
  259. lastModeInfo := list;
  260. { go to the end of the list }
  261. while assigned(list) do
  262. begin
  263. {$ifdef logging}
  264. Log('Found driver '+strf(list^.DriverNumber)+
  265. ' and mode $'+hexstr(list^.ModeNumber,4)+'... ');
  266. {$endif logging}
  267. if ((list^.DriverNumber = ReqDriver) and
  268. ((list^.ModeNumber = ReqMode) or
  269. { search for lowest mode }
  270. (reqMode = -32768))) or
  271. { search for highest mode }
  272. ((reqMode = -32767) and
  273. (lastModeInfo^.driverNumber = reqDriver) and
  274. ((list^.driverNumber <> lastModeInfo^.driverNumber) or
  275. not(assigned(list^.next)))) then
  276. begin
  277. {$ifdef logging}
  278. LogLn('Accepted!');
  279. {$endif logging}
  280. searchmode := list;
  281. If reqMode = -32768 then
  282. reqMode := list^.modeNumber
  283. else if reqMode = -32767 then
  284. begin
  285. reqMode := lastModeInfo^.modeNumber;
  286. searchMode := lastModeInfo;
  287. end;
  288. exit;
  289. end;
  290. {$ifdef logging}
  291. LogLn('Rejected.');
  292. {$endif logging}
  293. lastModeInfo := list;
  294. list:=list^.next;
  295. end;
  296. end;
  297. {-----------------------------------------------------------------------}
  298. { External routines }
  299. {-----------------------------------------------------------------------}
  300. function GetModeName(ModeNumber: smallint): string;
  301. {********************************************************}
  302. { Function GetModeName() }
  303. {--------------------------------------------------------}
  304. { Checks the known video list, and returns ModeName }
  305. { string. On error returns an empty string. }
  306. {********************************************************}
  307. var
  308. mode: PModeInfo;
  309. begin
  310. mode:=nil;
  311. GetModeName:='';
  312. { only search in the current driver modes ... }
  313. mode:=SearchMode(IntCurrentDriver,ModeNumber);
  314. if assigned(mode) then
  315. GetModeName:=Mode^.ModeName
  316. else
  317. _GraphResult := grInvalidMode;
  318. end;
  319. function GetGraphMode: smallint;
  320. begin
  321. GetGraphMode := IntCurrentMode;
  322. end;
  323. function GetMaxMode: word;
  324. { I know , i know, this routine is very slow, and it would }
  325. { be much easier to sort the linked list of possible modes }
  326. { instead of doing this, but I'm lazy!! And anyways, the }
  327. { speed of the routine here is not that important.... }
  328. var
  329. i: word;
  330. mode: PModeInfo;
  331. begin
  332. mode:=nil;
  333. i:=0;
  334. repeat
  335. inc(i);
  336. { mode 0 always exists... }
  337. { start search at 1.. }
  338. mode:=SearchMode(IntCurrentDriver,i);
  339. until not assigned(mode);
  340. GetMaxMode:=i;
  341. end;
  342. procedure GetModeRange(GraphDriver: smallint; var LoMode,
  343. HiMode: smallint);
  344. var
  345. mode : PModeInfo;
  346. begin
  347. {$ifdef logging}
  348. LogLn('GetModeRange : Enter ('+strf(GraphDriver)+')');
  349. {$endif}
  350. HiMode:=-1;
  351. mode := nil;
  352. { First search if the graphics driver is supported .. }
  353. { since mode zero is always supported.. if that driver }
  354. { is supported it should return something... }
  355. { not true, e.g. VESA doesn't have a mode 0. Changed so}
  356. { -32768 means "return lowest mode in second parameter }
  357. { also, under VESA some modes may not be supported }
  358. { (e.g. $108 here) while some with a higher number can }
  359. { be supported ($112 and onward), so I also added that }
  360. { -32767 means "return highest mode in second parameter}
  361. { This whole system should be overhauled though to work}
  362. { without such hacks (JM) }
  363. loMode := -32768;
  364. mode := SearchMode(GraphDriver, loMode);
  365. { driver not supported...}
  366. if not assigned(mode) then
  367. begin
  368. loMode := -1;
  369. exit;
  370. end;
  371. {$ifdef logging}
  372. LogLn('GetModeRange : Mode 0 found');
  373. {$endif}
  374. { now it exists... find highest available mode... }
  375. hiMode := -32767;
  376. mode:=SearchMode(GraphDriver,hiMode);
  377. end;
  378. procedure SetGraphMode(mode: smallint);
  379. var
  380. modeinfo: PModeInfo;
  381. begin
  382. { check if the mode exists... }
  383. modeinfo := searchmode(IntcurrentDriver,mode);
  384. if not assigned(modeinfo) then
  385. begin
  386. {$ifdef logging}
  387. LogLn('Mode setting failed in setgraphmode pos 1');
  388. {$endif logging}
  389. _GraphResult := grInvalidMode;
  390. exit;
  391. end;
  392. { reset all hooks...}
  393. DefaultHooks;
  394. { arccall not reset - tested against VGA BGI driver }
  395. { Setup all hooks if none, keep old defaults...}
  396. { required hooks - returns error if no hooks to these }
  397. { routines. }
  398. if assigned(modeinfo^.DirectPutPixel) then
  399. DirectPutPixel := modeinfo^.DirectPutPixel
  400. else
  401. begin
  402. {$ifdef logging}
  403. LogLn('Mode setting failed in setgraphmode pos 2');
  404. {$endif logging}
  405. _Graphresult := grInvalidMode;
  406. exit;
  407. end;
  408. if assigned(modeinfo^.PutPixel) then
  409. PutPixel := modeinfo^.PutPixel
  410. else
  411. begin
  412. {$ifdef logging}
  413. LogLn('Mode setting failed in setgraphmode pos 3');
  414. {$endif logging}
  415. _Graphresult := grInvalidMode;
  416. exit;
  417. end;
  418. if assigned(modeinfo^.GetPixel) then
  419. GetPixel := modeinfo^.GetPixel
  420. else
  421. begin
  422. {$ifdef logging}
  423. LogLn('Mode setting failed in setgraphmode pos 4');
  424. {$endif logging}
  425. _Graphresult := grInvalidMode;
  426. exit;
  427. end;
  428. if assigned(modeinfo^.SetRGBPalette) then
  429. SetRGBPalette := modeinfo^.SetRGBPalette
  430. else
  431. begin
  432. {$ifdef logging}
  433. LogLn('Mode setting failed in setgraphmode pos 5');
  434. {$endif logging}
  435. _Graphresult := grInvalidMode;
  436. exit;
  437. end;
  438. if assigned(modeinfo^.GetRGBPalette) then
  439. GetRGBPalette := modeinfo^.GetRGBPalette
  440. else
  441. begin
  442. {$ifdef logging}
  443. LogLn('Mode setting failed in setgraphmode pos 6');
  444. {$endif logging}
  445. _Graphresult := grInvalidMode;
  446. exit;
  447. end;
  448. { optional hooks. }
  449. if assigned(modeinfo^.ClearViewPort) then
  450. ClearViewPort := modeinfo^.ClearViewPort;
  451. if assigned(modeinfo^.PutImage) then
  452. PutImage := modeinfo^.PutImage;
  453. if assigned(modeinfo^.GetImage) then
  454. GetImage := modeinfo^.GetImage;
  455. if assigned(modeinfo^.ImageSize) then
  456. ImageSize := modeinfo^.ImageSize;
  457. if assigned(modeinfo^.GetScanLine) then
  458. GetScanLine := modeinfo^.GetScanLine;
  459. if assigned(modeinfo^.Line) then
  460. Line := modeinfo^.Line;
  461. if assigned(modeinfo^.InternalEllipse) then
  462. InternalEllipse := modeinfo^.InternalEllipse;
  463. if assigned(modeinfo^.PatternLine) then
  464. PatternLine := modeinfo^.PatternLine;
  465. if assigned(modeinfo^.HLine) then
  466. Hline := modeinfo^.Hline;
  467. if assigned(modeinfo^.Vline) then
  468. VLine := modeinfo^.VLine;
  469. if assigned(modeInfo^.SetVisualPage) then
  470. SetVisualPage := modeInfo^.SetVisualPage;
  471. if assigned(modeInfo^.SetActivePage) then
  472. SetActivePage := modeInfo^.SetActivePage;
  473. if assigned(modeInfo^.OutTextXY) then
  474. OutTextXY:=modeInfo^.OutTextXY;
  475. IntCurrentMode := modeinfo^.ModeNumber;
  476. IntCurrentDriver := modeinfo^.DriverNumber;
  477. XAspect := modeinfo^.XAspect;
  478. YAspect := modeinfo^.YAspect;
  479. MaxX := modeinfo^.MaxX;
  480. MaxY := modeinfo^.MaxY;
  481. HardwarePages := modeInfo^.HardwarePages;
  482. MaxColor := modeinfo^.MaxColor;
  483. PaletteSize := modeinfo^.PaletteSize;
  484. { is this a direct color mode? }
  485. DirectColor := modeinfo^.DirectColor;
  486. { now actually initialize the video mode...}
  487. { check first if the routine exists }
  488. if not assigned(modeinfo^.InitMode) then
  489. begin
  490. {$ifdef logging}
  491. LogLn('Mode setting failed in setgraphmode pos 7');
  492. {$endif logging}
  493. _GraphResult := grInvalidMode;
  494. exit;
  495. end;
  496. modeinfo^.InitMode;
  497. if _GraphResult <> grOk then exit;
  498. isgraphmode := true;
  499. { It is very important that this call be made }
  500. { AFTER the other variables have been setup. }
  501. { Since it calls some routines which rely on }
  502. { those variables. }
  503. SetActivePage(0);
  504. SetVisualPage(0);
  505. GraphDefaults;
  506. SetViewPort(0,0,MaxX,MaxY,TRUE);
  507. end;
  508. procedure RestoreCrtMode;
  509. {********************************************************}
  510. { Procedure RestoreCRTMode() }
  511. {--------------------------------------------------------}
  512. { Returns to the video mode which was set before the }
  513. { InitGraph. Hardware state is set to the old values. }
  514. {--------------------------------------------------------}
  515. { NOTE: - }
  516. { - }
  517. {********************************************************}
  518. begin
  519. isgraphmode := false;
  520. RestoreVideoState;
  521. end;
  522. {
  523. $Log$
  524. Revision 1.23 2000-06-17 19:09:23 jonas
  525. * new platform independent mode handling (between -dnewmodes)
  526. Revision 1.22 2000/04/02 12:13:37 florian
  527. * some more procedures can be now hooked by the OS specific implementation
  528. Revision 1.21 2000/03/24 18:16:33 florian
  529. * introduce a DrawBitmapCharHoriz procedure variable to accelerate output on
  530. win32
  531. Revision 1.20 2000/03/24 13:01:15 florian
  532. * ClearViewPort fixed
  533. Revision 1.19 2000/01/07 16:41:39 daniel
  534. * copyright 2000
  535. Revision 1.18 2000/01/07 16:32:26 daniel
  536. * copyright 2000 added
  537. Revision 1.17 2000/01/02 19:02:39 jonas
  538. * removed/commented out (inited but) unused vars and unused types
  539. Revision 1.16 1999/12/21 17:42:18 jonas
  540. * changed vesa.inc do it doesn't try to use linear modes anymore (doesn't work
  541. yet!!)
  542. * fixed mode detection so the low modenumber of a driver doesn't have to be zero
  543. anymore (so VESA autodetection now works)
  544. Revision 1.15 1999/12/20 11:22:36 peter
  545. * integer -> smallint to overcome -S2 switch needed for ggi version
  546. Revision 1.14 1999/12/04 21:20:04 michael
  547. + Additional logging
  548. Revision 1.13 1999/11/28 16:13:55 jonas
  549. * corrected misplacement of call to initvars in initgraph
  550. + some extra debugging commands (for -dlogging) in the mode functions
  551. Revision 1.12 1999/09/28 13:56:31 jonas
  552. * reordered some local variables (first 4 byte vars, then 2 byte vars
  553. etc)
  554. * font data is now disposed in exitproc, exitproc is now called
  555. GraphExitProc (was CleanModes) and resides in graph.pp instead of in
  556. modes.inc
  557. Revision 1.11 1999/09/26 13:31:07 jonas
  558. * changed name of modeinfo variable to vesamodeinfo and fixed
  559. associated errors (fillchar(modeinfo,sizeof(tmodeinfo),#0) instead
  560. of sizeof(TVesamodeinfo) etc)
  561. * changed several sizeof(type) to sizeof(varname) to avoid similar
  562. errors in the future
  563. Revision 1.10 1999/09/24 22:52:39 jonas
  564. * optimized patternline a bit (always use hline when possible)
  565. * isgraphmode stuff cleanup
  566. * vesainfo.modelist now gets disposed in cleanmode instead of in
  567. closegraph (required moving of some declarations from vesa.inc to
  568. new vesah.inc)
  569. * queryadapter gets no longer called from initgraph (is called from
  570. initialization of graph unit)
  571. * bugfix for notput in 32k and 64k vesa modes
  572. * a div replaced by / in fillpoly
  573. Revision 1.9 1999/09/22 13:13:36 jonas
  574. * renamed text.inc -> gtext.inc to avoid conflict with system unit
  575. * fixed textwidth
  576. * isgraphmode now gets properly updated, so mode restoring works
  577. again
  578. Revision 1.8 1999/09/18 22:21:11 jonas
  579. + hlinevesa256 and vlinevesa256
  580. + support for not/xor/or/andput in vesamodes with 32k/64k colors
  581. * lots of changes to avoid warnings under FPC
  582. Revision 1.7 1999/07/12 13:27:14 jonas
  583. + added Log and Id tags
  584. * added first FPC support, only VGA works to some extend for now
  585. * use -dasmgraph to use assembler routines, otherwise Pascal
  586. equivalents are used
  587. * use -dsupportVESA to support VESA (crashes under FPC for now)
  588. * only dispose vesainfo at closegrph if a vesa card was detected
  589. * changed int32 to longint (int32 is not declared under FPC)
  590. * changed the declaration of almost every procedure in graph.inc to
  591. "far;" becquse otherwise you can't assign them to procvars under TP
  592. real mode (but unexplainable "data segnment too large" errors prevent
  593. it from working under real mode anyway)
  594. }