Programación General > Trucos

 Acceso A Pixeles Y Pintado En Pantalla Rápidos

(1/1)

Amilius:
Este truco es para graficar rápidamente con delphi, aplicable a juegos 2d y para tratamiento de pixeles:

Esto me costó unas buenas horas de investigación con los archivos de ayuda de delphi (win32.hlp), una buena página de funciones de windows: http://www.winprog.org/tutorial y también una revisada al archivo fuente "graphics.pas".

La idea es pasar lo más rápido posible un pedazo de memoria cuyos bits puedes manejar de la forma que quieras a la pantalla. Generalmente al usar Delphi esto significa tener un Tbitmap y acceder a los pixeles con el scanline. El problema es que no quería llamar al scanline (vieron todo el codigo que tiene?*) por cada línea. Tampoco llamar al .draw (vieron todo el codigo que tiene?*) cada vez que tenga que mostrar una imagen en pantalla.

* Se que ese código extra le da toda la potencia y simplicidad de uso del GDI al Delphi, pero para este caso específico donde sólo tu parte de código trabaja con el bitmap y lo que más quieres es velocidad todo ese código no es pertinente. De todas formas se puede utilizar las comodidades de las clases de delphi, como el Tbitmap.loadFromFile() y copiarlo al hbitmap con el bitblt() y Tcanvas.handle para obtener el "HDC".

IMPORTANTE:

+ EL ejemplo es para pixeles de 16 bits.
+ El formato de color a 16bits es A-5-5-5, 5 bits para cada canal RGB.
+ Hay que tener en cuenta que cada línea del bitmap DEBE estar alineado a DWORD. Si ANCHO_BMP_RENDER es múltiplo de 4 no hay problema para cualquier número de bits por pixel. Para 16bits basta que sea múltiplo de 2, pero para 24 y 8bits tiene que ser múltiplo de 4. Para 32bits no hay problema.

EN EL FORMULARIO:
Agregar un botón, enlazar el evento "onclick" a "Button1Click", enlazar el oncreate y ondestroy al form1.


--- Código: Text --- unit main; interface uses  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,  StdCtrls, DIB, ExtCtrls;  const  ANCHO_BMP_RENDER=256;  ALTO_BMP_RENDER=128;  PIXELES_BMP_RENDER=ANCHO_BMP_RENDER*ALTO_BMP_RENDER;  BYTES_BMP_RENDER=PIXELES_BMP_RENDER*2; type   TForm1 = class(TForm)    Button1: TButton;    procedure Button1Click(Sender: TObject);    procedure FormCreate(Sender: TObject);    procedure FormDestroy(Sender: TObject);    procedure FormPaint(Sender: TObject);  private    { Private declarations }    hdcBuffer:HDC;    hbmBuffer,hbmBufferOriginal:HBITMAP;    InfoBM:PBITMAPINFO;    fPixeles:pointer;    procedure CrearBitmapRender;    procedure EliminarBitmapRender;  public    { Public declarations }  end; var  Form1: TForm1; implementation {$R *.DFM} function GDICheck(n:integer):integer;begin  result:=n;  if n=0 then    showmessage('Error GDI: #'+inttostr(GetLastError));end; procedure TForm1.CrearBitmapRender;var HDCPrincipal:HDC;begin  getMem(infoBM,sizeof(TBitmapInfo));  with InfoBM^,bmiHeader do  begin    biSize:=sizeof(TBITMAPINFOHEADER);//40    biWidth:=ANCHO_BMP_RENDER;    biHeight:=-ALTO_BMP_RENDER;//Para un Bitmap "TOP->DOWN"    biPlanes:=1;    biBitCount:=16;    biCompression:=0;    biSizeImage:=BYTES_BMP_RENDER;    biXPelsPerMeter:=0;    biYPelsPerMeter:=0;    biClrUsed:=0;    biClrImportant:=0;  end;  HDCPrincipal:=getDC(handle);  if longbool(HDCPrincipal) then  begin    hdcBuffer:=CreateCompatibleDC(HDCPrincipal);    hbmBuffer:=GDICheck(CreateDIBSection(hdcBuffer,InfoBM^,DIB_RGB_COLORS,fPixeles,0,0));    hbmBufferOriginal := SelectObject(hdcBuffer, hbmBuffer);//Viene con uno que no usaremos    releaseDC(handle,HDCPrincipal);  end;end; procedure TForm1.EliminarBitmapRender;begin  if (hdcBuffer<>0) then  begin    SelectObject(hdcBuffer, hbmBufferOriginal);//Para que sea eliminado junto con el hbitmap    DeleteDC(hdcBuffer);  end;  if (hbmBuffer<>0) then    DeleteObject(hbmBuffer);  if InfoBM<>nil then    freemem(InfoBM);end; procedure TForm1.FormCreate(Sender: TObject);begin  CrearBitmapRender;end; procedure TForm1.Button1Click(Sender: TObject);type TPixeles=array[0..ALTO_BMP_RENDER-1,0..ANCHO_BMP_RENDER-1] of word;     PPixeles=^TPixeles;     TPixeles2=array[0..PIXELES_BMP_RENDER-1] of word;     PPixeles2=^TPixeles2;var i:integer;begin//Tres formas de acceder a los pixeles  for i:=0 to 5000 do    PPixeles(fPixeles)[random(ALTO_BMP_RENDER),random(ANCHO_BMP_RENDER)]:=random(32);  for i:=0 to 5000 do    PPixeles2(fPixeles)[random(PIXELES_BMP_RENDER)]:=random(32) shl 5;  for i:=0 to 5000 do    word(pointer(integer(fPixeles)+(random(PIXELES_BMP_RENDER) shl 1))^):=random(32) shl 10;  BitBlt(canvas.handle, 0, 0, ANCHO_BMP_RENDER, ALTO_BMP_RENDER, hdcBuffer, 0, 0, SRCCOPY);end; procedure TForm1.FormDestroy(Sender: TObject);begin  EliminarBitmapRender;end; procedure TForm1.FormPaint(Sender: TObject);begin  BitBlt(canvas.handle,0,0, ANCHO_BMP_RENDER, ALTO_BMP_RENDER, hdcBuffer, 0, 0, SRCCOPY);end; end.  

Navegación

[0] Índice de Mensajes

Ir a la versión completa