modes.inc 19 KB

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