Mostrar una matriz de colores en C [cerrado]
Mi programa escribe y lee matrices de colores como este:
struct Image {
size_t width;
size_t height;
struct Color *data;
}
struct Color {
char r;
char g;
char b;
}
¿Cómo puedo mostrar una matriz de este tipo en la pantalla en C?
Representación de gráficos:
Estoy acostumbrado a los entornos win32 y Borland C++, así que me apego a ellos, pero las diferencias con otros entornos se encuentran principalmente solo en los nombres de las clases. Primero algunos enfoques:
- modos de consola/texto
Puedes usar gráficos de texto ( arte ASCII, creo que en inglés). Donde el punto está representado por el carácter . La intensidad está formada por caracteres más o menos rellenos. Por lo general, tiene una tabla de caracteres ordenados por intensidad " ..:+*#"
y la usa en lugar de colores. Para imprimir algo, puedes usar iostream
, like cout << "text" << endl;
o printf
from stdio
, creo (no he usado la salida de consola de estilo antiguo durante más de una década).
La RAM de video en modos de texto ( VRAM ) comienza en 0B000:0000
si tiene los privilegios para ello, puede realizar acceso directo de esta manera:
char far *scr = (char far*)0x0B0000000;
scr[0] = 'A'; // Print A to left upper corner
Pero en Windows puedes olvidarte del acceso directo .
- Modo de gráficos VGA
(Solo DOS, no Windows; esto implica acceso directo al hardware VGA). Aquí hay un pequeño ejemplo:
// Turbo C++ for 16-bit real mode DOS
//==============================================================================
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 switches VGA to 320*200*256 color mode (fits inside a single 64 KB 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 6-bit long, therefore the shr al,2
out dx,al
}
scr=(char far*)0xA0000000; // VRAM start address
}
//==============================================================================
void cls() // This clears the screen with zeros
{
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 draws a 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;
}
}
//==============================================================================
El acceso VESA es similar, pero hay que lidiar con el cruce de segmentos y la localización. Aquí hay un pequeño ejemplo de Turbo C++:
VESA.h
// Turbo C++, still 16-bit DOS,
// but using VESA calls to set modes instead of VGA registers
//==============================================================================
//=== Globals: =================================================================
//==============================================================================
char far* scr=(char far*)0xA0000000; // VGA/VESA memory pointer
int VESA_page,VESA_pages; // Actual 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 video 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 {
// Wait 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. =====================================================================
//==============================================================================
principal.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 : utilizable en Windows
Canvas
es un subcomponente gráfico de los componentes visuales en Windows. En Borland se TCanvas
llama la clase Canvas
. Todas las ventanas lo tienen también PaintBoxes, Bitmaps, ...
. Es la interfaz GDI entre Windows y su aplicación. Tiene subcomponentes como Pen, Brush, and Font
líneas, rellenos o papel de texto, tinta de texto.
Form1->Canvas->Pen->Color=clYellow;
Form1->Canvas->MoveTo(10,10);
Form1->Canvas->LineTo(100,150);
¿ Dónde Form1
está mi ventana VCL ? Este código dibuja una línea amarilla.
GDI tiene muchas funciones como Arc, Ellipse, Pixels[][],...
. Consulte la ayuda integrada de su IDE para obtener más información.
- Mapa de bits GDI
Este es un objeto especial. Es un mapa de bits con un identificador gráfico del sistema operativo (contexto de dispositivo DC ). Esto permite que un mapa de bits sea algo así como una ventana y tenga acceso a GDI :
Graphics::TBitmap *bmp=new Graphics::TBitmap;
bmp->Width=100;
bmp->Height=100;
bmp->HandleType=bmDIB; // Allows use of ScanLine
bmp->PixelFormat=pf32bit; // 32-bit - the same as int so we can use int* for pixels pointer
Esto crea un mapa de bits VCL y lo configura 100x100x32 bit
con acceso directo. Ahora puedes acceder a la ScanLine
propiedad. También bmp->Canvas
está presente, por lo que también puedes hacer todas las cosas de 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
Tenga cuidado de permanecer x,y
dentro de un mapa de bits o se generará una excepción. El código de colores depende de pixelformat
, y normalmente es 0x00RRGGBB
o 0x00BBGGRR
. Creo que este enfoque es la mejor opción para ti. Además, puedes dibujar cualquier objeto GDI en cualquier otro objeto GDI :
Form1->Canvas->Draw(0, 0, bmp);
Esto dibuja su mapa de bits en la ventana, para que pueda verlo realmente.
- Biblioteca de gráficos
Hay muchas, pero las más utilizadas son OpenGL y DirectX . Prefiero OpenGL porque es más sencillo de implementar (al menos para empezar) y además OpenGL es multiplataforma y DirectX es solo para Windows. Además, cuando comencé a codificar no había DirecX. Cuando comencé a usar OpenGL, todos los proveedores lo incluían en los controladores. Ahora los únicos proveedores que todavía están actualizados son Nvidia y ATI (AMD) . Casi siempre hay algún problema de controlador entre ellos, pero en general Nvidia es mejor para OpenGL (tiene errores en la implementación de DirectX) y ATI (solo versiones AMD) es mejor para DirectX (tiene errores en la implementación de OpenGL). Pero para las operaciones básicas está bien (los problemas surgen en funciones más avanzadas).
Proveedores como Intel, SiS, etc. han detenido sus implementaciones en versiones más recientes de OpenGL. Al menos no conozco ningún controlador mejor que OpenGL 3.3 para ellos.
Para comenzar con OpenGL, consulte OpenGL obtener contexto del dispositivo .
Recomiendo encarecidamente comenzar primero con GDI + Bitmap. Puedes hacer mucho con ellos. Todavía lo estoy usando para renderizados no complejos.
Como se mencionó anteriormente, soy compatible con Borland ( estilo VCL ), por lo que si usa un compilador/IDE diferente, cambie los nombres de los objetos GDI para que correspondan a su entorno. Creo que Canvas es lo mismo y el mapa de bits HBitmap
, pero será mejor que consultes tu ayuda/documentación. Al menos sabes qué buscar.
Otras plataformas y esas cosas.
- Los gráficos simples en Linux están aquí: ejemplo de X11/Xlib.h
- Modos VGA en ensamblaje 8086