modes.inc 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by the Free Pascal development team
  4. This include implements video mode management.
  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. {-----------------------------------------------------------------------}
  12. { Internal routines }
  13. {-----------------------------------------------------------------------}
  14. procedure res2Mode(x, y, maxColor: longint; var driver,mode: smallInt);
  15. var
  16. l: longint;
  17. begin
  18. case maxColor of
  19. 2: driver := D1bit;
  20. 4: driver := D2bit;
  21. 16: driver := D4bit;
  22. 64: driver := D6bit;
  23. 256: driver := D8bit;
  24. 4096: driver := D12bit;
  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 := maxsmallint;
  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 := maxsmallint;
  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. procedure addmode(const mode: TModeInfo);
  61. {********************************************************}
  62. { Procedure AddMode() }
  63. {--------------------------------------------------------}
  64. { This routine adds <mode> to the list of recognized }
  65. { modes. Duplicates are allowed. }
  66. {********************************************************}
  67. var
  68. i,driverNr, modeNr: smallint;
  69. prev: PModeInfo;
  70. list: PModeInfo;
  71. newlst : PModeInfo;
  72. begin
  73. res2Mode(mode.maxx+1,mode.maxy+1,mode.maxColor,driverNr,ModeNr);
  74. { bitdepth supported? }
  75. if (driverNr <> maxsmallint) then
  76. begin
  77. { Yes, add the mode }
  78. if not assigned(newModeList.modeinfo[driverNr]) then
  79. begin
  80. {$ifdef logging}
  81. logln('Adding resolution '+strf(modenr)+' for drivernr '+strf(drivernr)+
  82. ' ('+strf(mode.maxx)+'x'+strf(mode.maxy)+')');
  83. {$endif logging}
  84. new(newModeList.modeinfo[driverNr]);
  85. newModeList.modeinfo[driverNr]^ := mode;
  86. newModeList.modeinfo[driverNr]^.next:=nil;
  87. end
  88. else
  89. begin
  90. prev := nil;
  91. list := newModeList.modeinfo[driverNr];
  92. { sort first by x resolution, then by yresolution }
  93. while assigned(list) and
  94. ((list^.maxx < mode.maxx) or
  95. ((list^.maxx = mode.maxx) and
  96. (list^.maxy < mode.maxy))) do
  97. begin
  98. prev := list;
  99. list := list^.next;
  100. end;
  101. { mode already exists? -> replace (assume later added modes are }
  102. { better) }
  103. if assigned(list) and
  104. (list^.maxx = mode.maxx) and
  105. (list^.maxy = mode.maxy) then
  106. begin
  107. {$ifdef logging}
  108. logln('replacing resolution '+strf(modenr)+' for drivernr '+strf(drivernr)+
  109. ' ('+strf(mode.maxx)+'x'+strf(mode.maxy)+')');
  110. {$endif logging}
  111. { save/restore next, drivernr and drivermode in list }
  112. prev := list^.next;
  113. list^ := mode;
  114. list^.next := prev;
  115. end
  116. else
  117. begin
  118. new(newLst);
  119. { Increase the number of modes for this driver }
  120. newLst^ := mode;
  121. {$ifdef logging}
  122. logln('Adding resolution '+strf(modenr)+' for drivernr '+strf(drivernr)+
  123. ' ('+strf(mode.maxx)+'x'+strf(mode.maxy)+')');
  124. {$endif logging}
  125. newLst^.next := list;
  126. if assigned(prev) then
  127. prev^.next := newLst
  128. else
  129. newModeList.modeinfo[driverNr] := newLst;
  130. end;
  131. end;
  132. { renumber internmodenumber }
  133. list := newModeList.modeinfo[driverNr];
  134. i:=0;
  135. while assigned(list) do
  136. begin
  137. inc(i);
  138. list^.internmodenumber:=i;
  139. list:=list^.next;
  140. end;
  141. newModeList.loHiModeNr[driverNr].lo:=1;
  142. newModeList.loHiModeNr[driverNr].hi:=i;
  143. end;
  144. { TP-like mode stuff }
  145. if not assigned(ModeList) then
  146. begin
  147. new(ModeList);
  148. move(mode, ModeList^, sizeof(Mode));
  149. end
  150. else
  151. begin
  152. list := ModeList;
  153. { go to the end of the list }
  154. while assigned(list^.next) do
  155. list:=list^.next;
  156. new(NewLst);
  157. list^.next := NewLst;
  158. move(mode, NewLst^, sizeof(Mode));
  159. end;
  160. end;
  161. procedure initmode(var mode: TModeInfo);
  162. {********************************************************}
  163. { Procedure InitMode() }
  164. {--------------------------------------------------------}
  165. { This routine initialized the mode to default values. }
  166. {********************************************************}
  167. begin
  168. FillChar(mode,sizeof(Mode),#0);
  169. end;
  170. function searchmode(ReqDriver : smallint; var reqmode: smallint): PModeInfo;
  171. {********************************************************}
  172. { Procedure SearchMode() }
  173. {--------------------------------------------------------}
  174. { This routine searches the list of recognized modes, }
  175. { and tries to find the <reqmode> in the <reqdriver> }
  176. { return nil if not found, otherwise returns the found }
  177. { structure. }
  178. { note: if reqmode = -32768, the first mode available }
  179. { for reqdriver is returned (JM) }
  180. { if reqmode = -32767, the last mode available }
  181. { for reqdriver is returned (JM) }
  182. {********************************************************}
  183. var
  184. list, lastModeInfo: PModeInfo;
  185. x,y: longint;
  186. begin
  187. {$ifdef logging}
  188. LogLn('Searching for driver '+strf(reqdriver)+' and mode '+strf(reqmode));
  189. {$endif logging}
  190. if (reqDriver >= lowNewDriver) and
  191. (reqDriver <= highNewDriver) then
  192. begin
  193. case reqMode of
  194. -32768:
  195. begin
  196. reqMode := newModeList.loHiModeNr[reqDriver].lo;
  197. searchMode := newModeList.modeinfo[reqDriver];
  198. end;
  199. -32767:
  200. begin
  201. reqMode := newModeList.loHiModeNr[reqDriver].hi;
  202. searchMode := nil;
  203. { Are there any modes available for this driver? }
  204. if reqMode <> -1 then
  205. begin
  206. list := newModeList.modeinfo[reqDriver];
  207. while assigned(list^.next) do
  208. list := list^.next;
  209. searchMode := list;
  210. end;
  211. end;
  212. else
  213. begin
  214. list := newModeList.modeinfo[reqDriver];
  215. searchMode := nil;
  216. if not assigned(list) then
  217. exit;
  218. if mode2res(reqMode,x,y) then
  219. begin
  220. x := pred(x);
  221. y := pred(y);
  222. while assigned(list) and
  223. ((list^.maxx < x) or
  224. ((list^.maxx = x) and
  225. (list^.maxy < y))) do
  226. list := list^.next;
  227. if not assigned(list) or
  228. (list^.maxx <> x) or
  229. (list^.maxy <> y) then
  230. list := nil;
  231. searchmode := list;
  232. end
  233. else
  234. begin
  235. while assigned(list) and
  236. (list^.internModeNumber <> reqMode) do
  237. list := list^.next;
  238. searchMode := list;
  239. end;
  240. end;
  241. end;
  242. exit;
  243. end;
  244. searchmode := nil;
  245. list := ModeList;
  246. If assigned(list) then
  247. lastModeInfo := list;
  248. { go to the end of the list }
  249. while assigned(list) do
  250. begin
  251. {$ifdef logging}
  252. Log('Found driver '+strf(list^.DriverNumber)+
  253. ' and mode $'+hexstr(list^.ModeNumber,4)+'...');
  254. {$endif logging}
  255. if ((list^.DriverNumber = ReqDriver) and
  256. ((list^.ModeNumber = ReqMode) or
  257. { search for lowest mode }
  258. (reqMode = -32768))) or
  259. { search for highest mode }
  260. ((reqMode = -32767) and
  261. (lastModeInfo^.driverNumber = reqDriver) and
  262. ((list^.driverNumber <> lastModeInfo^.driverNumber) or
  263. not(assigned(list^.next)))) then
  264. begin
  265. {$ifdef logging}
  266. LogLn('Accepted!');
  267. {$endif logging}
  268. searchmode := list;
  269. If reqMode = -32768 then
  270. reqMode := list^.ModeNumber
  271. else if reqMode = -32767 then
  272. begin
  273. reqMode := lastModeInfo^.ModeNumber;
  274. searchMode := lastModeInfo;
  275. end;
  276. exit;
  277. end;
  278. {$ifdef logging}
  279. LogLn('Rejected.');
  280. {$endif logging}
  281. lastModeInfo := list;
  282. list:=list^.next;
  283. end;
  284. end;
  285. {-----------------------------------------------------------------------}
  286. { External routines }
  287. {-----------------------------------------------------------------------}
  288. function GetModeName(ModeNumber: smallint): string;
  289. {********************************************************}
  290. { Function GetModeName() }
  291. {--------------------------------------------------------}
  292. { Checks the known video list, and returns ModeName }
  293. { string. On error returns an empty string. }
  294. {********************************************************}
  295. var
  296. mode: PModeInfo;
  297. begin
  298. mode:=nil;
  299. GetModeName:='';
  300. { only search in the current driver modes ... }
  301. mode:=SearchMode(IntCurrentNewDriver,ModeNumber);
  302. if assigned(mode) then
  303. GetModeName:=Mode^.ModeName
  304. else
  305. _GraphResult := grInvalidMode;
  306. end;
  307. function GetGraphMode: smallint;
  308. begin
  309. GetGraphMode := IntCurrentMode;
  310. end;
  311. function GetMaxMode: smallint;
  312. { I know , i know, this routine is very slow, and it would }
  313. { be much easier to sort the linked list of possible modes }
  314. { instead of doing this, but I'm lazy!! And anyways, the }
  315. { speed of the routine here is not that important.... }
  316. var
  317. i: smallint;
  318. mode: PModeInfo;
  319. begin
  320. mode:=nil;
  321. i:=0;
  322. repeat
  323. inc(i);
  324. { mode 0 always exists... }
  325. { start search at 1.. }
  326. mode:=SearchMode(IntCurrentNewDriver,i);
  327. until not assigned(mode);
  328. GetMaxMode:=i;
  329. end;
  330. procedure GetModeRange(GraphDriver: smallint; var LoMode,
  331. HiMode: smallint);
  332. var
  333. mode : PModeInfo;
  334. begin
  335. {$ifdef logging}
  336. LogLn('GetModeRange : Enter ('+strf(GraphDriver)+')');
  337. {$endif}
  338. HiMode:=-1;
  339. mode := nil;
  340. { First search if the graphics driver is supported .. }
  341. { since mode zero is always supported.. if that driver }
  342. { is supported it should return something... }
  343. { not true, e.g. VESA doesn't have a mode 0. Changed so}
  344. { -32768 means "return lowest mode in second parameter }
  345. { also, under VESA some modes may not be supported }
  346. { (e.g. $108 here) while some with a higher number can }
  347. { be supported ($112 and onward), so I also added that }
  348. { -32767 means "return highest mode in second parameter}
  349. { This whole system should be overhauled though to work}
  350. { without such hacks (JM) }
  351. loMode := -32768;
  352. mode := SearchMode(GraphDriver, loMode);
  353. { driver not supported...}
  354. if not assigned(mode) then
  355. begin
  356. loMode := -1;
  357. exit;
  358. end;
  359. {$ifdef logging}
  360. LogLn('GetModeRange : Mode '+strf(lomode)+' found');
  361. {$endif}
  362. { now it exists... find highest available mode... }
  363. hiMode := -32767;
  364. mode:=SearchMode(GraphDriver,hiMode);
  365. end;
  366. procedure SetGraphMode(mode: smallint);
  367. var
  368. modeinfo: PModeInfo;
  369. usedDriver: Integer;
  370. begin
  371. { check if the mode exists... }
  372. { Depending on the modenumber, we search using the old or new }
  373. { graphdriver number (because once we entered graphmode, }
  374. { getgraphmode() returns the old mode number and }
  375. { both setgraphmode(getgraphmode) and setgraphmode(mAAAxBBB) }
  376. { have to work (JM) }
  377. case mode of
  378. detectMode:
  379. begin
  380. mode := -32767;
  381. usedDriver := IntcurrentNewDriver;
  382. modeInfo := searchmode(IntcurrentNewDriver,mode);
  383. end;
  384. lowNewMode..highNewMode:
  385. begin
  386. usedDriver := IntcurrentNewDriver;
  387. modeInfo := searchmode(IntcurrentNewDriver,mode);
  388. end;
  389. else
  390. begin
  391. usedDriver := IntcurrentDriver;
  392. modeinfo := searchmode(IntcurrentDriver,mode);
  393. end;
  394. end;
  395. if not assigned(modeinfo) then
  396. begin
  397. {$ifdef logging}
  398. LogLn('Mode setting failed in setgraphmode pos 1');
  399. {$endif logging}
  400. _GraphResult := grInvalidMode;
  401. exit;
  402. end;
  403. { reset all hooks...}
  404. DefaultHooks;
  405. { required hooks - returns error if no hooks to these }
  406. { routines. }
  407. if assigned(modeinfo^.DirectPutPixel) then
  408. DirectPutPixel := modeinfo^.DirectPutPixel
  409. else
  410. begin
  411. {$ifdef logging}
  412. LogLn('Mode setting failed in setgraphmode pos 2');
  413. {$endif logging}
  414. DefaultHooks;
  415. _Graphresult := grInvalidMode;
  416. exit;
  417. end;
  418. if assigned(modeinfo^.PutPixel) then
  419. PutPixel := modeinfo^.PutPixel
  420. else
  421. begin
  422. {$ifdef logging}
  423. LogLn('Mode setting failed in setgraphmode pos 3');
  424. {$endif logging}
  425. DefaultHooks;
  426. _Graphresult := grInvalidMode;
  427. exit;
  428. end;
  429. if assigned(modeinfo^.GetPixel) then
  430. GetPixel := modeinfo^.GetPixel
  431. else
  432. begin
  433. {$ifdef logging}
  434. LogLn('Mode setting failed in setgraphmode pos 4');
  435. {$endif logging}
  436. DefaultHooks;
  437. _Graphresult := grInvalidMode;
  438. exit;
  439. end;
  440. if assigned(modeinfo^.SetRGBPalette) then
  441. SetRGBPalette := modeinfo^.SetRGBPalette
  442. else
  443. begin
  444. {$ifdef logging}
  445. LogLn('Mode setting failed in setgraphmode pos 5');
  446. {$endif logging}
  447. DefaultHooks;
  448. _Graphresult := grInvalidMode;
  449. exit;
  450. end;
  451. if assigned(modeinfo^.GetRGBPalette) then
  452. GetRGBPalette := modeinfo^.GetRGBPalette
  453. else
  454. begin
  455. {$ifdef logging}
  456. LogLn('Mode setting failed in setgraphmode pos 6');
  457. {$endif logging}
  458. DefaultHooks;
  459. _Graphresult := grInvalidMode;
  460. exit;
  461. end;
  462. { optional hooks. }
  463. if assigned(modeinfo^.SetAllPalette) then
  464. SetAllPalette := modeinfo^.SetAllPalette;
  465. if assigned(modeinfo^.ClearViewPort) then
  466. ClearViewPort := modeinfo^.ClearViewPort;
  467. if assigned(modeinfo^.PutImage) then
  468. PutImage := modeinfo^.PutImage;
  469. if assigned(modeinfo^.GetImage) then
  470. GetImage := modeinfo^.GetImage;
  471. if assigned(modeinfo^.ImageSize) then
  472. ImageSize := modeinfo^.ImageSize;
  473. if assigned(modeinfo^.GetScanLine) then
  474. GetScanLine := modeinfo^.GetScanLine;
  475. if assigned(modeinfo^.Line) then
  476. Line := modeinfo^.Line;
  477. if assigned(modeinfo^.InternalEllipse) then
  478. InternalEllipse := modeinfo^.InternalEllipse;
  479. if assigned(modeinfo^.PatternLine) then
  480. PatternLine := modeinfo^.PatternLine;
  481. if assigned(modeinfo^.HLine) then
  482. Hline := modeinfo^.Hline;
  483. if assigned(modeinfo^.Vline) then
  484. VLine := modeinfo^.VLine;
  485. if assigned(modeInfo^.SetVisualPage) then
  486. SetVisualPage := modeInfo^.SetVisualPage;
  487. if assigned(modeInfo^.SetActivePage) then
  488. SetActivePage := modeInfo^.SetActivePage;
  489. if assigned(modeInfo^.OutTextXY) then
  490. OutTextXY:=modeInfo^.OutTextXY;
  491. IntCurrentMode := modeinfo^.ModeNumber;
  492. IntCurrentDriver := usedDriver;
  493. {$ifdef logging}
  494. logln('Entering mode '+strf(intCurrentMode)+' of driver '+strf(intCurrentDriver));
  495. {$endif logging}
  496. XAspect := modeinfo^.XAspect;
  497. YAspect := modeinfo^.YAspect;
  498. MaxX := modeinfo^.MaxX;
  499. MaxY := modeinfo^.MaxY;
  500. {$ifdef logging}
  501. logln('maxx = '+strf(maxx)+', maxy = '+strf(maxy));
  502. {$endif logging}
  503. HardwarePages := modeInfo^.HardwarePages;
  504. MaxColor := modeinfo^.MaxColor;
  505. PaletteSize := modeinfo^.PaletteSize;
  506. { is this a direct color mode? }
  507. DirectColor := modeinfo^.DirectColor;
  508. { now actually initialize the video mode...}
  509. { check first if the routine exists }
  510. if not assigned(modeinfo^.InitMode) then
  511. begin
  512. {$ifdef logging}
  513. LogLn('Mode setting failed in setgraphmode pos 7');
  514. {$endif logging}
  515. DefaultHooks;
  516. _GraphResult := grInvalidMode;
  517. exit;
  518. end;
  519. modeinfo^.InitMode;
  520. if _GraphResult <> grOk then
  521. begin
  522. DefaultHooks;
  523. exit;
  524. end;
  525. isgraphmode := true;
  526. { It is very important that this call be made }
  527. { AFTER the other variables have been setup. }
  528. { Since it calls some routines which rely on }
  529. { those variables. }
  530. SetActivePage(0);
  531. SetVisualPage(0);
  532. SetViewPort(0,0,MaxX,MaxY,TRUE);
  533. GraphDefaults;
  534. end;
  535. procedure RestoreCrtMode;
  536. {********************************************************}
  537. { Procedure RestoreCRTMode() }
  538. {--------------------------------------------------------}
  539. { Returns to the video mode which was set before the }
  540. { InitGraph. Hardware state is set to the old values. }
  541. {--------------------------------------------------------}
  542. { NOTE: - }
  543. { - }
  544. {********************************************************}
  545. begin
  546. isgraphmode := false;
  547. RestoreVideoState;
  548. end;