Вывод BMP в видеорежимах VESA
Комментариев:
Очень часто в форумах всплывают такие вопросы, как вывод на экран BMP и работа с видеорежимами VESA. Этот пример ответит на оба вопроса.
Программа писалась в студенческие годы, в качестве лабораторной работы. Студенты должны были получить спецификации и писать модули для поддержки файлов разных графических форматов, но были выставлены автоматы, и все замялось.
Все закончилось на том, что включался видеорежим, были написаны кое-какие функции для него (blt(), putpixel() и line())
bmp.cpp
#include "vesa.h";#include <math.h>;#include "bmp.h";void BMP_PutFromFile(TMode m, int x, int y, char * fname) {FILE* fp;struct BMPHeader bmp;TPallete pal[256]; // Палитраchar paloffset; // Смещение в палитре;if (x>m.w || y>m.h) return; // Если не влезает в экран.fp=fopen(fname,"rb");fread(&bmp,54,1,fp);if (bmp.ID==0x4D42) { // Проверим IDint rw=m.w-x-1; if (rw>bmp.Width) rw=bmp.Width; // Требуемая ширинаint rh=m.h-y-1; if (rh>bmp.Height) rh=bmp.Height; // Требуемая высотаint bpl=bmp.ISize/bmp.Height; // Байт на строку у BMPul pnt=(ul)m.VLFB;pnt=pnt+(y+rh)*m.bpl+x*m.bytespp; // Установим указатель на нижнюю строку картинки// 24 бита не пакованая ##############################################if (bmp.Bits==24 && bmp.Comp==0) {if (bmp.Height-rh!=0) fseek(fp, (bmp.Height-rh)*bpl ,SEEK_CUR);int fseeksize=bpl-rw*3; // Пропускаемая часть в файлеint pntmove=m.bpl+rw*4; // Смещене указателя на экранеfor (int i=0;i<rh;i++) {for (int j=0;j<rw;j++) {fread((void *)pnt, 3, 1, fp);pnt+=4;}fseek(fp, fseeksize, SEEK_CUR);pnt-=pntmove;}}// 8 бит не пакованая ################################################if (bmp.Bits==8 && bmp.Comp==0) {if (bpl==0) bpl=bmp.Width;fread(&pal,1024,1,fp); // Читаем палитруif (bmp.Height-rh!=0) fseek(fp, (bmp.Height-rh)*bpl ,SEEK_CUR);int fseeksize=bpl-rw; // Пропускаемая часть в файлеint pntmove=m.bpl+rw*4; // Смещене указателя на экранеchar * pnto;for (int i=0;i<rh;i++) {for (int j=0;j<rw;j++) {fread(&paloffset, 1, 1, fp);pnto=(char *)pnt;pnto[2]=pal[paloffset].r;pnto[1]=pal[paloffset].g;pnto[0]=pal[paloffset].b;pnt+=4;}fseek(fp, fseeksize, SEEK_CUR);pnt-=pntmove;}} // end of 8 bit}fclose(fp);}
Download this code: bmp.cpp
glib2000.cpp
#include <conio.h>;#include "vesa.h";#include "bmp.h";char VScreen[1024*768*4];void DrawHistogram(char * scr, int size, char *s) {int R[256];int G[256];int B[256];int i,val;char value;memset (&R, 0, sizeof(R));memset (&G, 0, sizeof(G));memset (&B, 0, sizeof(B));for (i=0;i<size;i=i+4) { // Рассчитываются гистограммыvalue=scr[i]; R[value]=R[value]+1;//s[i]=255-value;value=scr[i+1]; G[value]=G[value]+1;//s[i+1]=255-value;value=scr[i+2]; B[value]=B[value]+1;//s[i+2]=255-value;}int sumR=0;for (i=0;i<255;i++) sumR=sumR+R[i];int maxR=sumR>>6;int sumG=0;for (i=0;i<255;i++) sumG=sumG+G[i];int maxG=sumG>>6;int sumB=0;for (i=0;i<255;i++) sumB=sumB+B[i];int maxB=sumB>>6;int maxM=(maxR+maxG+maxB)/3;maxR=maxM;maxG=maxM;maxB=maxM;// Вывод гистограммы для RLine(9,151,9,10,0xFFFFFF);Line(9,151,522,151,0xFFFFFF);for (i=0;i<256;i++) {val=(R[i]*140)/maxR;if (val>140) val=140;Line(10+(i<<1),150,10+(i<<1),150-val,i<<16);Line(11+(i<<1),150,11+(i<<1),150-val+1,0xC0C0C0);}Line(9,301,9,160,0xFFFFFF);Line(9,301,522,301,0xFFFFFF);for (i=0;i<256;i++) {val=(G[i]*140)/maxG;if (val>140) val=140;Line(10+(i<<1),300,10+(i<<1),300-val,i<<8);Line(11+(i<<1),300,11+(i<<1),300-val+1,0xC0C0C0);}Line(9,451,9,310,0xFFFFFF);Line(9,451,522,451,0xFFFFFF);for (i=0;i<256;i++) {val=(B[i]*140)/maxB;if (val>140) val=140;Line(10+(i<<1),450,10+(i<<1),450-val,i);Line(11+(i<<1),450,11+(i<<1),450-val+1,0xC0C0C0);}}void main(void) {cm=SetVESAMode(640,480,32); // Включение видеорежима.cm.VLFB=(uc *)VScreen; // Установка виртуального экрана.InitGraph();BMP_PutFromFile(cm,0,0,"29sc091.bmp");DrawHistogram((char *)cm.VLFB, cm.w*cm.h*cm.bytespp, (char *)cm.LFB);blt(cm);getch();SetVGAMode(3);}
Download this code: glib2000.cpp
vesa.cpp
#include "vesa.h";#include <conio.h>;VBE_InfoBlock far * vinfo;VBE_ModeInfoBlock far * minfo;int *scr;int dwpl;// Возвращает версию VESA ####################################################int GetVBEVersion(void) {union REGS r;us seg,sel;static VBE_RMI RMI;struct SREGS sr;ul ver;memset (&cm, 0, sizeof(cm));r.x.eax=0x0100;r.x.ebx=600>>4;int386(0x31,&r,&r);if (r.x.cflag) {puts (" ¦ DOS memory alocate error.");return(0);}seg = r.w.ax; // RM segmentsel = r.w.dx; // PM selectorvinfo = (VBE_InfoBlock far *) MK_FP (sel, 0);memset (&sr, 0, sizeof (sr));memset (&RMI, 0, sizeof (RMI));RMI.EAX = 0x00004f00; // Get VBE InfoRMI.ES = seg;RMI.EDI = 0;r.w.ax = 0x0300;r.h.bl = 0x10;r.h.bh = 0;r.w.cx = 0;sr.es = FP_SEG (&RMI);r.x.edi = FP_OFF (&RMI);int386x (0x31, &r, &r, &sr);if (r.x.cflag) {puts (" ¦ DPMI 300h failed.");return(0);}if ((us) RMI.EAX != 0x004f) {puts (" ¦ Error Getting Video Controller Info.");return(0);}return(vinfo -> VbeVersion);}void PutVBEVersion(void) {int ver=GetVBEVersion();printf("%d.%d",(ver & 0xFF00)>>8 ,ver & 0x00FF);}// Включение VESA видео-режима ###########################// 0 - Ok// 1 - DPMI 300h failed// 2 - Error Getting Video Controller Info// 3 - DOS memory alocate error// 4 - Video mode no found// 5 - Error mapping physical to linear// 6 - Error Init ModeTMode SetVESAMode(int xmax, int ymax, int bpp) {static VBE_RMI RMI;union REGS r;struct SREGS sr;us sel,seg,x,y,ic;ul phys;int mmode;TMode cm;r.x.eax=0x0100;r.x.ebx=600>>4;int386(0x31,&r,&r);if (r.x.cflag) {cm.error=1;return(cm);}seg = r.w.ax; // RM segmentsel = r.w.dx; // PM selectorvinfo = (VBE_InfoBlock far *) MK_FP (sel, 0);memset (&sr, 0, sizeof (sr));memset (&RMI, 0, sizeof (RMI));RMI.EAX = 0x00004f00; // Get VBE InfoRMI.ES = seg;RMI.EDI = 0;r.w.ax = 0x0300;r.h.bl = 0x10;r.h.bh = 0;r.w.cx = 0;sr.es = FP_SEG (&RMI);r.x.edi = FP_OFF (&RMI);int386x (0x31, &r, &r, &sr);if (r.x.cflag) {cm.error=1;return(cm);}if ((us) RMI.EAX != 0x004f) {cm.error=2;return(cm);}r.x.eax = 0x0100;r.x.ebx = 300 >> 4;int386 (0x31, &r, &r);if (r.x.cflag) {cm.error=3;return(cm);}seg = r.w.ax; // RM segmentsel = r.w.dx; // PM selectorminfo = (VBE_ModeInfoBlock far *) MK_FP (sel, 0);memset (&sr, 0, sizeof (sr));memset (&RMI, 0, sizeof (RMI));mmode=0;if (vinfo -> VbeVersion >= 0x0200) {for (ic=0x4100;ic<0x4200;ic++) {RMI.EAX = 0x00004f01; // Get VBE Mode InfoRMI.ECX = ic;RMI.ES = seg;RMI.EDI = 0;r.w.ax = 0x0300;r.h.bl = 0x10;r.h.bh = 0;r.w.cx = 0;sr.es = FP_SEG (&RMI);r.x.edi = FP_OFF (&RMI);int386x (0x31, &r, &r, &sr);if (r.x.cflag) {cm.error=1;return(cm);}if ((minfo->BitsPerPixel==bpp) &&(minfo->XResolution==xmax) &&(minfo->YResolution==ymax) &&((us)RMI.EAX==0x004f)) {if (mmode==0) {mmode=ic;}}}if (mmode!=0) cm.banked=1; else cm.banked=0;}if (mmode==0) {for (ic=0x0100;ic<0x0200;ic++) {RMI.EAX = 0x00004f01; // Get VBE Mode InfoRMI.ECX = ic;RMI.ES = seg;RMI.EDI = 0;r.w.ax = 0x0300;r.h.bl = 0x10;r.h.bh = 0;r.w.cx = 0;sr.es = FP_SEG (&RMI);r.x.edi = FP_OFF (&RMI);int386x (0x31, &r, &r, &sr);if (r.x.cflag) {cm.error=1;return(cm);}if ((minfo->BitsPerPixel==bpp)&&(minfo->XResolution==xmax)&&(minfo->YResolution==ymax)&&((us)RMI.EAX==0x004f)) {if (mmode==0) {mmode=ic;}}}}if (mmode==0) {cm.error=4;return(cm);}RMI.EAX = 0x00004f01; // Get VBE Mode InfoRMI.ECX = mmode;RMI.ES = seg;RMI.EDI = 0;r.w.ax = 0x0300;r.h.bl = 0x10;r.h.bh = 0;r.w.cx = 0;sr.es = FP_SEG (&RMI);r.x.edi = FP_OFF (&RMI);int386x (0x31, &r, &r, &sr);phys=minfo->PhysBasePtr;cm.bpp=minfo->BitsPerPixel;cm.bytespp=cm.bpp/8;cm.h=minfo->YResolution;cm.w=minfo->XResolution;cm.bpl=minfo->BytesPerScanLine;r.w.ax = 0x0800;r.w.bx = (phys >> 0x10);r.w.cx = (phys & 0xffff);r.w.si = (long)((minfo->YResolution * minfo->BytesPerScanLine)>>16);r.w.di = minfo->YResolution * minfo->BytesPerScanLine;int386 (0x31, &r, &r);if (r.x.cflag) {cm.error=5;return(cm);}cm.LFB = (uc near *) (((ul) r.w.bx << 16) | r.w.cx);r.w.ax = 0x4f02;r.w.bx = mmode;int386 (0x10, &r, &r);if (r.w.ax != 0x004f) {cm.error=6;return(cm);}cm.error=0;return(cm);}// Установка VGA режима ######################################################void SetVGAMode(int mode) {static VBE_RMI RMI;union REGS r;struct SREGS sr;memset (&sr, 0, sizeof (sr));memset (&RMI, 0, sizeof (RMI));memset (&r, 0, sizeof (r));RMI.EAX = mode; // Get VBE Mode Infor.w.ax = 0x0300;r.h.bl = 0x10;r.h.bh = 0;r.w.cx = 0;sr.es = FP_SEG (&RMI);r.x.edi = FP_OFF (&RMI);int386x (0x31, &r, &r, &sr);}void blt(TMode m) {if (m.bpp==32 && m.banked==1) { // Если включен 32 битный LFB режимmemcpy((void *)m.LFB, (void *)m.VLFB, m.w * m.h * m.bytespp);}}void InitGraph(void) {dwpl=cm.bpl>>2;scr=(int *)cm.VLFB;}void PutPixel(int x,int y,int color) {scr[y*dwpl+x]=color;}int sgn(int i) {if (i==0) return(0);if (i>0) return(1);return(-1);}void Line(int x1,int y1,int x2,int y2,int color) {int dx,dy,r,dr1,dr2,x,y,sx,sy;dx=abs(x2-x1);dy=abs(y2-y1);sx=sgn(x2-x1);sy=sgn(y2-y1);if (dx>dy) {r=dx;dr1=-dy<<1;dr2=(dx-dy)<<1;y=y1;x=x1;x2=x2+sx;do {PutPixel(x,y,color);if (r>0) r=r+dr1;else {r=r+dr2;y=y+sy;PutPixel(x,y,color);}x=x+sx;} while (x!=x2);}else {r=dy;dr1=-dx<<1;dr2=(dy-dx)<<1;y=y1;x=x1;y2=y2+sy;do {PutPixel(x,y,color);if (r>0) r=r+dr1;else {r=r+dr2;x=x+sx;PutPixel(x,y,color);}y=y+sy;} while (y!=y2);}}
Download this code: vesa.cpp
bmp.h
struct BMPHeader{unsigned short ID; // 'BM' for a Windows BitMaPunsigned int FSize; // Size of fileunsigned short Res1; // Not usedunsigned short Res2; // Not usedunsigned int Image; // Offset of image into fileunsigned int stSize; // число байт, занимаемых структурой BITMAPINFOHEADERunsigned int Width; // Width of imageunsigned int Height; // Height of imageunsigned short Num; // число битовых плоскостей устройстваunsigned short Bits; // Number of bits per pixelunsigned int Comp; // Type of compression, 0 for uncompressed, 1,2 for RLEunsigned int ISize; // Size of image in bytesunsigned int XRes; // X dots per metre (not inches! for US, unbelievable!)unsigned int YRes; // Y dots per metreunsigned int PSize; // Palette size (number of colours) if not zerounsigned int PImportant; // Probably reserved, currently 0};typedef struct SPallete { // Тип описывающий элемент палитры.char b,g,r,x;} TPallete;void BMP_PutFromFile(TMode cm, int x, int y, char * fname);
Download this code: bmp.h
vesa.h
#include <string.h>#include <stdio.h>#include <stdlib.h>#include <dos.h>typedef unsigned short us;typedef unsigned int ui;typedef unsigned char uc;typedef unsigned long ul;typedef struct SVBE_InfoBlock {uc VbeSignature[4]; // VBE Signatureus VbeVersion; // VBE Versionul OemStringPtr; // Pointer to OEM Stringul Capabilities; // Capabilities of graphics cont.ul VideoModePtr; // Pointer to Video Mode List// Added for VBE 1.2+us TotalMemory; // Number of 64kb memory blocks// Added for VBE 2.0+us OemSoftwareRev; // VBE implementation Software revisionul OemVendorNamePtr; // Pointer to Vendor Name Stringul OemProductNamePtr; // Pointer to Product Name Stringul OemProductRevPtr; // Pointer to Product Revision Stringus AccelVbeVersion; // VBE/AF Versionul AccelVideoModePtr; // Pointer to Acclelerated Mode Listuc Reserved20[216]; // Reserved for VBE implementation// scratch areauc OemData[256]; // Data Area for OEM Stringsuc NaVsyakiySloochay[100]; // 2e} VBE_InfoBlock;typedef struct SVBE_ModeInfoBlock {us ModeAttributes; // mode attributesuc WinAAttributes; // window A attributesuc WinBAttributes; // window B attributesus WinGranularity; // window granularityus WinSize; // window sizeus WinASegment; // window A start segmentus WinBSegment; // window B start segmentul WinFuncPtr; // pointer to window functionus BytesPerScanLine; // bytes per scan line// Mandatory information for VBE 1.2 and aboveus XResolution; // horizontal resolution in pixels or charsus YResolution; // vertical resolution in pixels or charsuc XCharSize; // character cell width in pixelsuc YCharSize; // character cell height in pixelsuc NumberOfPlanes; // number of memory planesuc BitsPerPixel; // bits per pixeluc NumberOfBanks; // number of banksuc MemoryModel; // memory model typeuc BankSize; // bank size in KBuc NumberOfImagePages; // number of imagesuc Reserved12; // reserved for page function// Direct Color fields (required// for direct/6 and YUV/7 memory models)uc RedMaskSize; // size of direct color red mask in bitsuc RedFieldPosition; // bit position of lsb of red maskuc GreenMaskSize; // size of direct color green mask in bitsuc GreenFieldPosition; // bit position of lsb of green maskuc BlueMaskSize; // size of direct color blue mask in bitsuc BlueFieldPosition; // bit position of lsb of blue maskuc RsvdMaskSize; // size of direct color reserved mask in bitsuc RsvdFieldPosition; // bit position of lsb of reserved maskuc DirectColorModeInfo; // direct color mode attributes// Mandatory information for VBE 2.0 and aboveul PhysBasePtr; // physical address for flat frame bufferul OffScreenMemOffset; // pointer to start of off screen memoryus OffScreenMemSize; // amount of off screen memory in 1k unitsuc Reserved20[206]; // remainder of ModeInfoBlockuc NaVsyakiySloochay[100]; // 2e} VBE_ModeInfoBlock;typedef struct SVBE_RMI { // Rreal Mode Interrupt (RMI) structureul EDI, ESI, EBP, ReservedByRMI,EBX, EDX, ECX, EAX;us flags,ES, DS,FS, GS,IP, CS,SP, SS;} VBE_RMI;typedef struct SMode { // Тип описывающий видео-режим.ul bpl; // Байт на строку растра.ul w; // Ширинаul h; // Высотаul bpp; // Бит на точкуul bytespp; // Байт на точкуul banked; // (1)LFB or (0)Bankedul error; // Ошибка (обязательно надо проверять)uc* LFB; // Указатель на LFBuc* VLFB; // Указатель на Виртуальный экран} TMode;TMode cm; // Текущий видеорежим.int GetVBEVersion(void);void PutVBEVersion(void);TMode SetVESAMode(int xmax, int ymax, int bpp);void SetVGAMode(int mode);void InitGraph(void);void blt(TMode m);void PutPixel(int x,int y,int color);void Line(int x1,int y1,int x2,int y2,int color);
Download this code: vesa.h