Вывод BMP в видеорежимах VESA

Вывод BMP в видеорежимах VESA

Вывод BMP в видеорежимах VESA

Очень часто в форумах всплывают такие вопросы, как вывод на экран BMP и работа с видеорежимами VESA. Этот пример ответит на оба вопроса.

Программа писалась в студенческие годы, в качестве лабораторной работы. Студенты должны были получить спецификации и писать модули для поддержки файлов разных графических форматов, но были выставлены автоматы, и все замялось.

Все закончилось на том, что включался видеорежим, были написаны кое-какие функции для него (blt(), putpixel() и line())

Скачать в архиве

bmp.cpp

  1. #include "vesa.h";
  2. #include <math.h>;
  3. #include "bmp.h";
  4.  
  5. void BMP_PutFromFile(TMode m, int x, int y, char * fname) {
  6. FILE* fp;
  7. struct BMPHeader bmp;
  8. TPallete pal[256]; // Палитра
  9. char paloffset; // Смещение в палитре;
  10.  
  11. if (x>m.w || y>m.h) return; // Если не влезает в экран.
  12.  
  13. fp=fopen(fname,"rb");
  14. fread(&bmp,54,1,fp);
  15.  
  16. if (bmp.ID==0x4D42) { // Проверим ID
  17.  
  18. int rw=m.w-x-1; if (rw>bmp.Width) rw=bmp.Width; // Требуемая ширина
  19. int rh=m.h-y-1; if (rh>bmp.Height) rh=bmp.Height; // Требуемая высота
  20. int bpl=bmp.ISize/bmp.Height; // Байт на строку у BMP
  21.  
  22. ul pnt=(ul)m.VLFB;
  23. pnt=pnt+(y+rh)*m.bpl+x*m.bytespp; // Установим указатель на нижнюю строку картинки
  24.  
  25. // 24 бита не пакованая ##############################################
  26. if (bmp.Bits==24 && bmp.Comp==0) {
  27. if (bmp.Height-rh!=0) fseek(fp, (bmp.Height-rh)*bpl ,SEEK_CUR);
  28.  
  29. int fseeksize=bpl-rw*3; // Пропускаемая часть в файле
  30. int pntmove=m.bpl+rw*4; // Смещене указателя на экране
  31. for (int i=0;i<rh;i++) {
  32. for (int j=0;j<rw;j++) {
  33. fread((void *)pnt, 3, 1, fp);
  34. pnt+=4;
  35. }
  36. fseek(fp, fseeksize, SEEK_CUR);
  37. pnt-=pntmove;
  38. }
  39. }
  40. // 8 бит не пакованая ################################################
  41. if (bmp.Bits==8 && bmp.Comp==0) {
  42. if (bpl==0) bpl=bmp.Width;
  43. fread(&pal,1024,1,fp); // Читаем палитру
  44.  
  45. if (bmp.Height-rh!=0) fseek(fp, (bmp.Height-rh)*bpl ,SEEK_CUR);
  46.  
  47. int fseeksize=bpl-rw; // Пропускаемая часть в файле
  48. int pntmove=m.bpl+rw*4; // Смещене указателя на экране
  49. char * pnto;
  50. for (int i=0;i<rh;i++) {
  51. for (int j=0;j<rw;j++) {
  52. fread(&paloffset, 1, 1, fp);
  53. pnto=(char *)pnt;
  54. pnto[2]=pal[paloffset].r;
  55. pnto[1]=pal[paloffset].g;
  56. pnto[0]=pal[paloffset].b;
  57. pnt+=4;
  58. }
  59. fseek(fp, fseeksize, SEEK_CUR);
  60. pnt-=pntmove;
  61. }
  62. } // end of 8 bit
  63. }
  64. fclose(fp);
  65. }

Download this code: bmp.cpp

glib2000.cpp

  1. #include <conio.h>;
  2. #include "vesa.h";
  3. #include "bmp.h";
  4.  
  5. char VScreen[1024*768*4];
  6.  
  7.  
  8. void DrawHistogram(char * scr, int size, char *s) {
  9. int R[256];
  10. int G[256];
  11. int B[256];
  12. int i,val;
  13. char value;
  14.  
  15. memset (&R, 0, sizeof(R));
  16. memset (&G, 0, sizeof(G));
  17. memset (&B, 0, sizeof(B));
  18. for (i=0;i<size;i=i+4) { // Рассчитываются гистограммы
  19. value=scr[i]; R[value]=R[value]+1;//s[i]=255-value;
  20. value=scr[i+1]; G[value]=G[value]+1;//s[i+1]=255-value;
  21. value=scr[i+2]; B[value]=B[value]+1;//s[i+2]=255-value;
  22. }
  23.  
  24. int sumR=0;for (i=0;i<255;i++) sumR=sumR+R[i];
  25. int maxR=sumR>>6;
  26. int sumG=0;for (i=0;i<255;i++) sumG=sumG+G[i];
  27. int maxG=sumG>>6;
  28. int sumB=0;for (i=0;i<255;i++) sumB=sumB+B[i];
  29. int maxB=sumB>>6;
  30.  
  31. int maxM=(maxR+maxG+maxB)/3;
  32. maxR=maxM;
  33. maxG=maxM;
  34. maxB=maxM;
  35.  
  36.  
  37. // Вывод гистограммы для R
  38. Line(9,151,9,10,0xFFFFFF);Line(9,151,522,151,0xFFFFFF);
  39. for (i=0;i<256;i++) {
  40. val=(R[i]*140)/maxR;if (val>140) val=140;
  41. Line(10+(i<<1),150,10+(i<<1),150-val,i<<16);
  42. Line(11+(i<<1),150,11+(i<<1),150-val+1,0xC0C0C0);
  43. }
  44.  
  45. Line(9,301,9,160,0xFFFFFF);Line(9,301,522,301,0xFFFFFF);
  46. for (i=0;i<256;i++) {
  47. val=(G[i]*140)/maxG;if (val>140) val=140;
  48. Line(10+(i<<1),300,10+(i<<1),300-val,i<<8);
  49. Line(11+(i<<1),300,11+(i<<1),300-val+1,0xC0C0C0);
  50. }
  51.  
  52. Line(9,451,9,310,0xFFFFFF);Line(9,451,522,451,0xFFFFFF);
  53. for (i=0;i<256;i++) {
  54. val=(B[i]*140)/maxB;if (val>140) val=140;
  55. Line(10+(i<<1),450,10+(i<<1),450-val,i);
  56. Line(11+(i<<1),450,11+(i<<1),450-val+1,0xC0C0C0);
  57. }
  58. }
  59.  
  60. void main(void) {
  61. cm=SetVESAMode(640,480,32); // Включение видеорежима.
  62. cm.VLFB=(uc *)VScreen; // Установка виртуального экрана.
  63. InitGraph();
  64.  
  65. BMP_PutFromFile(cm,0,0,"29sc091.bmp");
  66.  
  67. DrawHistogram((char *)cm.VLFB, cm.w*cm.h*cm.bytespp, (char *)cm.LFB);
  68. blt(cm);
  69.  
  70. getch();
  71. SetVGAMode(3);
  72. }

Download this code: glib2000.cpp

vesa.cpp

  1. #include "vesa.h";
  2. #include <conio.h>;
  3.  
  4. VBE_InfoBlock far * vinfo;
  5. VBE_ModeInfoBlock far * minfo;
  6.  
  7. int *scr;
  8. int dwpl;
  9.  
  10. // Возвращает версию VESA ####################################################
  11. int GetVBEVersion(void) {
  12. union REGS r;
  13. us seg,sel;
  14. static VBE_RMI RMI;
  15. struct SREGS sr;
  16. ul ver;
  17.  
  18. memset (&cm, 0, sizeof(cm));
  19. r.x.eax=0x0100;
  20. r.x.ebx=600>>4;
  21. int386(0x31,&r,&r);
  22. if (r.x.cflag) {
  23. puts (" ¦ DOS memory alocate error.");
  24. return(0);
  25. }
  26. seg = r.w.ax; // RM segment
  27. sel = r.w.dx; // PM selector
  28. vinfo = (VBE_InfoBlock far *) MK_FP (sel, 0);
  29. memset (&sr, 0, sizeof (sr));
  30. memset (&RMI, 0, sizeof (RMI));
  31. RMI.EAX = 0x00004f00; // Get VBE Info
  32. RMI.ES = seg;
  33. RMI.EDI = 0;
  34. r.w.ax = 0x0300;
  35. r.h.bl = 0x10;
  36. r.h.bh = 0;
  37. r.w.cx = 0;
  38. sr.es = FP_SEG (&RMI);
  39. r.x.edi = FP_OFF (&RMI);
  40. int386x (0x31, &r, &r, &sr);
  41. if (r.x.cflag) {
  42. puts (" ¦ DPMI 300h failed.");
  43. return(0);
  44. }
  45. if ((us) RMI.EAX != 0x004f) {
  46. puts (" ¦ Error Getting Video Controller Info.");
  47. return(0);
  48. }
  49. return(vinfo -> VbeVersion);
  50. }
  51.  
  52. void PutVBEVersion(void) {
  53. int ver=GetVBEVersion();
  54. printf("%d.%d",(ver & 0xFF00)>>8 ,ver & 0x00FF);
  55. }
  56.  
  57. // Включение VESA видео-режима ###########################
  58. // 0 - Ok
  59. // 1 - DPMI 300h failed
  60. // 2 - Error Getting Video Controller Info
  61. // 3 - DOS memory alocate error
  62. // 4 - Video mode no found
  63. // 5 - Error mapping physical to linear
  64. // 6 - Error Init Mode
  65. TMode SetVESAMode(int xmax, int ymax, int bpp) {
  66. static VBE_RMI RMI;
  67. union REGS r;
  68. struct SREGS sr;
  69. us sel,seg,x,y,ic;
  70. ul phys;
  71. int mmode;
  72. TMode cm;
  73.  
  74. r.x.eax=0x0100;
  75. r.x.ebx=600>>4;
  76. int386(0x31,&r,&r);
  77. if (r.x.cflag) {
  78. cm.error=1;
  79. return(cm);
  80. }
  81. seg = r.w.ax; // RM segment
  82. sel = r.w.dx; // PM selector
  83. vinfo = (VBE_InfoBlock far *) MK_FP (sel, 0);
  84. memset (&sr, 0, sizeof (sr));
  85. memset (&RMI, 0, sizeof (RMI));
  86. RMI.EAX = 0x00004f00; // Get VBE Info
  87. RMI.ES = seg;
  88. RMI.EDI = 0;
  89. r.w.ax = 0x0300;
  90. r.h.bl = 0x10;
  91. r.h.bh = 0;
  92. r.w.cx = 0;
  93. sr.es = FP_SEG (&RMI);
  94. r.x.edi = FP_OFF (&RMI);
  95. int386x (0x31, &r, &r, &sr);
  96. if (r.x.cflag) {
  97. cm.error=1;
  98. return(cm);
  99. }
  100. if ((us) RMI.EAX != 0x004f) {
  101. cm.error=2;
  102. return(cm);
  103. }
  104. r.x.eax = 0x0100;
  105. r.x.ebx = 300 >> 4;
  106. int386 (0x31, &r, &r);
  107. if (r.x.cflag) {
  108. cm.error=3;
  109. return(cm);
  110. }
  111. seg = r.w.ax; // RM segment
  112. sel = r.w.dx; // PM selector
  113. minfo = (VBE_ModeInfoBlock far *) MK_FP (sel, 0);
  114. memset (&sr, 0, sizeof (sr));
  115. memset (&RMI, 0, sizeof (RMI));
  116. mmode=0;
  117. if (vinfo -> VbeVersion >= 0x0200) {
  118. for (ic=0x4100;ic<0x4200;ic++) {
  119. RMI.EAX = 0x00004f01; // Get VBE Mode Info
  120. RMI.ECX = ic;
  121. RMI.ES = seg;
  122. RMI.EDI = 0;
  123. r.w.ax = 0x0300;
  124. r.h.bl = 0x10;
  125. r.h.bh = 0;
  126. r.w.cx = 0;
  127. sr.es = FP_SEG (&RMI);
  128. r.x.edi = FP_OFF (&RMI);
  129. int386x (0x31, &r, &r, &sr);
  130. if (r.x.cflag) {
  131. cm.error=1;
  132. return(cm);
  133. }
  134. if ((minfo->BitsPerPixel==bpp) &&
  135. (minfo->XResolution==xmax) &&
  136. (minfo->YResolution==ymax) &&
  137. ((us)RMI.EAX==0x004f)) {
  138. if (mmode==0) {mmode=ic;}
  139. }
  140. }
  141. if (mmode!=0) cm.banked=1; else cm.banked=0;
  142. }
  143. if (mmode==0) {
  144. for (ic=0x0100;ic<0x0200;ic++) {
  145. RMI.EAX = 0x00004f01; // Get VBE Mode Info
  146. RMI.ECX = ic;
  147. RMI.ES = seg;
  148. RMI.EDI = 0;
  149. r.w.ax = 0x0300;
  150. r.h.bl = 0x10;
  151. r.h.bh = 0;
  152. r.w.cx = 0;
  153. sr.es = FP_SEG (&RMI);
  154. r.x.edi = FP_OFF (&RMI);
  155. int386x (0x31, &r, &r, &sr);
  156. if (r.x.cflag) {
  157. cm.error=1;
  158. return(cm);
  159. }
  160. if ((minfo->BitsPerPixel==bpp)&&
  161. (minfo->XResolution==xmax)&&
  162. (minfo->YResolution==ymax)&&
  163. ((us)RMI.EAX==0x004f)) {
  164. if (mmode==0) {mmode=ic;}
  165. }
  166. }
  167. }
  168. if (mmode==0) {
  169. cm.error=4;
  170. return(cm);
  171. }
  172. RMI.EAX = 0x00004f01; // Get VBE Mode Info
  173. RMI.ECX = mmode;
  174. RMI.ES = seg;
  175. RMI.EDI = 0;
  176. r.w.ax = 0x0300;
  177. r.h.bl = 0x10;
  178. r.h.bh = 0;
  179. r.w.cx = 0;
  180. sr.es = FP_SEG (&RMI);
  181. r.x.edi = FP_OFF (&RMI);
  182. int386x (0x31, &r, &r, &sr);
  183. phys=minfo->PhysBasePtr;
  184. cm.bpp=minfo->BitsPerPixel;
  185. cm.bytespp=cm.bpp/8;
  186. cm.h=minfo->YResolution;
  187. cm.w=minfo->XResolution;
  188. cm.bpl=minfo->BytesPerScanLine;
  189. r.w.ax = 0x0800;
  190. r.w.bx = (phys >> 0x10);
  191. r.w.cx = (phys & 0xffff);
  192. r.w.si = (long)((minfo->YResolution * minfo->BytesPerScanLine)>>16);
  193. r.w.di = minfo->YResolution * minfo->BytesPerScanLine;
  194. int386 (0x31, &r, &r);
  195. if (r.x.cflag) {
  196. cm.error=5;
  197. return(cm);
  198. }
  199. cm.LFB = (uc near *) (((ul) r.w.bx << 16) | r.w.cx);
  200. r.w.ax = 0x4f02;
  201. r.w.bx = mmode;
  202. int386 (0x10, &r, &r);
  203. if (r.w.ax != 0x004f) {
  204. cm.error=6;
  205. return(cm);
  206. }
  207. cm.error=0;
  208. return(cm);
  209. }
  210.  
  211. // Установка VGA режима ######################################################
  212. void SetVGAMode(int mode) {
  213. static VBE_RMI RMI;
  214. union REGS r;
  215. struct SREGS sr;
  216.  
  217. memset (&sr, 0, sizeof (sr));
  218. memset (&RMI, 0, sizeof (RMI));
  219. memset (&r, 0, sizeof (r));
  220. RMI.EAX = mode; // Get VBE Mode Info
  221. r.w.ax = 0x0300;
  222. r.h.bl = 0x10;
  223. r.h.bh = 0;
  224. r.w.cx = 0;
  225. sr.es = FP_SEG (&RMI);
  226. r.x.edi = FP_OFF (&RMI);
  227. int386x (0x31, &r, &r, &sr);
  228. }
  229.  
  230. void blt(TMode m) {
  231. if (m.bpp==32 && m.banked==1) { // Если включен 32 битный LFB режим
  232. memcpy((void *)m.LFB, (void *)m.VLFB, m.w * m.h * m.bytespp);
  233. }
  234. }
  235.  
  236. void InitGraph(void) {
  237. dwpl=cm.bpl>>2;
  238. scr=(int *)cm.VLFB;
  239. }
  240.  
  241. void PutPixel(int x,int y,int color) {
  242. scr[y*dwpl+x]=color;
  243. }
  244.  
  245. int sgn(int i) {
  246. if (i==0) return(0);
  247. if (i>0) return(1);
  248. return(-1);
  249. }
  250.  
  251. void Line(int x1,int y1,int x2,int y2,int color) {
  252. int dx,dy,r,dr1,dr2,x,y,sx,sy;
  253.  
  254. dx=abs(x2-x1);
  255. dy=abs(y2-y1);
  256. sx=sgn(x2-x1);
  257. sy=sgn(y2-y1);
  258. if (dx>dy) {
  259.  
  260. r=dx;
  261. dr1=-dy<<1;
  262. dr2=(dx-dy)<<1;
  263. y=y1;
  264. x=x1;
  265. x2=x2+sx;
  266. do {
  267. PutPixel(x,y,color);
  268. if (r>0) r=r+dr1;
  269. else {
  270. r=r+dr2;
  271. y=y+sy;
  272. PutPixel(x,y,color);
  273. }
  274. x=x+sx;
  275. } while (x!=x2);
  276. }
  277. else {
  278. r=dy;
  279. dr1=-dx<<1;
  280. dr2=(dy-dx)<<1;
  281. y=y1;
  282. x=x1;
  283. y2=y2+sy;
  284. do {
  285. PutPixel(x,y,color);
  286. if (r>0) r=r+dr1;
  287. else {
  288. r=r+dr2;
  289. x=x+sx;
  290. PutPixel(x,y,color);
  291. }
  292. y=y+sy;
  293. } while (y!=y2);
  294. }
  295. }

Download this code: vesa.cpp

bmp.h

  1. struct BMPHeader
  2. {
  3. unsigned short ID; // 'BM' for a Windows BitMaP
  4. unsigned int FSize; // Size of file
  5. unsigned short Res1; // Not used
  6. unsigned short Res2; // Not used
  7. unsigned int Image; // Offset of image into file
  8.  
  9. unsigned int stSize; // число байт, занимаемых структурой BITMAPINFOHEADER
  10. unsigned int Width; // Width of image
  11. unsigned int Height; // Height of image
  12. unsigned short Num; // число битовых плоскостей устройства
  13. unsigned short Bits; // Number of bits per pixel
  14. unsigned int Comp; // Type of compression, 0 for uncompressed, 1,2 for RLE
  15. unsigned int ISize; // Size of image in bytes
  16. unsigned int XRes; // X dots per metre (not inches! for US, unbelievable!)
  17. unsigned int YRes; // Y dots per metre
  18. unsigned int PSize; // Palette size (number of colours) if not zero
  19. unsigned int PImportant; // Probably reserved, currently 0
  20. };
  21.  
  22. typedef struct SPallete { // Тип описывающий элемент палитры.
  23. char b,g,r,x;
  24. } TPallete;
  25.  
  26. void BMP_PutFromFile(TMode cm, int x, int y, char * fname);

Download this code: bmp.h

bmp.cpp

vesa.h

  1. #include <string.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <dos.h>
  5.  
  6. typedef unsigned short us;
  7. typedef unsigned int ui;
  8. typedef unsigned char uc;
  9. typedef unsigned long ul;
  10.  
  11. typedef struct SVBE_InfoBlock {
  12. uc VbeSignature[4]; // VBE Signature
  13. us VbeVersion; // VBE Version
  14. ul OemStringPtr; // Pointer to OEM String
  15. ul Capabilities; // Capabilities of graphics cont.
  16. ul VideoModePtr; // Pointer to Video Mode List
  17. // Added for VBE 1.2+
  18. us TotalMemory; // Number of 64kb memory blocks
  19. // Added for VBE 2.0+
  20. us OemSoftwareRev; // VBE implementation Software revision
  21. ul OemVendorNamePtr; // Pointer to Vendor Name String
  22. ul OemProductNamePtr; // Pointer to Product Name String
  23. ul OemProductRevPtr; // Pointer to Product Revision String
  24. us AccelVbeVersion; // VBE/AF Version
  25. ul AccelVideoModePtr; // Pointer to Acclelerated Mode List
  26. uc Reserved20[216]; // Reserved for VBE implementation
  27. // scratch area
  28. uc OemData[256]; // Data Area for OEM Strings
  29. uc NaVsyakiySloochay[100]; // 2e
  30. } VBE_InfoBlock;
  31.  
  32. typedef struct SVBE_ModeInfoBlock {
  33. us ModeAttributes; // mode attributes
  34. uc WinAAttributes; // window A attributes
  35. uc WinBAttributes; // window B attributes
  36. us WinGranularity; // window granularity
  37. us WinSize; // window size
  38. us WinASegment; // window A start segment
  39. us WinBSegment; // window B start segment
  40. ul WinFuncPtr; // pointer to window function
  41. us BytesPerScanLine; // bytes per scan line
  42. // Mandatory information for VBE 1.2 and above
  43. us XResolution; // horizontal resolution in pixels or chars
  44. us YResolution; // vertical resolution in pixels or chars
  45. uc XCharSize; // character cell width in pixels
  46. uc YCharSize; // character cell height in pixels
  47. uc NumberOfPlanes; // number of memory planes
  48. uc BitsPerPixel; // bits per pixel
  49. uc NumberOfBanks; // number of banks
  50. uc MemoryModel; // memory model type
  51. uc BankSize; // bank size in KB
  52. uc NumberOfImagePages; // number of images
  53. uc Reserved12; // reserved for page function
  54. // Direct Color fields (required
  55. // for direct/6 and YUV/7 memory models)
  56. uc RedMaskSize; // size of direct color red mask in bits
  57. uc RedFieldPosition; // bit position of lsb of red mask
  58. uc GreenMaskSize; // size of direct color green mask in bits
  59. uc GreenFieldPosition; // bit position of lsb of green mask
  60. uc BlueMaskSize; // size of direct color blue mask in bits
  61. uc BlueFieldPosition; // bit position of lsb of blue mask
  62. uc RsvdMaskSize; // size of direct color reserved mask in bits
  63. uc RsvdFieldPosition; // bit position of lsb of reserved mask
  64. uc DirectColorModeInfo; // direct color mode attributes
  65. // Mandatory information for VBE 2.0 and above
  66. ul PhysBasePtr; // physical address for flat frame buffer
  67. ul OffScreenMemOffset; // pointer to start of off screen memory
  68. us OffScreenMemSize; // amount of off screen memory in 1k units
  69. uc Reserved20[206]; // remainder of ModeInfoBlock
  70. uc NaVsyakiySloochay[100]; // 2e
  71. } VBE_ModeInfoBlock;
  72.  
  73. typedef struct SVBE_RMI { // Rreal Mode Interrupt (RMI) structure
  74. ul EDI, ESI, EBP, ReservedByRMI,
  75. EBX, EDX, ECX, EAX;
  76. us flags,
  77. ES, DS,
  78. FS, GS,
  79. IP, CS,
  80. SP, SS;
  81. } VBE_RMI;
  82.  
  83. typedef struct SMode { // Тип описывающий видео-режим.
  84. ul bpl; // Байт на строку растра.
  85. ul w; // Ширина
  86. ul h; // Высота
  87. ul bpp; // Бит на точку
  88. ul bytespp; // Байт на точку
  89. ul banked; // (1)LFB or (0)Banked
  90. ul error; // Ошибка (обязательно надо проверять)
  91. uc* LFB; // Указатель на LFB
  92. uc* VLFB; // Указатель на Виртуальный экран
  93. } TMode;
  94.  
  95. TMode cm; // Текущий видеорежим.
  96.  
  97. int GetVBEVersion(void);
  98. void PutVBEVersion(void);
  99. TMode SetVESAMode(int xmax, int ymax, int bpp);
  100. void SetVGAMode(int mode);
  101. void InitGraph(void);
  102. void blt(TMode m);
  103. void PutPixel(int x,int y,int color);
  104. void Line(int x1,int y1,int x2,int y2,int color);

Download this code: vesa.h

Комментарии