Показать массив цветов в C
Моя программа пишет как читает массивы цветов, как этот:
struct Image {
size_t width;
size_t height;
struct Color *data;
}
struct Color {
char r;
char g;
char b;
}
Как я могу отобразить такой массив на экране в C?
1 ответ
Рендеринг графики:
Я привык к средам win32 и Borland C++, поэтому придерживаюсь этого, но различия в других средах в основном только в именах классов. Сначала несколько подходов:
консольные / текстовые режимы
Вы можете использовать текстовую графику ( ASCII art я думаю на английском языке). Где точка представлена символом. Интенсивность определяется более или менее заполненными символами. Обычно есть таблица символов, отсортированная по интенсивности
" ..:+*#"
и использовать это вместо цветов. Для распечатки можно использовать что-тоiostream
лайкcout << "text" << endl;
или жеprintf
отstdio
Я думаю (не использую вывод консоли в старом стиле более десяти лет).Видеорам в текстовых режимах (VRAM) начинается с
0B000:0000
если у вас есть привилегии для этого, вы можете сделать прямой доступ следующим образом:char far *scr=(char far*)0x0B0000000; scr[0]='A'; // print A to left upper corner
а на винде про прямой доступ можно забыть
Режим VGA gfx
на Windows вы можете забыть об этом также... Вот небольшой пример:
//============================================================================== char far* scr; // VGA screen const _sx= 320; // physical screen size const _sy= 200; //============================================================================== void gfxinit(); void cls(); void pnt(int x,int y,char c); //============================================================================== void gfxinit() { asm { mov ax,19 // this swith VGA to 320*200*256 color mode (fits inside single 64KB segment so no funny stuff is needed) int 16 } for (int i=0;i<256;i++) asm { // this overwrites 256 color palette with some BW gradients mov dx,0x3C8 mov ax,i out dx,al // overwrite color al = i inc dx shr al,2 // al=al>>2 out dx,al // r,g,b or b,g,r not sure now out dx,al // all values are 6bit long therefore the shr al,2 out dx,al } scr=(char far*)0xA0000000; // VRAM start address } //============================================================================== void cls() // this clear screen with zero { asm { push es mov ax,0xA000 mov es,ax mov di,0x0000 sub ax,ax mov cx,32000 rep stosw pop es } } //============================================================================== void pnt(int x,int y,char c) // this draw single point of color c { unsigned int adr; if (x<_sx) if (x>=0) if (y<_sy) if (y>=0) { y=y*_sx; adr=x+y; scr[adr]=c; } } //==============================================================================
Доступ к VESA аналогичен, но вам приходится иметь дело с пересечением сегментов и поиском. Вот небольшой пример Turbo C++:
VESA.h
//============================================================================== //=== Globals: ================================================================= //============================================================================== char far* scr=(char far*)0xA0000000; // VGA/VESA memory pointer int VESA_page,VESA_pages; // actaul page and total pages int VESA_xs,VESA_ys,VESA_bpp; // video mode properties int VESA_page_xy[64]={-1,-1}; // starting x,y for each page const int VESAmodes[]= // usable video modes table { 320, 200, 8,0x150, 640, 480, 8,0x101, 800, 600, 8,0x103, 1024, 768, 8,0x105, 1280,1024, 8,0x107, 320, 200,16,0x10E, 640, 480,16,0x111, 800, 600,16,0x114, 1024, 768,16,0x117, 320, 200,32,0x10F, 640, 480,32,0x112, 800, 600,32,0x115, 0,0,0,0 }; //============================================================================== //=== Headers: ================================================================= //============================================================================== int VESAmode(int xs,int ys,int bpp); // set video mode void VESApage(int page); // set page void VESAexit(); // return to VGA text mode void VESAcls(); // clear with 0 void VESApnt(int x,int y,unsigned int c); // render 8/16 bpp point void VESApnt32(int x,int y,int r,int g ,int b); // render 32bpp point //============================================================================== //=== Graphic: ================================================================= //============================================================================== int VESAmode(int xs,int ys,int bpp) { int i,mode,x,y; unsigned int adr0,adr,dx,dy; // find video mode for (i=0;VESAmodes[i];i+=4) if (VESAmodes[i+0]==xs) if (VESAmodes[i+1]==ys) if (VESAmodes[i+2]==bpp) break; if (!VESAmodes[i]) return 0; mode=VESAmodes[i+3]; VESA_xs=xs; VESA_ys=ys; VESA_bpp=bpp; // compute start x,y for each page>0 dx=bpp>>3; dy=xs*dx; VESA_pages=1; for (adr=i=x=y=0;y<VESA_ys;y++) { adr0=adr; adr+=dy; if (adr0>adr) { while (adr>0) { adr-=dx; x--; } while (x<0) { x+=VESA_xs; y--; } VESA_page_xy[i]=x; i++; VESA_page_xy[i]=y+1; i++; VESA_pages++; } } VESA_page_xy[i]=-1; i++; VESA_page_xy[i]=-1; i++; // set vide mode asm { mov bx,mode mov ax,0x4F02 int 16 } VESApage(0); /* // set palette to grayscale if (VESAbpp==8) for (int i=0;i<256;i++) asm { mov dx,0x3C8 mov ax,i out dx,al inc dx shr al,2 out dx,al out dx,al out dx,al } */ return 1; } //============================================================================== void VESApage(int page) { int p=page; asm { mov dx,p mov bx,0 mov ax,0x4f05 int 16 } VESA_page=page; } //============================================================================== void VESAexit() { asm { // waut for key press mov ax,0 int 0x16 // VGA 80x25 text mode mov ax,3 int 16 } } //============================================================================== void VESAcls() { int i; for (i=0;i<VESA_pages;i++) { VESApage(i); asm { push es mov ax,0xA000 mov es,ax mov di,0x0000 mov ax,0 mov cx,32000 rep stosw pop es } } } //============================================================================== void VESApnt(int x,int y,unsigned int c) { unsigned int adr; int p; // inside screen? if ((x>=0)&&(x<VESA_xs)) if ((y>=0)&&(y<VESA_ys)) { // low 16 bit of address adr=y; adr*=VESA_xs; adr+=x; adr*=(VESA_bpp>>3); // page for (p=0;VESA_page_xy[p+p+0]>=0;p++) { if (VESA_page_xy[p+p+1]>y) break; if (VESA_page_xy[p+p+1]<y) continue; if (VESA_page_xy[p+p+0]>x) break; } if (p!=VESA_page) VESApage(p); // render scr[adr]=c; if (VESA_bpp==16) { adr++; if (adr==0) VESApage(p+1); scr[adr]=(c>>8); } } } //============================================================================== void VESApnt32(int x,int y,int r,int g ,int b) { unsigned int adr; int p; // inside screen? if ((x>=0)&&(x<VESA_xs)) if ((y>=0)&&(y<VESA_ys)) { // low 16 bit of address adr=y; adr*=VESA_xs; adr+=x; adr*=(VESA_bpp>>3); // page for (p=0;VESA_page_xy[p+p+0]>=0;p++) { if (VESA_page_xy[p+p+1]>y) break; if (VESA_page_xy[p+p+1]<y) continue; if (VESA_page_xy[p+p+0]>x) break; } if (p!=VESA_page) VESApage(p); // render scr[adr]=b; adr++; if (adr==0) VESApage(p+1); scr[adr]=g; adr++; if (adr==0) VESApage(p+1); scr[adr]=r; } } //============================================================================== //=== End. ===================================================================== //==============================================================================
main.cpp
//============================================================================== //=== Includes: ================================================================ //============================================================================== #include "vesa.h" //============================================================================== //=== Main: ==================================================================== //============================================================================== void main() { if (!VESAmode(800,600,32)) return; VESAcls(); int x,y; unsigned int c; for (y=0;y<VESA_ys;y++) for (x=0;x<VESA_xs;x++) { if (VESA_bpp== 8) { c=x+y; VESApnt(x,y,c); } if (VESA_bpp==16) { c=(x&31)+((y&63)<<5); VESApnt(x,y,c); } if (VESA_bpp==32) VESApnt32(x,y,x,x+y,y); } VESAexit(); } //============================================================================== //=== End. ===================================================================== //==============================================================================
GDI
Canvas
является графическим подкомпонентом визуальных компонентов в Windows. В Borland это классTCanvas
названныйCanvas
, Все окна имеют это такжеPaintBoxes,Bitmaps,...
, Это интерфейс GDI между Windows и вашим приложением. Имеет подкомпоненты, такие какPen,Brush,Font
для строк, заливок или текстовой бумаги, текстовых чернил.Form1->Canvas->Pen->Color=clYellow; Form1->Canvas->MoveTo(10,10); Form1->Canvas->LineTo(100,150);
где
Form1
мое окно VCL этот код рисует желтую линию.GDI имеет много функций, таких как
Arc,Ellipse,Pixels[][],...
см. встроенную справку вашей IDE для получения дополнительной информации.GDI Bitmap
это специальный объект, это растровое изображение с графическим дескриптором ОС (контекст устройства DC). Это позволяет растровому изображению быть чем-то вроде окна и иметь доступ к GDI
Graphics::TBitmap *bmp=new Graphics::TBitmap; bmp->Width=100; bmp->Height=100; bmp->HandleType=bmDIB; // allows use of ScanLine bmp->PixelFormat=pf32bit; // 32bit the same as int so we can use int* for pixels pointer
это создает растровое изображение VCL и устанавливает его
100x100x32bit
с прямым доступом. Теперь вы можете получить доступScanLine
имущество. Такжеbmp->Canvas
присутствует, так что вы можете делать все вещи GDI тоже.int *p=bmp->ScanLine[10]; // p = pointer to y=10 line of bitmap p[20]=0; // draw dot on x=20,y=10 color=0x00000000 which is black int c = p[15]; // read pixel x=15,y=10 from bitmap to c
Будьте осторожны, чтобы остаться с
x,y
внутри будет выброшено растровое изображение или исключение. Цветовое кодирование зависит отpixelformat
обычно это0x00RRGGBB
или же0x00BBGGRR
, Я думаю, что этот подход является лучшим вариантом для вас, также вы можете нарисовать любой объект GDI для любого другого объекта GDIForm1->Canvas->Draw(0,0,bmp);
это рисует ваше растровое изображение в окне, так что вы можете увидеть его на самом деле.
Графическая библиотека
Их много, но чаще всего используются OpenGL и DirectX. Я предпочитаю OpenGL, потому что его проще реализовать (по крайней мере, для начинающих), а также OpenGL является кроссплатформенным, а DirectX - только для Windows. Кроме того, когда я начал кодировать, не было DirecX. Когда я начал использовать OpenGL, он был включен в драйверы. Теперь единственными поставщиками, которые все еще обновляются, являются nVidia и ATI(AMD). Между ними почти всегда возникают проблемы с драйверами, но в целом nVidia лучше для OpenGL (есть ошибки в реализации DirectX), а ATI(только для версий AMD) лучше для DirectX (есть ошибки в реализации OpenGL). Но с базовыми операциями у вас все в порядке (проблемы переходят на более сложные функции)
Такие производители, как Intel, SiS,... остановили свои реализации на более новых версиях OpenGL, по крайней мере, я не знаю ни одного драйвера лучше, чем OpenGL 3.3 для них
Чтобы начать работу с OpenGL, посмотрите OpenGL get Device Context
Я настоятельно рекомендую начать с GDI+Bitmap. Вы можете сделать с ними многое, я все еще использую его для несложного рендеринга.
Как упоминалось ранее, я дружественен к Borland (стиль VCL), поэтому, если вы используете другой компилятор /IDE, измените имена объектов GDI, чтобы они соответствовали вашей среде. Я думаю, что холст такой же, и растровое изображение HBitmap
но лучше проверьте свою помощь / документы, по крайней мере, вы знаете, что искать.
Надеюсь, это немного поможет.
[Edit1] другие платформы
- простой gfx в Linux здесь: пример X11/Xlib.h