PageRenderTime 52ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/DOSBox/src/hardware/vga_draw.cpp

https://bitbucket.org/alunbestor/boxer/
C++ | 1511 lines | 1194 code | 92 blank | 225 comment | 294 complexity | 8fe36f56a103e0a1ea57e3dcaab5ece3 MD5 | raw file
Possible License(s): GPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * Copyright (C) 2002-2010 The DOSBox Team
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  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. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17. */
  18. /* $Id: vga_draw.cpp,v 1.112 2009-11-03 21:06:59 h-a-l-9000 Exp $ */
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include <math.h>
  22. #include "dosbox.h"
  23. #include "video.h"
  24. #include "render.h"
  25. #include "../gui/render_scalers.h"
  26. #include "vga.h"
  27. #include "pic.h"
  28. //--Added 2011-04-18 by Alun Bestor to fix endianness issues in Tandy/CGA line-printing
  29. #import <CoreFoundation/CFByteOrder.h>
  30. //--endif
  31. //#undef C_DEBUG
  32. //#define C_DEBUG 1
  33. //#define LOG(X,Y) LOG_MSG
  34. #define VGA_PARTS 4
  35. typedef Bit8u * (* VGA_Line_Handler)(Bitu vidstart, Bitu line);
  36. static VGA_Line_Handler VGA_DrawLine;
  37. static Bit8u TempLine[SCALER_MAXWIDTH * 4];
  38. static Bit8u * VGA_Draw_1BPP_Line(Bitu vidstart, Bitu line) {
  39. const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
  40. Bit32u *draw = (Bit32u *)TempLine;
  41. for (Bitu x=vga.draw.blocks;x>0;x--, vidstart++) {
  42. Bitu val = base[(vidstart & (8 * 1024 -1))];
  43. *draw++=CGA_2_Table[val >> 4];
  44. *draw++=CGA_2_Table[val & 0xf];
  45. }
  46. return TempLine;
  47. }
  48. static Bit8u * VGA_Draw_2BPP_Line(Bitu vidstart, Bitu line) {
  49. const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
  50. Bit32u * draw=(Bit32u *)TempLine;
  51. for (Bitu x=0;x<vga.draw.blocks;x++) {
  52. Bitu val = base[vidstart & vga.tandy.addr_mask];
  53. vidstart++;
  54. *draw++=CGA_4_Table[val];
  55. }
  56. return TempLine;
  57. }
  58. static Bit8u * VGA_Draw_2BPPHiRes_Line(Bitu vidstart, Bitu line) {
  59. const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
  60. Bit32u * draw=(Bit32u *)TempLine;
  61. for (Bitu x=0;x<vga.draw.blocks;x++) {
  62. Bitu val1 = base[vidstart & vga.tandy.addr_mask];
  63. ++vidstart;
  64. Bitu val2 = base[vidstart & vga.tandy.addr_mask];
  65. ++vidstart;
  66. *draw++=CGA_4_HiRes_Table[(val1>>4)|(val2&0xf0)];
  67. *draw++=CGA_4_HiRes_Table[(val1&0x0f)|((val2&0x0f)<<4)];
  68. }
  69. return TempLine;
  70. }
  71. static Bitu temp[643]={0};
  72. static Bit8u * VGA_Draw_CGA16_Line(Bitu vidstart, Bitu line) {
  73. const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
  74. const Bit8u *reader = base + vidstart;
  75. Bit32u * draw=(Bit32u *)TempLine;
  76. //Generate a temporary bitline to calculate the avarage
  77. //over bit-2 bit-1 bit bit+1.
  78. //Combine this number with the current colour to get
  79. //an unigue index in the pallete. Or it with bit 7 as they are stored
  80. //in the upperpart to keep them from interfering the regular cga stuff
  81. for(Bitu x = 0; x < 640; x++)
  82. temp[x+2] = (( reader[(x>>3)] >> (7-(x&7)) )&1) << 4;
  83. //shift 4 as that is for the index.
  84. Bitu i = 0,temp1,temp2,temp3,temp4;
  85. for (Bitu x=0;x<vga.draw.blocks;x++) {
  86. Bitu val1 = *reader++;
  87. Bitu val2 = val1&0xf;
  88. val1 >>= 4;
  89. temp1 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++;
  90. temp2 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++;
  91. temp3 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++;
  92. temp4 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++;
  93. //--Modified 2011-04-19 by Alun Bestor to fix swapped pixel columns on PowerPC Macs
  94. *draw++ = CFSwapInt32HostToLittle(0x80808080|(temp1|val1) |
  95. ((temp2|val1) << 8) |
  96. ((temp3|val1) <<16) |
  97. ((temp4|val1) <<24));
  98. temp1 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++;
  99. temp2 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++;
  100. temp3 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++;
  101. temp4 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++;
  102. *draw++ = CFSwapInt32HostToLittle(0x80808080|(temp1|val2) |
  103. ((temp2|val2) << 8) |
  104. ((temp3|val2) <<16) |
  105. ((temp4|val2) <<24));
  106. //--End of modifications
  107. }
  108. return TempLine;
  109. }
  110. static Bit8u * VGA_Draw_4BPP_Line(Bitu vidstart, Bitu line) {
  111. const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
  112. Bit32u * draw=(Bit32u *)TempLine;
  113. for (Bitu x=0;x<vga.draw.blocks;x++) {
  114. Bitu val1 = base[vidstart & vga.tandy.addr_mask];
  115. ++vidstart;
  116. Bitu val2 = base[vidstart & vga.tandy.addr_mask];
  117. ++vidstart;
  118. //--Modified 2011-04-19 by Alun Bestor to fix swapped pixel columns on PowerPC Macs
  119. *draw++=CFSwapInt32HostToLittle((val1 & 0x0f) << 8 |
  120. (val1 & 0xf0) >> 4 |
  121. (val2 & 0x0f) << 24 |
  122. (val2 & 0xf0) << 12);
  123. //--End of modifications
  124. }
  125. return TempLine;
  126. }
  127. static Bit8u * VGA_Draw_4BPP_Line_Double(Bitu vidstart, Bitu line) {
  128. const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
  129. Bit32u * draw=(Bit32u *)TempLine;
  130. for (Bitu x=0;x<vga.draw.blocks;x++) {
  131. Bitu val = base[vidstart & vga.tandy.addr_mask];
  132. ++vidstart;
  133. //--Modified 2011-04-19 by Alun Bestor to fix swapped pixel columns on PowerPC Macs
  134. *draw++=CFSwapInt32HostToLittle((val & 0xf0) >> 4 |
  135. (val & 0xf0) << 4 |
  136. (val & 0x0f) << 16 |
  137. (val & 0x0f) << 24);
  138. //--End of modifications
  139. }
  140. return TempLine;
  141. }
  142. #ifdef VGA_KEEP_CHANGES
  143. static Bit8u * VGA_Draw_Changes_Line(Bitu vidstart, Bitu line) {
  144. Bitu checkMask = vga.changes.checkMask;
  145. Bit8u *map = vga.changes.map;
  146. Bitu start = (vidstart >> VGA_CHANGE_SHIFT);
  147. Bitu end = ((vidstart + vga.draw.line_length ) >> VGA_CHANGE_SHIFT);
  148. for (; start <= end;start++) {
  149. if ( map[start] & checkMask ) {
  150. Bitu offset = vidstart & vga.draw.linear_mask;
  151. if(vga.draw.linear_mask-offset < vga.draw.line_length)
  152. memcpy(vga.draw.linear_base+vga.draw.linear_mask+1, vga.draw.linear_base, vga.draw.line_length);
  153. Bit8u *ret = &vga.draw.linear_base[ offset ];
  154. #if !defined(C_UNALIGNED_MEMORY)
  155. if (GCC_UNLIKELY( ((Bitu)ret) & (sizeof(Bitu)-1)) ) {
  156. memcpy( TempLine, ret, vga.draw.line_length );
  157. return TempLine;
  158. }
  159. #endif
  160. return ret;
  161. }
  162. }
  163. // memset( TempLine, 0x30, vga.changes.lineWidth );
  164. // return TempLine;
  165. return 0;
  166. }
  167. #endif
  168. static Bit8u * VGA_Draw_Linear_Line(Bitu vidstart, Bitu /*line*/) {
  169. // There is guaranteed extra memory past the wrap boundary. So, instead of using temporary
  170. // storage just copy appropriate chunk from the beginning to the wrap boundary when needed.
  171. Bitu offset = vidstart & vga.draw.linear_mask;
  172. if (vga.draw.linear_mask-offset < vga.draw.line_length)
  173. memcpy(vga.draw.linear_base+vga.draw.linear_mask+1, vga.draw.linear_base, vga.draw.line_length);
  174. Bit8u *ret = &vga.draw.linear_base[ offset ];
  175. #if !defined(C_UNALIGNED_MEMORY)
  176. if (GCC_UNLIKELY( ((Bitu)ret) & (sizeof(Bitu)-1)) ) {
  177. memcpy( TempLine, ret, vga.draw.line_length );
  178. return TempLine;
  179. }
  180. #endif
  181. return ret;
  182. }
  183. static Bit8u * VGA_Draw_Xlat16_Linear_Line(Bitu vidstart, Bitu /*line*/) {
  184. Bit8u *ret = &vga.draw.linear_base[ vidstart & vga.draw.linear_mask ];
  185. Bit16u* temps = (Bit16u*) TempLine;
  186. for(Bitu i = 0; i < vga.draw.line_length; i++) {
  187. temps[i]=vga.dac.xlat16[ret[i]];
  188. }
  189. return TempLine;
  190. /*
  191. #if !defined(C_UNALIGNED_MEMORY)
  192. if (GCC_UNLIKELY( ((Bitu)ret) & (sizeof(Bitu)-1)) ) {
  193. memcpy( TempLine, ret, vga.draw.line_length );
  194. return TempLine;
  195. }
  196. #endif
  197. return ret;*/
  198. }
  199. //Test version, might as well keep it
  200. /* static Bit8u * VGA_Draw_Chain_Line(Bitu vidstart, Bitu line) {
  201. Bitu i = 0;
  202. for ( i = 0; i < vga.draw.width;i++ ) {
  203. Bitu addr = vidstart + i;
  204. TempLine[i] = vga.mem.linear[((addr&~3)<<2)+(addr&3)];
  205. }
  206. return TempLine;
  207. } */
  208. static Bit8u * VGA_Draw_VGA_Line_HWMouse( Bitu vidstart, Bitu /*line*/) {
  209. if (!svga.hardware_cursor_active || !svga.hardware_cursor_active())
  210. // HW Mouse not enabled, use the tried and true call
  211. return &vga.mem.linear[vidstart];
  212. Bitu lineat = (vidstart-(vga.config.real_start<<2)) / vga.draw.width;
  213. if ((vga.s3.hgc.posx >= vga.draw.width) ||
  214. (lineat < vga.s3.hgc.originy) ||
  215. (lineat > (vga.s3.hgc.originy + (63U-vga.s3.hgc.posy))) ) {
  216. // the mouse cursor *pattern* is not on this line
  217. return &vga.mem.linear[ vidstart ];
  218. } else {
  219. // Draw mouse cursor: cursor is a 64x64 pattern which is shifted (inside the
  220. // 64x64 mouse cursor space) to the right by posx pixels and up by posy pixels.
  221. // This is used when the mouse cursor partially leaves the screen.
  222. // It is arranged as bitmap of 16bits of bitA followed by 16bits of bitB, each
  223. // AB bits corresponding to a cursor pixel. The whole map is 8kB in size.
  224. memcpy(TempLine, &vga.mem.linear[ vidstart ], vga.draw.width);
  225. // the index of the bit inside the cursor bitmap we start at:
  226. Bitu sourceStartBit = ((lineat - vga.s3.hgc.originy) + vga.s3.hgc.posy)*64 + vga.s3.hgc.posx;
  227. // convert to video memory addr and bit index
  228. // start adjusted to the pattern structure (thus shift address by 2 instead of 3)
  229. // Need to get rid of the third bit, so "/8 *2" becomes ">> 2 & ~1"
  230. Bitu cursorMemStart = ((sourceStartBit >> 2)& ~1) + (((Bit32u)vga.s3.hgc.startaddr) << 10);
  231. Bitu cursorStartBit = sourceStartBit & 0x7;
  232. // stay at the right position in the pattern
  233. if (cursorMemStart & 0x2) cursorMemStart--;
  234. Bitu cursorMemEnd = cursorMemStart + ((64-vga.s3.hgc.posx) >> 2);
  235. Bit8u* xat = &TempLine[vga.s3.hgc.originx]; // mouse data start pos. in scanline
  236. for (Bitu m = cursorMemStart; m < cursorMemEnd; (m&1)?(m+=3):m++) {
  237. // for each byte of cursor data
  238. Bit8u bitsA = vga.mem.linear[m];
  239. Bit8u bitsB = vga.mem.linear[m+2];
  240. for (Bit8u bit=(0x80 >> cursorStartBit); bit != 0; bit >>= 1) {
  241. // for each bit
  242. cursorStartBit=0; // only the first byte has some bits cut off
  243. if (bitsA&bit) {
  244. if (bitsB&bit) *xat ^= 0xFF; // Invert screen data
  245. //else Transparent
  246. } else if (bitsB&bit) {
  247. *xat = vga.s3.hgc.forestack[0]; // foreground color
  248. } else {
  249. *xat = vga.s3.hgc.backstack[0];
  250. }
  251. xat++;
  252. }
  253. }
  254. return TempLine;
  255. }
  256. }
  257. static Bit8u * VGA_Draw_LIN16_Line_HWMouse(Bitu vidstart, Bitu /*line*/) {
  258. if (!svga.hardware_cursor_active || !svga.hardware_cursor_active())
  259. return &vga.mem.linear[vidstart];
  260. Bitu lineat = ((vidstart-(vga.config.real_start<<2)) >> 1) / vga.draw.width;
  261. if ((vga.s3.hgc.posx >= vga.draw.width) ||
  262. (lineat < vga.s3.hgc.originy) ||
  263. (lineat > (vga.s3.hgc.originy + (63U-vga.s3.hgc.posy))) ) {
  264. return &vga.mem.linear[vidstart];
  265. } else {
  266. memcpy(TempLine, &vga.mem.linear[ vidstart ], vga.draw.width*2);
  267. Bitu sourceStartBit = ((lineat - vga.s3.hgc.originy) + vga.s3.hgc.posy)*64 + vga.s3.hgc.posx;
  268. Bitu cursorMemStart = ((sourceStartBit >> 2)& ~1) + (((Bit32u)vga.s3.hgc.startaddr) << 10);
  269. Bitu cursorStartBit = sourceStartBit & 0x7;
  270. if (cursorMemStart & 0x2) cursorMemStart--;
  271. Bitu cursorMemEnd = cursorMemStart + ((64-vga.s3.hgc.posx) >> 2);
  272. Bit16u* xat = &((Bit16u*)TempLine)[vga.s3.hgc.originx];
  273. for (Bitu m = cursorMemStart; m < cursorMemEnd; (m&1)?(m+=3):m++) {
  274. // for each byte of cursor data
  275. Bit8u bitsA = vga.mem.linear[m];
  276. Bit8u bitsB = vga.mem.linear[m+2];
  277. for (Bit8u bit=(0x80 >> cursorStartBit); bit != 0; bit >>= 1) {
  278. // for each bit
  279. cursorStartBit=0;
  280. if (bitsA&bit) {
  281. // byte order doesn't matter here as all bits get flipped
  282. if (bitsB&bit) *xat ^= ~0U;
  283. //else Transparent
  284. } else if (bitsB&bit) {
  285. // Source as well as destination are Bit8u arrays,
  286. // so this should work out endian-wise?
  287. *xat = *(Bit16u*)vga.s3.hgc.forestack;
  288. } else {
  289. *xat = *(Bit16u*)vga.s3.hgc.backstack;
  290. }
  291. xat++;
  292. }
  293. }
  294. return TempLine;
  295. }
  296. }
  297. static Bit8u * VGA_Draw_LIN32_Line_HWMouse(Bitu vidstart, Bitu /*line*/) {
  298. if (!svga.hardware_cursor_active || !svga.hardware_cursor_active())
  299. return &vga.mem.linear[vidstart];
  300. Bitu lineat = ((vidstart-(vga.config.real_start<<2)) >> 2) / vga.draw.width;
  301. if ((vga.s3.hgc.posx >= vga.draw.width) ||
  302. (lineat < vga.s3.hgc.originy) ||
  303. (lineat > (vga.s3.hgc.originy + (63U-vga.s3.hgc.posy))) ) {
  304. return &vga.mem.linear[ vidstart ];
  305. } else {
  306. memcpy(TempLine, &vga.mem.linear[ vidstart ], vga.draw.width*4);
  307. Bitu sourceStartBit = ((lineat - vga.s3.hgc.originy) + vga.s3.hgc.posy)*64 + vga.s3.hgc.posx;
  308. Bitu cursorMemStart = ((sourceStartBit >> 2)& ~1) + (((Bit32u)vga.s3.hgc.startaddr) << 10);
  309. Bitu cursorStartBit = sourceStartBit & 0x7;
  310. if (cursorMemStart & 0x2) cursorMemStart--;
  311. Bitu cursorMemEnd = cursorMemStart + ((64-vga.s3.hgc.posx) >> 2);
  312. Bit32u* xat = &((Bit32u*)TempLine)[vga.s3.hgc.originx];
  313. for (Bitu m = cursorMemStart; m < cursorMemEnd; (m&1)?(m+=3):m++) {
  314. // for each byte of cursor data
  315. Bit8u bitsA = vga.mem.linear[m];
  316. Bit8u bitsB = vga.mem.linear[m+2];
  317. for (Bit8u bit=(0x80 >> cursorStartBit); bit != 0; bit >>= 1) { // for each bit
  318. cursorStartBit=0;
  319. if (bitsA&bit) {
  320. if (bitsB&bit) *xat ^= ~0U;
  321. //else Transparent
  322. } else if (bitsB&bit) {
  323. *xat = *(Bit32u*)vga.s3.hgc.forestack;
  324. } else {
  325. *xat = *(Bit32u*)vga.s3.hgc.backstack;
  326. }
  327. xat++;
  328. }
  329. }
  330. return TempLine;
  331. }
  332. }
  333. static const Bit8u* VGA_Text_Memwrap(Bitu vidstart) {
  334. vidstart &= vga.draw.linear_mask;
  335. Bitu line_end = 2 * vga.draw.blocks;
  336. if (GCC_UNLIKELY((vidstart + line_end) > vga.draw.linear_mask)) {
  337. // wrapping in this line
  338. Bitu break_pos = (vga.draw.linear_mask - vidstart) + 1;
  339. // need a temporary storage - TempLine/2 is ok for a bit more than 132 columns
  340. memcpy(&TempLine[sizeof(TempLine)/2], &vga.tandy.draw_base[vidstart], break_pos);
  341. memcpy(&TempLine[sizeof(TempLine)/2 + break_pos],&vga.tandy.draw_base[0], line_end - break_pos);
  342. return &TempLine[sizeof(TempLine)/2];
  343. } else return &vga.tandy.draw_base[vidstart];
  344. }
  345. static Bit32u FontMask[2]={0xffffffff,0x0};
  346. static Bit8u * VGA_TEXT_Draw_Line(Bitu vidstart, Bitu line) {
  347. Bits font_addr;
  348. Bit32u * draw=(Bit32u *)TempLine;
  349. const Bit8u* vidmem = VGA_Text_Memwrap(vidstart);
  350. for (Bitu cx=0;cx<vga.draw.blocks;cx++) {
  351. Bitu chr=vidmem[cx*2];
  352. Bitu col=vidmem[cx*2+1];
  353. Bitu font=vga.draw.font_tables[(col >> 3)&1][chr*32+line];
  354. Bit32u mask1=TXT_Font_Table[font>>4] & FontMask[col >> 7];
  355. Bit32u mask2=TXT_Font_Table[font&0xf] & FontMask[col >> 7];
  356. Bit32u fg=TXT_FG_Table[col&0xf];
  357. Bit32u bg=TXT_BG_Table[col>>4];
  358. *draw++=(fg&mask1) | (bg&~mask1);
  359. *draw++=(fg&mask2) | (bg&~mask2);
  360. }
  361. if (!vga.draw.cursor.enabled || !(vga.draw.cursor.count&0x8)) goto skip_cursor;
  362. font_addr = (vga.draw.cursor.address-vidstart) >> 1;
  363. if (font_addr>=0 && font_addr<(Bits)vga.draw.blocks) {
  364. if (line<vga.draw.cursor.sline) goto skip_cursor;
  365. if (line>vga.draw.cursor.eline) goto skip_cursor;
  366. draw=(Bit32u *)&TempLine[font_addr*8];
  367. Bit32u att=TXT_FG_Table[vga.tandy.draw_base[vga.draw.cursor.address+1]&0xf];
  368. *draw++=att;*draw++=att;
  369. }
  370. skip_cursor:
  371. return TempLine;
  372. }
  373. static Bit8u * VGA_TEXT_Herc_Draw_Line(Bitu vidstart, Bitu line) {
  374. Bits font_addr;
  375. Bit32u * draw=(Bit32u *)TempLine;
  376. const Bit8u* vidmem = VGA_Text_Memwrap(vidstart);
  377. for (Bitu cx=0;cx<vga.draw.blocks;cx++) {
  378. Bitu chr=vidmem[cx*2];
  379. Bitu attrib=vidmem[cx*2+1];
  380. if (!(attrib&0x77)) {
  381. // 00h, 80h, 08h, 88h produce black space
  382. *draw++=0;
  383. *draw++=0;
  384. } else {
  385. Bit32u bg, fg;
  386. bool underline=false;
  387. if ((attrib&0x77)==0x70) {
  388. bg = TXT_BG_Table[0x7];
  389. if (attrib&0x8) fg = TXT_FG_Table[0xf];
  390. else fg = TXT_FG_Table[0x0];
  391. } else {
  392. if (((Bitu)(vga.crtc.underline_location&0x1f)==line) && ((attrib&0x77)==0x1)) underline=true;
  393. bg = TXT_BG_Table[0x0];
  394. if (attrib&0x8) fg = TXT_FG_Table[0xf];
  395. else fg = TXT_FG_Table[0x7];
  396. }
  397. Bit32u mask1, mask2;
  398. if (GCC_UNLIKELY(underline)) mask1 = mask2 = FontMask[attrib >> 7];
  399. else {
  400. Bitu font=vga.draw.font_tables[0][chr*32+line];
  401. mask1=TXT_Font_Table[font>>4] & FontMask[attrib >> 7]; // blinking
  402. mask2=TXT_Font_Table[font&0xf] & FontMask[attrib >> 7];
  403. }
  404. *draw++=(fg&mask1) | (bg&~mask1);
  405. *draw++=(fg&mask2) | (bg&~mask2);
  406. }
  407. }
  408. if (!vga.draw.cursor.enabled || !(vga.draw.cursor.count&0x8)) goto skip_cursor;
  409. font_addr = (vga.draw.cursor.address-vidstart) >> 1;
  410. if (font_addr>=0 && font_addr<(Bits)vga.draw.blocks) {
  411. if (line<vga.draw.cursor.sline) goto skip_cursor;
  412. if (line>vga.draw.cursor.eline) goto skip_cursor;
  413. draw=(Bit32u *)&TempLine[font_addr*8];
  414. Bit8u attr = vga.tandy.draw_base[vga.draw.cursor.address+1];
  415. Bit32u cg;
  416. if (attr&0x8) {
  417. cg = TXT_FG_Table[0xf];
  418. } else if ((attr&0x77)==0x70) {
  419. cg = TXT_FG_Table[0x0];
  420. } else {
  421. cg = TXT_FG_Table[0x7];
  422. }
  423. *draw++=cg;*draw++=cg;
  424. }
  425. skip_cursor:
  426. return TempLine;
  427. }
  428. static Bit8u * VGA_TEXT_Xlat16_Draw_Line(Bitu vidstart, Bitu line) {
  429. Bits font_addr;
  430. Bit16u * draw=(Bit16u *)TempLine;
  431. const Bit8u* vidmem = VGA_Text_Memwrap(vidstart);
  432. for (Bitu cx=0;cx<vga.draw.blocks;cx++) {
  433. Bitu chr=vidmem[cx*2];
  434. Bitu col=vidmem[cx*2+1];
  435. Bitu font=vga.draw.font_tables[(col >> 3)&1][chr*32+line];
  436. Bit32u mask1=TXT_Font_Table[font>>4] & FontMask[col >> 7];
  437. Bit32u mask2=TXT_Font_Table[font&0xf] & FontMask[col >> 7];
  438. Bit32u fg=TXT_FG_Table[col&0xf];
  439. Bit32u bg=TXT_BG_Table[col>>4];
  440. mask1=(fg&mask1) | (bg&~mask1);
  441. mask2=(fg&mask2) | (bg&~mask2);
  442. for(int i = 0; i < 4; i++) {
  443. *draw++ = vga.dac.xlat16[(mask1>>8*i)&0xff];
  444. }
  445. for(int i = 0; i < 4; i++) {
  446. *draw++ = vga.dac.xlat16[(mask2>>8*i)&0xff];
  447. }
  448. }
  449. if (!vga.draw.cursor.enabled || !(vga.draw.cursor.count&0x8)) goto skip_cursor;
  450. font_addr = (vga.draw.cursor.address-vidstart) >> 1;
  451. if (font_addr>=0 && font_addr<(Bits)vga.draw.blocks) {
  452. if (line<vga.draw.cursor.sline) goto skip_cursor;
  453. if (line>vga.draw.cursor.eline) goto skip_cursor;
  454. draw=(Bit16u *)&TempLine[font_addr*16];
  455. Bit8u att=(Bit8u)(TXT_FG_Table[vga.tandy.draw_base[vga.draw.cursor.address+1]&0xf]&0xff);
  456. for(int i = 0; i < 8; i++) {
  457. *draw++ = vga.dac.xlat16[att];
  458. }
  459. }
  460. skip_cursor:
  461. return TempLine;
  462. }
  463. /*
  464. static Bit8u * VGA_TEXT_Draw_Line_9(Bitu vidstart, Bitu line) {
  465. Bits font_addr;
  466. Bit8u * draw=(Bit8u *)TempLine;
  467. bool underline=(Bitu)(vga.crtc.underline_location&0x1f)==line;
  468. Bit8u pel_pan=(Bit8u)vga.draw.panning;
  469. if ((vga.attr.mode_control&0x20) && (vga.draw.lines_done>=vga.draw.split_line)) pel_pan=0;
  470. const Bit8u* vidmem = VGA_Text_Memwrap(vidstart);
  471. Bit8u chr=vidmem[0];
  472. Bit8u col=vidmem[1];
  473. Bit8u font=(vga.draw.font_tables[(col >> 3)&1][chr*32+line])<<pel_pan;
  474. if (underline && ((col&0x07) == 0x01)) font=0xff;
  475. Bit8u fg=col&0xf;
  476. Bit8u bg=(Bit8u)(TXT_BG_Table[col>>4]&0xff);
  477. Bitu draw_blocks=vga.draw.blocks;
  478. draw_blocks++;
  479. for (Bitu cx=1;cx<draw_blocks;cx++) {
  480. if (pel_pan) {
  481. chr=vidmem[cx*2];
  482. col=vidmem[cx*2+1];
  483. if (underline && ((col&0x07) == 0x01)) font|=0xff>>(8-pel_pan);
  484. else font|=vga.draw.font_tables[(col >> 3)&1][chr*32+line]>>(8-pel_pan);
  485. fg=col&0xf;
  486. bg=(Bit8u)(TXT_BG_Table[col>>4]&0xff);
  487. } else {
  488. chr=vidmem[(cx-1)*2];
  489. col=vidmem[(cx-1)*2+1];
  490. if (underline && ((col&0x07) == 0x01)) font=0xff;
  491. else font=vga.draw.font_tables[(col >> 3)&1][chr*32+line];
  492. fg=col&0xf;
  493. bg=(Bit8u)(TXT_BG_Table[col>>4]&0xff);
  494. }
  495. if (FontMask[col>>7]==0) font=0;
  496. *draw++=(font&0x80)?fg:bg; *draw++=(font&0x40)?fg:bg;
  497. *draw++=(font&0x20)?fg:bg; *draw++=(font&0x10)?fg:bg;
  498. *draw++=(font&0x08)?fg:bg; *draw++=(font&0x04)?fg:bg;
  499. *draw++=(font&0x02)?fg:bg;
  500. Bit8u last=(font&0x01)?fg:bg;
  501. *draw++=last;
  502. *draw++=((vga.attr.mode_control&0x04) && ((chr<0xc0) || (chr>0xdf))) ? bg : last;
  503. if (pel_pan) {
  504. if (underline && ((col&0x07) == 0x01)) font=0xff;
  505. else font=(vga.draw.font_tables[(col >> 3)&1][chr*32+line])<<pel_pan;
  506. }
  507. }
  508. if (!vga.draw.cursor.enabled || !(vga.draw.cursor.count&0x8)) goto skip_cursor;
  509. font_addr = (vga.draw.cursor.address-vidstart) >> 1;
  510. if (font_addr>=0 && font_addr<(Bits)vga.draw.blocks) {
  511. if (line<vga.draw.cursor.sline) goto skip_cursor;
  512. if (line>vga.draw.cursor.eline) goto skip_cursor;
  513. draw=&TempLine[font_addr*9];
  514. Bit8u fg=vga.tandy.draw_base[vga.draw.cursor.address+1]&0xf;
  515. *draw++=fg; *draw++=fg; *draw++=fg; *draw++=fg;
  516. *draw++=fg; *draw++=fg; *draw++=fg; *draw++=fg;
  517. }
  518. skip_cursor:
  519. return TempLine;
  520. }
  521. */
  522. static Bit8u * VGA_TEXT_Xlat16_Draw_Line_9(Bitu vidstart, Bitu line) {
  523. Bits font_addr;
  524. Bit16u * draw=(Bit16u *)TempLine;
  525. bool underline=(Bitu)(vga.crtc.underline_location&0x1f)==line;
  526. Bit8u pel_pan=(Bit8u)vga.draw.panning;
  527. if ((vga.attr.mode_control&0x20) && (vga.draw.lines_done>=vga.draw.split_line)) pel_pan=0;
  528. const Bit8u* vidmem = VGA_Text_Memwrap(vidstart);
  529. Bit8u chr=vidmem[0];
  530. Bit8u col=vidmem[1];
  531. Bit8u font=(vga.draw.font_tables[(col >> 3)&1][chr*32+line])<<pel_pan;
  532. if (underline && ((col&0x07) == 0x01)) font=0xff;
  533. Bit8u fg=col&0xf;
  534. Bit8u bg=(Bit8u)(TXT_BG_Table[col>>4]&0xff);
  535. Bitu draw_blocks=vga.draw.blocks;
  536. draw_blocks++;
  537. for (Bitu cx=1;cx<draw_blocks;cx++) {
  538. if (pel_pan) {
  539. chr=vidmem[cx*2];
  540. col=vidmem[cx*2+1];
  541. if (underline && ((col&0x07) == 0x01)) font|=0xff>>(8-pel_pan);
  542. else font|=vga.draw.font_tables[(col >> 3)&1][chr*32+line]>>(8-pel_pan);
  543. fg=col&0xf;
  544. bg=(Bit8u)(TXT_BG_Table[col>>4]&0xff);
  545. } else {
  546. chr=vidmem[(cx-1)*2];
  547. col=vidmem[(cx-1)*2+1];
  548. if (underline && ((col&0x07) == 0x01)) font=0xff;
  549. else font=vga.draw.font_tables[(col >> 3)&1][chr*32+line];
  550. fg=col&0xf;
  551. bg=(Bit8u)(TXT_BG_Table[col>>4]&0xff);
  552. }
  553. if (FontMask[col>>7]==0) font=0;
  554. Bit8u mask=0x80;
  555. for (int i = 0; i < 7; i++) {
  556. *draw++=vga.dac.xlat16[font&mask?fg:bg];
  557. mask>>=1;
  558. }
  559. Bit16u lastval=vga.dac.xlat16[font&mask?fg:bg];
  560. *draw++=lastval;
  561. *draw++=(((vga.attr.mode_control&0x04) && ((chr<0xc0) || (chr>0xdf))) &&
  562. !(underline && ((col&0x07) == 0x01))) ?
  563. (vga.dac.xlat16[bg]) : lastval;
  564. if (pel_pan) {
  565. if (underline && ((col&0x07) == 0x01)) font=0xff;
  566. else font=(vga.draw.font_tables[(col >> 3)&1][chr*32+line])<<pel_pan;
  567. }
  568. }
  569. if (!vga.draw.cursor.enabled || !(vga.draw.cursor.count&0x8)) goto skip_cursor;
  570. font_addr = (vga.draw.cursor.address-vidstart) >> 1;
  571. if (font_addr>=0 && font_addr<(Bits)vga.draw.blocks) {
  572. if (line<vga.draw.cursor.sline) goto skip_cursor;
  573. if (line>vga.draw.cursor.eline) goto skip_cursor;
  574. draw=(Bit16u*)&TempLine[font_addr*18];
  575. fg=vga.tandy.draw_base[vga.draw.cursor.address+1]&0xf;
  576. for(int i = 0; i < 8; i++) {
  577. *draw++ = vga.dac.xlat16[fg];
  578. }
  579. //if(underline && ((col&0x07) == 0x01))
  580. // *draw = vga.dac.xlat16[fg];
  581. }
  582. skip_cursor:
  583. return TempLine;
  584. }
  585. #ifdef VGA_KEEP_CHANGES
  586. static INLINE void VGA_ChangesEnd(void ) {
  587. if ( vga.changes.active ) {
  588. // vga.changes.active = false;
  589. Bitu end = vga.draw.address >> VGA_CHANGE_SHIFT;
  590. Bitu total = 4 + end - vga.changes.start;
  591. Bit32u clearMask = vga.changes.clearMask;
  592. total >>= 2;
  593. Bit32u *clear = (Bit32u *)&vga.changes.map[ vga.changes.start & ~3 ];
  594. while ( total-- ) {
  595. clear[0] &= clearMask;
  596. clear++;
  597. }
  598. }
  599. }
  600. #endif
  601. static void VGA_ProcessSplit() {
  602. // On the EGA the address is always reset to 0.
  603. if ((vga.attr.mode_control&0x20) || (machine==MCH_EGA)) {
  604. vga.draw.address=0;
  605. } else {
  606. // In text mode only the characters are shifted by panning, not the address;
  607. // this is done in the text line draw function.
  608. vga.draw.address = vga.draw.byte_panning_shift*vga.draw.bytes_skip;
  609. if (!(vga.mode==M_TEXT)) vga.draw.address += vga.draw.panning;
  610. }
  611. vga.draw.address_line=0;
  612. }
  613. static void VGA_DrawSingleLine(Bitu /*blah*/) {
  614. if (GCC_UNLIKELY(vga.attr.disabled)) {
  615. // draw blanked line (DoWhackaDo, Alien Carnage, TV sports Football)
  616. memset(TempLine, 0, sizeof(TempLine));
  617. RENDER_DrawLine(TempLine);
  618. } else {
  619. Bit8u * data=VGA_DrawLine( vga.draw.address, vga.draw.address_line );
  620. RENDER_DrawLine(data);
  621. }
  622. vga.draw.address_line++;
  623. if (vga.draw.address_line>=vga.draw.address_line_total) {
  624. vga.draw.address_line=0;
  625. vga.draw.address+=vga.draw.address_add;
  626. }
  627. vga.draw.lines_done++;
  628. if (vga.draw.split_line==vga.draw.lines_done) VGA_ProcessSplit();
  629. if (vga.draw.lines_done < vga.draw.lines_total) {
  630. PIC_AddEvent(VGA_DrawSingleLine,(float)vga.draw.delay.htotal);
  631. } else RENDER_EndUpdate(false);
  632. }
  633. static void VGA_DrawPart(Bitu lines) {
  634. while (lines--) {
  635. Bit8u * data=VGA_DrawLine( vga.draw.address, vga.draw.address_line );
  636. RENDER_DrawLine(data);
  637. vga.draw.address_line++;
  638. if (vga.draw.address_line>=vga.draw.address_line_total) {
  639. vga.draw.address_line=0;
  640. vga.draw.address+=vga.draw.address_add;
  641. }
  642. vga.draw.lines_done++;
  643. if (vga.draw.split_line==vga.draw.lines_done) {
  644. #ifdef VGA_KEEP_CHANGES
  645. VGA_ChangesEnd( );
  646. #endif
  647. VGA_ProcessSplit();
  648. #ifdef VGA_KEEP_CHANGES
  649. vga.changes.start = vga.draw.address >> VGA_CHANGE_SHIFT;
  650. #endif
  651. }
  652. }
  653. if (--vga.draw.parts_left) {
  654. PIC_AddEvent(VGA_DrawPart,(float)vga.draw.delay.parts,
  655. (vga.draw.parts_left!=1) ? vga.draw.parts_lines : (vga.draw.lines_total - vga.draw.lines_done));
  656. } else {
  657. #ifdef VGA_KEEP_CHANGES
  658. VGA_ChangesEnd();
  659. #endif
  660. RENDER_EndUpdate(false);
  661. }
  662. }
  663. void VGA_SetBlinking(Bitu enabled) {
  664. Bitu b;
  665. LOG(LOG_VGA,LOG_NORMAL)("Blinking %d",enabled);
  666. if (enabled) {
  667. b=0;vga.draw.blinking=1; //used to -1 but blinking is unsigned
  668. vga.attr.mode_control|=0x08;
  669. vga.tandy.mode_control|=0x20;
  670. } else {
  671. b=8;vga.draw.blinking=0;
  672. vga.attr.mode_control&=~0x08;
  673. vga.tandy.mode_control&=~0x20;
  674. }
  675. for (Bitu i=0;i<8;i++) TXT_BG_Table[i+8]=(b+i) | ((b+i) << 8)| ((b+i) <<16) | ((b+i) << 24);
  676. }
  677. #ifdef VGA_KEEP_CHANGES
  678. static void INLINE VGA_ChangesStart( void ) {
  679. vga.changes.start = vga.draw.address >> VGA_CHANGE_SHIFT;
  680. vga.changes.last = vga.changes.start;
  681. if ( vga.changes.lastAddress != vga.draw.address ) {
  682. // LOG_MSG("Address");
  683. VGA_DrawLine = VGA_Draw_Linear_Line;
  684. vga.changes.lastAddress = vga.draw.address;
  685. } else if ( render.fullFrame ) {
  686. // LOG_MSG("Full Frame");
  687. VGA_DrawLine = VGA_Draw_Linear_Line;
  688. } else {
  689. // LOG_MSG("Changes");
  690. VGA_DrawLine = VGA_Draw_Changes_Line;
  691. }
  692. vga.changes.active = true;
  693. vga.changes.checkMask = vga.changes.writeMask;
  694. vga.changes.clearMask = ~( 0x01010101 << (vga.changes.frame & 7));
  695. vga.changes.frame++;
  696. vga.changes.writeMask = 1 << (vga.changes.frame & 7);
  697. }
  698. #endif
  699. static void VGA_VertInterrupt(Bitu /*val*/) {
  700. if ((!vga.draw.vret_triggered) && ((vga.crtc.vertical_retrace_end&0x30)==0x10)) {
  701. vga.draw.vret_triggered=true;
  702. if (GCC_UNLIKELY(machine==MCH_EGA)) PIC_ActivateIRQ(9);
  703. }
  704. }
  705. static void VGA_Other_VertInterrupt(Bitu val) {
  706. if (val) PIC_ActivateIRQ(5);
  707. else PIC_DeActivateIRQ(5);
  708. }
  709. static void VGA_DisplayStartLatch(Bitu /*val*/) {
  710. vga.config.real_start=vga.config.display_start & (vga.vmemwrap-1);
  711. vga.draw.bytes_skip = vga.config.bytes_skip;
  712. }
  713. static void VGA_PanningLatch(Bitu /*val*/) {
  714. vga.draw.panning = vga.config.pel_panning;
  715. }
  716. static void VGA_VerticalTimer(Bitu /*val*/) {
  717. vga.draw.delay.framestart = PIC_FullIndex();
  718. PIC_AddEvent( VGA_VerticalTimer, (float)vga.draw.delay.vtotal );
  719. switch(machine) {
  720. case MCH_PCJR:
  721. case MCH_TANDY:
  722. // PCJr: Vsync is directly connected to the IRQ controller
  723. // Some earlier Tandy models are said to have a vsync interrupt too
  724. PIC_AddEvent(VGA_Other_VertInterrupt, (float)vga.draw.delay.vrstart, 1);
  725. PIC_AddEvent(VGA_Other_VertInterrupt, (float)vga.draw.delay.vrend, 0);
  726. // fall-through
  727. case MCH_CGA:
  728. case MCH_HERC:
  729. // MC6845-powered graphics: Loading the display start latch happens somewhere
  730. // after vsync off and before first visible scanline, so probably here
  731. VGA_DisplayStartLatch(0);
  732. break;
  733. case MCH_VGA:
  734. case MCH_EGA:
  735. PIC_AddEvent(VGA_DisplayStartLatch, (float)vga.draw.delay.vrstart);
  736. PIC_AddEvent(VGA_PanningLatch, (float)vga.draw.delay.vrend);
  737. // EGA: 82c435 datasheet: interrupt happens at display end
  738. // VGA: checked with scope; however disabled by default by jumper on VGA boards
  739. // add a little amount of time to make sure the last drawpart has already fired
  740. PIC_AddEvent(VGA_VertInterrupt,(float)(vga.draw.delay.vdend + 0.005));
  741. break;
  742. default:
  743. E_Exit("This new machine needs implementation in VGA_VerticalTimer too.");
  744. break;
  745. }
  746. //Check if we can actually render, else skip the rest (frameskip)
  747. if (!RENDER_StartUpdate())
  748. return;
  749. vga.draw.address_line = vga.config.hlines_skip;
  750. if (IS_EGAVGA_ARCH) {
  751. vga.draw.split_line = (Bitu)((vga.config.line_compare+1)/vga.draw.lines_scaled);
  752. if ((svgaCard==SVGA_S3Trio) && (vga.config.line_compare==0)) vga.draw.split_line=0;
  753. vga.draw.split_line -= vga.draw.vblank_skip;
  754. } else {
  755. vga.draw.split_line = 0x10000; // don't care
  756. }
  757. vga.draw.address = vga.config.real_start;
  758. vga.draw.byte_panning_shift = 0;
  759. // go figure...
  760. if (machine==MCH_EGA) vga.draw.split_line*=2;
  761. // if (machine==MCH_EGA) vga.draw.split_line = ((((vga.config.line_compare&0x5ff)+1)*2-1)/vga.draw.lines_scaled);
  762. #ifdef VGA_KEEP_CHANGES
  763. bool startaddr_changed=false;
  764. #endif
  765. switch (vga.mode) {
  766. case M_EGA:
  767. if (!(vga.crtc.mode_control&0x1)) vga.draw.linear_mask &= ~0x10000;
  768. else vga.draw.linear_mask |= 0x10000;
  769. case M_LIN4:
  770. vga.draw.byte_panning_shift = 8;
  771. vga.draw.address += vga.draw.bytes_skip;
  772. vga.draw.address *= vga.draw.byte_panning_shift;
  773. vga.draw.address += vga.draw.panning;
  774. #ifdef VGA_KEEP_CHANGES
  775. startaddr_changed=true;
  776. #endif
  777. break;
  778. case M_VGA:
  779. if(vga.config.compatible_chain4 && (vga.crtc.underline_location & 0x40)) {
  780. vga.draw.linear_base = vga.fastmem;
  781. vga.draw.linear_mask = 0xffff;
  782. } else {
  783. vga.draw.linear_base = vga.mem.linear;
  784. vga.draw.linear_mask = vga.vmemwrap - 1;
  785. }
  786. case M_LIN8:
  787. case M_LIN15:
  788. case M_LIN16:
  789. case M_LIN32:
  790. vga.draw.byte_panning_shift = 4;
  791. vga.draw.address += vga.draw.bytes_skip;
  792. vga.draw.address *= vga.draw.byte_panning_shift;
  793. vga.draw.address += vga.draw.panning;
  794. #ifdef VGA_KEEP_CHANGES
  795. startaddr_changed=true;
  796. #endif
  797. break;
  798. case M_TEXT:
  799. vga.draw.byte_panning_shift = 2;
  800. vga.draw.address += vga.draw.bytes_skip;
  801. // fall-through
  802. case M_TANDY_TEXT:
  803. case M_HERC_TEXT:
  804. if (machine==MCH_HERC) vga.draw.linear_mask = 0xfff; // 1 page
  805. else if (IS_EGAVGA_ARCH) vga.draw.linear_mask = 0x7fff; // 8 pages
  806. else vga.draw.linear_mask = 0x3fff; // CGA, Tandy 4 pages
  807. vga.draw.cursor.address=vga.config.cursor_start*2;
  808. vga.draw.address *= 2;
  809. vga.draw.cursor.count++;
  810. /* check for blinking and blinking change delay */
  811. FontMask[1]=(vga.draw.blinking & (vga.draw.cursor.count >> 4)) ?
  812. 0 : 0xffffffff;
  813. break;
  814. case M_HERC_GFX:
  815. break;
  816. case M_CGA4:case M_CGA2:
  817. vga.draw.address=(vga.draw.address*2)&0x1fff;
  818. break;
  819. case M_CGA16:
  820. case M_TANDY2:case M_TANDY4:case M_TANDY16:
  821. vga.draw.address *= 2;
  822. break;
  823. default:
  824. break;
  825. }
  826. if (GCC_UNLIKELY(vga.draw.split_line==0)) VGA_ProcessSplit();
  827. #ifdef VGA_KEEP_CHANGES
  828. if (startaddr_changed) VGA_ChangesStart();
  829. #endif
  830. // check if some lines at the top off the screen are blanked
  831. float draw_skip = 0.0f;
  832. if (GCC_UNLIKELY(vga.draw.vblank_skip)) {
  833. draw_skip = (float)(vga.draw.delay.htotal * vga.draw.vblank_skip);
  834. vga.draw.address += vga.draw.address_add * (vga.draw.vblank_skip/(vga.draw.address_line_total));
  835. }
  836. // add the draw event
  837. switch (vga.draw.mode) {
  838. case PART:
  839. if (GCC_UNLIKELY(vga.draw.parts_left)) {
  840. LOG(LOG_VGAMISC,LOG_NORMAL)( "Parts left: %d", vga.draw.parts_left );
  841. PIC_RemoveEvents(VGA_DrawPart);
  842. RENDER_EndUpdate(true);
  843. }
  844. vga.draw.lines_done = 0;
  845. vga.draw.parts_left = vga.draw.parts_total;
  846. PIC_AddEvent(VGA_DrawPart,(float)vga.draw.delay.parts + draw_skip,vga.draw.parts_lines);
  847. break;
  848. case LINE:
  849. if (GCC_UNLIKELY(vga.draw.lines_done < vga.draw.lines_total)) {
  850. LOG(LOG_VGAMISC,LOG_NORMAL)( "Lines left: %d",
  851. vga.draw.lines_total-vga.draw.lines_done);
  852. PIC_RemoveEvents(VGA_DrawSingleLine);
  853. RENDER_EndUpdate(true);
  854. }
  855. vga.draw.lines_done = 0;
  856. PIC_AddEvent(VGA_DrawSingleLine,(float)(vga.draw.delay.htotal/4.0 + draw_skip));
  857. break;
  858. //case EGALINE:
  859. }
  860. }
  861. void VGA_CheckScanLength(void) {
  862. switch (vga.mode) {
  863. case M_EGA:
  864. case M_LIN4:
  865. vga.draw.address_add=vga.config.scan_len*16;
  866. break;
  867. case M_VGA:
  868. case M_LIN8:
  869. case M_LIN15:
  870. case M_LIN16:
  871. case M_LIN32:
  872. vga.draw.address_add=vga.config.scan_len*8;
  873. break;
  874. case M_TEXT:
  875. vga.draw.address_add=vga.config.scan_len*4;
  876. break;
  877. case M_CGA2:
  878. case M_CGA4:
  879. case M_CGA16:
  880. vga.draw.address_add=80;
  881. return;
  882. case M_TANDY2:
  883. vga.draw.address_add=vga.draw.blocks/4;
  884. break;
  885. case M_TANDY4:
  886. vga.draw.address_add=vga.draw.blocks;
  887. break;
  888. case M_TANDY16:
  889. vga.draw.address_add=vga.draw.blocks;
  890. break;
  891. case M_TANDY_TEXT:
  892. vga.draw.address_add=vga.draw.blocks*2;
  893. break;
  894. case M_HERC_TEXT:
  895. vga.draw.address_add=vga.draw.blocks*2;
  896. break;
  897. case M_HERC_GFX:
  898. vga.draw.address_add=vga.draw.blocks;
  899. break;
  900. default:
  901. vga.draw.address_add=vga.draw.blocks*8;
  902. break;
  903. }
  904. }
  905. void VGA_ActivateHardwareCursor(void) {
  906. bool hwcursor_active=false;
  907. if (svga.hardware_cursor_active) {
  908. if (svga.hardware_cursor_active()) hwcursor_active=true;
  909. }
  910. if (hwcursor_active) {
  911. switch(vga.mode) {
  912. case M_LIN32:
  913. VGA_DrawLine=VGA_Draw_LIN32_Line_HWMouse;
  914. break;
  915. case M_LIN15:
  916. case M_LIN16:
  917. VGA_DrawLine=VGA_Draw_LIN16_Line_HWMouse;
  918. break;
  919. default:
  920. VGA_DrawLine=VGA_Draw_VGA_Line_HWMouse;
  921. }
  922. } else {
  923. VGA_DrawLine=VGA_Draw_Linear_Line;
  924. }
  925. }
  926. void VGA_SetupDrawing(Bitu /*val*/) {
  927. if (vga.mode==M_ERROR) {
  928. PIC_RemoveEvents(VGA_VerticalTimer);
  929. PIC_RemoveEvents(VGA_PanningLatch);
  930. PIC_RemoveEvents(VGA_DisplayStartLatch);
  931. return;
  932. }
  933. // set the drawing mode
  934. switch (machine) {
  935. case MCH_CGA:
  936. case MCH_PCJR:
  937. vga.draw.mode = LINE;
  938. break;
  939. case MCH_VGA:
  940. if (svgaCard==SVGA_None) {
  941. vga.draw.mode = LINE;
  942. break;
  943. }
  944. // fall-through
  945. default:
  946. vga.draw.mode = PART;
  947. break;
  948. }
  949. /* Calculate the FPS for this screen */
  950. double fps; Bitu clock;
  951. Bitu htotal, hdend, hbstart, hbend, hrstart, hrend;
  952. Bitu vtotal, vdend, vbstart, vbend, vrstart, vrend;
  953. Bitu vblank_skip;
  954. if (IS_EGAVGA_ARCH) {
  955. htotal = vga.crtc.horizontal_total;
  956. hdend = vga.crtc.horizontal_display_end;
  957. hbend = vga.crtc.end_horizontal_blanking&0x1F;
  958. hbstart = vga.crtc.start_horizontal_blanking;
  959. hrstart = vga.crtc.start_horizontal_retrace;
  960. vtotal= vga.crtc.vertical_total | ((vga.crtc.overflow & 1) << 8);
  961. vdend = vga.crtc.vertical_display_end | ((vga.crtc.overflow & 2)<<7);
  962. vbstart = vga.crtc.start_vertical_blanking | ((vga.crtc.overflow & 0x08) << 5);
  963. vrstart = vga.crtc.vertical_retrace_start + ((vga.crtc.overflow & 0x04) << 6);
  964. if (IS_VGA_ARCH) {
  965. // additional bits only present on vga cards
  966. htotal |= (vga.s3.ex_hor_overflow & 0x1) << 8;
  967. htotal += 3;
  968. hdend |= (vga.s3.ex_hor_overflow & 0x2) << 7;
  969. hbend |= (vga.crtc.end_horizontal_retrace&0x80) >> 2;
  970. hbstart |= (vga.s3.ex_hor_overflow & 0x4) << 6;
  971. hrstart |= (vga.s3.ex_hor_overflow & 0x10) << 4;
  972. vtotal |= (vga.crtc.overflow & 0x20) << 4;
  973. vtotal |= (vga.s3.ex_ver_overflow & 0x1) << 10;
  974. vdend |= (vga.crtc.overflow & 0x40) << 3;
  975. vdend |= (vga.s3.ex_ver_overflow & 0x2) << 9;
  976. vbstart |= (vga.crtc.maximum_scan_line & 0x20) << 4;
  977. vbstart |= (vga.s3.ex_ver_overflow & 0x4) << 8;
  978. vrstart |= ((vga.crtc.overflow & 0x80) << 2);
  979. vrstart |= (vga.s3.ex_ver_overflow & 0x10) << 6;
  980. vbend = vga.crtc.end_vertical_blanking & 0x7f;
  981. } else { // EGA
  982. vbend = vga.crtc.end_vertical_blanking & 0x1f;
  983. }
  984. htotal += 2;
  985. vtotal += 2;
  986. hdend += 1;
  987. vdend += 1;
  988. vbstart += 1;
  989. hbend = hbstart + ((hbend - hbstart) & 0x3F);
  990. hrend = vga.crtc.end_horizontal_retrace & 0x1f;
  991. hrend = (hrend - hrstart) & 0x1f;
  992. if ( !hrend ) hrend = hrstart + 0x1f + 1;
  993. else hrend = hrstart + hrend;
  994. vrend = vga.crtc.vertical_retrace_end & 0xF;
  995. vrend = ( vrend - vrstart)&0xF;
  996. if ( !vrend) vrend = vrstart + 0xf + 1;
  997. else vrend = vrstart + vrend;
  998. vbend = (vbend - vbstart) & 0x7f;
  999. if ( !vbend) vbend = vbstart + 0x7f + 1;
  1000. else vbend = vbstart + vbend;
  1001. vbend++;
  1002. if (svga.get_clock) {
  1003. clock = svga.get_clock();
  1004. } else {
  1005. switch ((vga.misc_output >> 2) & 3) {
  1006. case 0:
  1007. clock = (machine==MCH_EGA) ? 14318180 : 25175000;
  1008. break;
  1009. case 1:
  1010. default:
  1011. clock = (machine==MCH_EGA) ? 16257000 : 28322000;
  1012. break;
  1013. }
  1014. }
  1015. /* Check for 8 for 9 character clock mode */
  1016. if (vga.seq.clocking_mode & 1 ) clock/=8; else clock/=9;
  1017. /* Check for pixel doubling, master clock/2 */
  1018. if (vga.seq.clocking_mode & 0x8) {
  1019. htotal*=2;
  1020. }
  1021. vga.draw.address_line_total=(vga.crtc.maximum_scan_line&0x1f)+1;
  1022. if(IS_VGA_ARCH && (svgaCard==SVGA_None) && (vga.mode==M_EGA || vga.mode==M_VGA)) {
  1023. // vgaonly; can't use with CGA because these use address_line for their
  1024. // own purposes.
  1025. // Set the low resolution modes to have as many lines as are scanned -
  1026. // Quite a few demos change the max_scanline register at display time
  1027. // to get SFX: Majic12 show, Magic circle, Copper, GBU, Party91
  1028. if( vga.crtc.maximum_scan_line&0x80) vga.draw.address_line_total*=2;
  1029. vga.draw.double_scan=false;
  1030. }
  1031. else if (IS_VGA_ARCH) vga.draw.double_scan=(vga.crtc.maximum_scan_line&0x80)>0;
  1032. else vga.draw.double_scan=(vtotal==262);
  1033. } else {
  1034. htotal = vga.other.htotal + 1;
  1035. hdend = vga.other.hdend;
  1036. hbstart = hdend;
  1037. hbend = htotal;
  1038. hrstart = vga.other.hsyncp;
  1039. hrend = hrstart + vga.other.hsyncw;
  1040. vga.draw.address_line_total = vga.other.max_scanline + 1;
  1041. vtotal = vga.draw.address_line_total * (vga.other.vtotal+1)+vga.other.vadjust;
  1042. vdend = vga.draw.address_line_total * vga.other.vdend;
  1043. vrstart = vga.draw.address_line_total * vga.other.vsyncp;
  1044. vrend = vrstart + 16; // vsync width is fixed to 16 lines on the MC6845 TODO Tandy
  1045. vbstart = vdend;
  1046. vbend = vtotal;
  1047. vga.draw.double_scan=false;
  1048. switch (machine) {
  1049. case MCH_CGA:
  1050. case TANDY_ARCH_CASE:
  1051. clock=((vga.tandy.mode_control & 1) ? 14318180 : (14318180/2))/8;
  1052. break;
  1053. case MCH_HERC:
  1054. if (vga.herc.mode_control & 0x2) clock=16000000/16;
  1055. else clock=16000000/8;
  1056. break;
  1057. default:
  1058. clock = 14318180;
  1059. break;
  1060. }
  1061. vga.draw.delay.hdend = hdend*1000.0/clock; //in milliseconds
  1062. }
  1063. #if C_DEBUG
  1064. LOG(LOG_VGA,LOG_NORMAL)("h total %d end %d blank (%d/%d) retrace (%d/%d)",
  1065. htotal, hdend, hbstart, hbend, hrstart, hrend );
  1066. LOG(LOG_VGA,LOG_NORMAL)("v total %d end %d blank (%d/%d) retrace (%d/%d)",
  1067. vtotal, vdend, vbstart, vbend, vrstart, vrend );
  1068. #endif
  1069. if (!htotal) return;
  1070. if (!vtotal) return;
  1071. // The screen refresh frequency
  1072. fps=(double)clock/(vtotal*htotal);
  1073. // Horizontal total (that's how long a line takes with whistles and bells)
  1074. vga.draw.delay.htotal = htotal*1000.0/clock; //in milliseconds
  1075. // Start and End of horizontal blanking
  1076. vga.draw.delay.hblkstart = hbstart*1000.0/clock; //in milliseconds
  1077. vga.draw.delay.hblkend = hbend*1000.0/clock;
  1078. // Start and End of horizontal retrace
  1079. vga.draw.delay.hrstart = hrstart*1000.0/clock;
  1080. vga.draw.delay.hrend = hrend*1000.0/clock;
  1081. // Start and End of vertical blanking
  1082. vga.draw.delay.vblkstart = vbstart * vga.draw.delay.htotal;
  1083. vga.draw.delay.vblkend = vbend * vga.draw.delay.htotal;
  1084. // Start and End of vertical retrace pulse
  1085. vga.draw.delay.vrstart = vrstart * vga.draw.delay.htotal;
  1086. vga.draw.delay.vrend = vrend * vga.draw.delay.htotal;
  1087. // Vertical blanking tricks
  1088. vblank_skip = 0;
  1089. if (IS_VGA_ARCH) { // others need more investigation
  1090. if (vbend > vtotal) {
  1091. // blanking wraps to the start of the screen
  1092. vblank_skip = vbend&0x7f;
  1093. // on blanking wrap to 0, the first line is not blanked
  1094. // this is used by the S3 BIOS and other S3 drivers in some SVGA modes
  1095. if((vbend&0x7f)==1) vblank_skip = 0;
  1096. // it might also cut some lines off the bottom
  1097. if(vbstart < vdend) {
  1098. vdend = vbstart;
  1099. }
  1100. LOG(LOG_VGA,LOG_WARN)("Blanking wrap to line %d", vblank_skip);
  1101. } else if (vbstart==1) {
  1102. // blanking is used to cut lines at the start of the screen
  1103. vblank_skip = vbend;
  1104. LOG(LOG_VGA,LOG_WARN)("Upper %d lines of the screen blanked", vblank_skip);
  1105. } else if (vbstart < vdend) {
  1106. if(vbend < vdend) {
  1107. // the game wants a black bar somewhere on the screen
  1108. LOG(LOG_VGA,LOG_WARN)("Unsupported blanking: line %d-%d",vbstart,vbend);
  1109. } else {
  1110. // blanking is used to cut off some lines from the bottom
  1111. vdend = vbstart;
  1112. }
  1113. }
  1114. vdend -= vblank_skip;
  1115. }
  1116. // Display end
  1117. vga.draw.delay.vdend = vdend * vga.draw.delay.htotal;
  1118. vga.draw.parts_total=VGA_PARTS;
  1119. /*
  1120. 6 Horizontal Sync Polarity. Negative if set
  1121. 7 Vertical Sync Polarity. Negative if set
  1122. Bit 6-7 indicates the number of lines on the display:
  1123. 1: 400, 2: 350, 3: 480
  1124. */
  1125. //Try to determine the pixel size, aspect correct is based around square pixels
  1126. //Base pixel width around 100 clocks horizontal
  1127. //For 9 pixel text modes this should be changed, but we don't support that anyway :)
  1128. //Seems regular vga only listens to the 9 char pixel mode with character mode enabled
  1129. double pwidth = (machine==MCH_EGA) ? (114.0 / htotal) : (100.0 / htotal);
  1130. //Base pixel height around vertical totals of modes that have 100 clocks horizontal
  1131. //Different sync values gives different scaling of the whole vertical range
  1132. //VGA monitor just seems to thighten or widen the whole vertical range
  1133. double pheight;
  1134. double target_total = (machine==MCH_EGA) ? 262.0 : 449.0;
  1135. Bitu sync = vga.misc_output >> 6;
  1136. switch ( sync ) {
  1137. case 0: // This is not defined in vga specs,
  1138. // Kiet, seems to be slightly less than 350 on my monitor
  1139. //340 line mode, filled with 449 total
  1140. pheight = (480.0 / 340.0) * ( target_total / vtotal );
  1141. break;
  1142. case 1: //400 line mode, filled with 449 total
  1143. pheight = (480.0 / 400.0) * ( target_total / vtotal );
  1144. break;
  1145. case 2: //350 line mode, filled with 449 total
  1146. //This mode seems to get regular 640x400 timing and goes for a loong retrace
  1147. //Depends on the monitor to stretch the screen
  1148. pheight = (480.0 / 350.0) * ( target_total / vtotal );
  1149. break;
  1150. case 3: //480 line mode, filled with 525 total
  1151. default:
  1152. pheight = (480.0 / 480.0) * ( 525.0 / vtotal );
  1153. break;
  1154. }
  1155. double aspect_ratio = pheight / pwidth;
  1156. vga.draw.delay.parts = vga.draw.delay.vdend/vga.draw.parts_total;
  1157. vga.draw.resizing=false;
  1158. vga.draw.vret_triggered=false;
  1159. //Check to prevent useless black areas
  1160. if (hbstart<hdend) hdend=hbstart;
  1161. if ((!IS_VGA_ARCH) && (vbstart<vdend)) vdend=vbstart;
  1162. Bitu width=hdend;
  1163. Bitu height=vdend;
  1164. bool doubleheight=false;
  1165. bool doublewidth=false;
  1166. //Set the bpp
  1167. Bitu bpp;
  1168. switch (vga.mode) {
  1169. case M_LIN15:
  1170. bpp = 15;
  1171. break;
  1172. case M_LIN16:
  1173. bpp = 16;
  1174. break;
  1175. case M_LIN32:
  1176. bpp = 32;
  1177. break;
  1178. default:
  1179. bpp = 8;
  1180. break;
  1181. }
  1182. vga.draw.linear_base = vga.mem.linear;
  1183. vga.draw.linear_mask = vga.vmemwrap - 1;
  1184. switch (vga.mode) {
  1185. case M_VGA:
  1186. doublewidth=true;
  1187. width<<=2;
  1188. if ((IS_VGA_ARCH) && (svgaCard==SVGA_None)) {
  1189. bpp=16;
  1190. VGA_DrawLine = VGA_Draw_Xlat16_Linear_Line;
  1191. } else VGA_DrawLine = VGA_Draw_Linear_Line;
  1192. break;
  1193. case M_LIN8:
  1194. if (vga.crtc.mode_control & 0x8)
  1195. width >>=1;
  1196. else if(svgaCard == SVGA_S3Trio && !(vga.s3.reg_3a&0x10)) {
  1197. doublewidth=true;
  1198. width >>=1;
  1199. }
  1200. // fall-through
  1201. case M_LIN32:
  1202. width<<=3;
  1203. if (vga.crtc.mode_control & 0x8)
  1204. doublewidth = true;
  1205. /* Use HW mouse cursor drawer if enabled */
  1206. VGA_ActivateHardwareCursor();
  1207. break;
  1208. case M_LIN15:
  1209. case M_LIN16:
  1210. // 15/16 bpp modes double the horizontal values
  1211. width<<=2;
  1212. if ((vga.crtc.mode_control & 0x8) || (svgaCard == SVGA_S3Trio && (vga.s3.pll.cmd & 0x10)))
  1213. doublewidth = true;
  1214. /* Use HW mouse cursor drawer if enabled */
  1215. VGA_ActivateHardwareCursor();
  1216. break;
  1217. case M_LIN4:
  1218. doublewidth=(vga.seq.clocking_mode & 0x8) > 0;
  1219. vga.draw.blocks = width;
  1220. width<<=3;
  1221. VGA_DrawLine=VGA_Draw_Linear_Line;
  1222. vga.draw.linear_base = vga.fastmem;
  1223. vga.draw.linear_mask = (vga.vmemwrap<<1) - 1;
  1224. break;
  1225. case M_EGA:
  1226. doublewidth=(vga.seq.clocking_mode & 0x8) > 0;
  1227. vga.draw.blocks = width;
  1228. width<<=3;
  1229. if ((IS_VGA_ARCH) && (svgaCard==SVGA_None)) {
  1230. bpp=16;
  1231. VGA_DrawLine = VGA_Draw_Xlat16_Linear_Line;
  1232. } else VGA_DrawLine=VGA_Draw_Linear_Line;
  1233. vga.draw.linear_base = vga.fastmem;
  1234. vga.draw.linear_mask = (vga.vmemwrap<<1) - 1;
  1235. break;
  1236. case M_CGA16:
  1237. doubleheight=true;
  1238. vga.draw.blocks=width*2;
  1239. width<<=4;
  1240. VGA_DrawLine=VGA_Draw_CGA16_Line;
  1241. break;
  1242. case M_CGA4:
  1243. doublewidth=true;
  1244. vga.draw.blocks=width*2;
  1245. width<<=3;
  1246. VGA_DrawLine=VGA_Draw_2BPP_Line;
  1247. break;
  1248. case M_CGA2:
  1249. doubleheight=true;
  1250. vga.draw.blocks=2*width;
  1251. width<<=3;
  1252. VGA_DrawLine=VGA_Draw_1BPP_Line;
  1253. break;
  1254. case M_TEXT:
  1255. aspect_ratio=1.0;
  1256. vga.draw.blocks=width;
  1257. doublewidth=(vga.seq.clocking_mode & 0x8) > 0;
  1258. if ((IS_VGA_ARCH) && (svgaCard==SVGA_None) && !(vga.seq.clocking_mode&0x01)) {
  1259. width*=9; /* 9 bit wide text font */
  1260. VGA_DrawLine=VGA_TEXT_Xlat16_Draw_Line_9;
  1261. bpp=16;
  1262. // VGA_DrawLine=VGA_TEXT_Draw_Line_9;
  1263. } else {
  1264. width<<=3; /* 8 bit wide text font */
  1265. if ((IS_VGA_ARCH) && (svgaCard==SVGA_None)) {
  1266. VGA_DrawLine=VGA_TEXT_Xlat16_Draw_Line;
  1267. bpp=16;
  1268. } else VGA_DrawLine=VGA_TEXT_Draw_Line;
  1269. }
  1270. break;
  1271. case M_HERC_GFX:
  1272. aspect_ratio=1.5;
  1273. vga.draw.blocks=width*2;
  1274. width*=16;
  1275. VGA_DrawLine=VGA_Draw_1BPP_Line;
  1276. break;
  1277. case M_TANDY2:
  1278. aspect_ratio=1.2;
  1279. doubleheight=true;
  1280. if (machine==MCH_PCJR) doublewidth=(vga.tandy.gfx_control & 0x8)==0x00;
  1281. else doublewidth=(vga.tandy.mode_control & 0x10)==0;
  1282. vga.draw.blocks=width * (doublewidth ? 4:8);
  1283. width=vga.draw.blocks*2;
  1284. VGA_DrawLine=VGA_Draw_1BPP_Line;
  1285. break;
  1286. case M_TANDY4:
  1287. aspect_ratio=1.2;
  1288. doubleheight=true;
  1289. if (machine==MCH_TANDY) doublewidth=(vga.tandy.mode_control & 0x10)==0;
  1290. else doublewidth=(vga.tandy.mode_control & 0x01)==0x00;
  1291. vga.draw.blocks=width * 2;
  1292. width=vga.draw.blocks*4;
  1293. if ((machine==MCH_TANDY && (vga.tandy.gfx_control & 0x8)) ||
  1294. (machine==MCH_PCJR && (vga.tandy.mode_control==0x0b)))
  1295. VGA_DrawLine=VGA_Draw_2BPPHiRes_Line;
  1296. else VGA_DrawLine=VGA_Draw_2BPP_Line;
  1297. break;
  1298. case M_TANDY16:
  1299. aspect_ratio=1.2;
  1300. doubleheight=true;
  1301. vga.draw.blocks=width*2;
  1302. if (vga.tandy.mode_control & 0x1) {
  1303. if (( machine==MCH_TANDY ) && ( vga.tandy.mode_control & 0x10 )) {
  1304. doublewidth = false;
  1305. vga.draw.blocks*=2;
  1306. width=vga.draw.blocks*2;
  1307. } else {
  1308. doublewidth = true;
  1309. width=vga.draw.blocks*2;
  1310. }
  1311. VGA_DrawLine=VGA_Draw_4BPP_Line;
  1312. } else {
  1313. doublewidth=true;
  1314. width=vga.draw.blocks*4;
  1315. VGA_DrawLine=VGA_Draw_4BPP_Line_Double;
  1316. }
  1317. break;
  1318. case M_TANDY_TEXT:
  1319. doublewidth=(vga.tandy.mode_control & 0x1)==0;
  1320. aspect_ratio=1;
  1321. doubleheight=true;
  1322. vga.draw.blocks=width;
  1323. width<<=3;
  1324. VGA_DrawLine=VGA_TEXT_Draw_Line;
  1325. break;
  1326. case M_HERC_TEXT:
  1327. aspect_ratio=1;
  1328. vga.draw.blocks=width;
  1329. width<<=3;
  1330. VGA_DrawLine=VGA_TEXT_Herc_Draw_Line;
  1331. break;
  1332. default:
  1333. LOG(LOG_VGA,LOG_ERROR)("Unhandled VGA mode %d while checking for resolution",vga.mode);
  1334. break;
  1335. }
  1336. VGA_CheckScanLength();
  1337. if (vga.draw.double_scan) {
  1338. if (IS_VGA_ARCH) {
  1339. vga.draw.vblank_skip /= 2;
  1340. height/=2;
  1341. }
  1342. doubleheight=true;
  1343. }
  1344. vga.draw.vblank_skip = vblank_skip;
  1345. if(!(IS_VGA_ARCH && (svgaCard==SVGA_None) && (vga.mode==M_EGA || vga.mode==M_VGA))) {
  1346. //Only check for extra double height in vga modes
  1347. //(line multiplying by address_line_total)
  1348. if (!doubleheight && (vga.mode<M_TEXT) && !(vga.draw.address_line_total & 1)) {
  1349. vga.draw.address_line_total/=2;
  1350. doubleheight=true;
  1351. height/=2;
  1352. }
  1353. }
  1354. vga.draw.lines_total=height;
  1355. vga.draw.parts_lines=vga.draw.lines_total/vga.draw.parts_total;
  1356. vga.draw.line_length = width * ((bpp + 1) / 8);
  1357. #ifdef VGA_KEEP_CHANGES
  1358. vga.changes.active = false;
  1359. vga.changes.frame = 0;
  1360. vga.changes.writeMask = 1;
  1361. #endif
  1362. /*
  1363. Cheap hack to just make all > 640x480 modes have 4:3 aspect ratio
  1364. */
  1365. if ( width >= 640 && height >= 480 ) {
  1366. aspect_ratio = ((float)width / (float)height) * ( 3.0 / 4.0);
  1367. }
  1368. // LOG_MSG("ht %d vt %d ratio %f", htotal, vtotal, aspect_ratio );
  1369. // need to change the vertical timing?
  1370. if (fabs(vga.draw.delay.vtotal - 1000.0 / fps) > 0.0001) {
  1371. vga.draw.delay.vtotal = 1000.0 / fps;
  1372. VGA_KillDrawing();
  1373. PIC_RemoveEvents(VGA_Other_VertInterrupt);
  1374. PIC_RemoveEvents(VGA_VerticalTimer);
  1375. PIC_RemoveEvents(VGA_PanningLatch);
  1376. PIC_RemoveEvents(VGA_DisplayStartLatch);
  1377. VGA_VerticalTimer(0);
  1378. }
  1379. #if C_DEBUG
  1380. LOG(LOG_VGA,LOG_NORMAL)("h total %2.5f (%3.2fkHz) blank(%02.5f/%02.5f) retrace(%02.5f/%02.5f)",
  1381. vga.draw.delay.htotal,(1.0/vga.draw.delay.htotal),
  1382. vga.draw.delay.hblkstart,vga.draw.delay.hblkend,
  1383. vga.draw.delay.hrstart,vga.draw.delay.hrend);
  1384. LOG(LOG_VGA,LOG_NORMAL)("v total %2.5f (%3.2fHz) blank(%02.5f/%02.5f) retrace(%02.5f/%02.5f)",
  1385. vga.draw.delay.vtotal,(1000.0/vga.draw.delay.vtotal),
  1386. vga.draw.delay.vblkstart,vga.draw.delay.vblkend,
  1387. vga.draw.delay.vrstart,vga.draw.delay.vrend);
  1388. #endif
  1389. // need to resize the output window?
  1390. if ((width != vga.draw.width) ||
  1391. (height != vga.draw.height) ||
  1392. (vga.draw.doublewidth != doublewidth) ||
  1393. (vga.draw.doubleheight != doubleheight) ||
  1394. (fabs(aspect_ratio - vga.draw.aspect_ratio) > 0.0001) ||
  1395. (vga.draw.bpp != bpp)) {
  1396. VGA_KillDrawing();
  1397. vga.draw.width = width;
  1398. vga.draw.height = height;
  1399. vga.draw.doublewidth = doublewidth;
  1400. vga.draw.doubleheight = doubleheight;
  1401. vga.draw.aspect_ratio = aspect_ratio;
  1402. vga.draw.bpp = bpp;
  1403. if (doubleheight) vga.draw.lines_scaled=2;
  1404. else vga.draw.lines_scaled=1;
  1405. #if C_DEBUG
  1406. LOG(LOG_VGA,LOG_NORMAL)("Width %d, Height %d, fps %f",width,height,fps);
  1407. LOG(LOG_VGA,LOG_NORMAL)("%s width, %s height aspect %f",
  1408. doublewidth ? "double":"normal",doubleheight ? "double":"normal",aspect_ratio);
  1409. #endif
  1410. RENDER_SetSize(width,height,bpp,(float)fps,aspect_ratio,doublewidth,doubleheight);
  1411. }
  1412. }
  1413. void VGA_KillDrawing(void) {
  1414. PIC_RemoveEvents(VGA_DrawPart);
  1415. PIC_RemoveEvents(VGA_DrawSingleLine);
  1416. vga.draw.parts_left = 0;
  1417. vga

Large files files are truncated, but you can click here to view the full file