Never too old to learn.

pixel2.0

Posted on By Andy Zhu

还记得上次的 pixel单元吗?现在对其进行了更新,修改如下

  1. 重构了代码,支持了鼠标键盘响应
  2. 帧率提高
  3. 修改了内存的管理部分,使用后会自动删除对象
  4. 去除了标题栏和侧边栏

修改后的gla.pas如下:

{
GL Addons
对GL、GLU中的东西进行了一定的整合
(或许)可以简化使用
FPC5719 and ZCY
2019.3
}
unit gla;

interface

uses
	windows,gMap,gUtil;

const
	GLACLASSNAME='GLAWNDCLS';

type
	TGLACallback=procedure(wp,lp:DWord);
	TGLALess=specialize TLess<DWord>;
	TGLACallbackMap=specialize TMap<DWord,TGLACallback,TGLALess>;
	TGLACallbackMapIterator=TGLACallbackMap.TIterator;

function glaInit:boolean;
function glaCreateWindow(x,y,w,h:DWord;s:PChar):DWord;
procedure glaBindFunc(msg:DWord;func:TGLACallback);
procedure glaLoop;
procedure glaRedisplay;

{ procedure glaPutPixel(x,y,c:DWord); }
{ function glaGetPixel(x,y:DWord):DWord; }

var
	glaDC:DWord;

implementation

var
	__map:TGLACallbackMap;
	__dc,__hw:DWord;

function __WindowProc(wnd,msg,wp,lp:DWord):DWord;stdcall;export;
var
	i:TGLACallbackMapIterator;
begin
	i:=__map.Find(msg);
	if i=NIL then
		exit(DefWindowProc(wnd,msg,wp,lp))
	else begin
		i.Value(wp,lp);
		exit(0);
	end;
end;

function glaInit:boolean;
var
	cls:WNDCLASS;
begin
	__map:=TGLACallbackMap.Create;
	with cls do begin
		Style:=CS_HREDRAW or CS_VREDRAW;
		lpfnWndProc:=WndProc(@__WindowProc);
		cbClsExtra:=0;
		cbWndExtra:=0;
		hInstance:=system.MainInstance;
		hIcon:=LoadIcon(0,IDI_APPLICATION);
		hCursor:=LoadCursor(0,IDC_ARROW);
		hbrBackground:=0;
		lpszMenuName:=NIL;
		lpszClassName:=GLACLASSNAME;
	end;
	exit(RegisterClass(cls)<>0);
end;
function glaCreateWindow(x,y,w,h:DWord;s:PChar):DWord;
var
	hw:DWord;
begin
	hw:=CreateWindow(GLACLASSNAME,s,WS_POPUP,x,y,
		w,h,0,0,system.MainInstance,NIL);//这一条语句修改了
	__hw:=hw;
	if hw<>0 then begin
		__dc:=GetDC(hw);
		glaDC:=__dc;
		ShowWindow(hw,SW_SHOW);
		UpdateWindow(hw);
	end;
	exit(hw);
end;
procedure glaBindFunc(msg:DWord;func:TGLACallback);
begin
	__map.Items[msg]:=func;
end;
procedure glaLoop;
var
	amsg:MSG;
begin
	glaRedisplay;
	while GetMessage(@amsg,0,0,0) do begin
		TranslateMessage(amsg);
		DispatchMessage(amsg);
	end;
end;
procedure glaRedisplay;
begin
	InvalidateRect(__hw,NIL,TRUE);
	UpdateWindow(__hw);
end;

{ procedure glaPutPixel(x,y,c:DWord); }
{ begin }
	{ SetPixelv(__dc,x,y,c); }
{ end; }
{ function glaGetPixel(x,y:DWord):DWord; }
{ begin }
	{ exit(GetPixel(__dc,x,y)); }
{ end; }

end.

pixel2.pas

{$mode objfpc}
unit pixel2;
interface
 uses gla,fpwritebmp,fpimage,windows;
 type
  color3=record
   r,g,b:byte;
  end;
  a_color3=array of color3;
  aa_color3=array of a_color3;
  _procedure=procedure (wp,lp:dword);
  var
  { _window=class }
   map:aa_color3;
   paint,keydown,keyup,lbuttondown,rbuttondown,mbuttondown,lbuttonup,rbuttonup,mbuttonup:_procedure;
   window_changed,first_load:boolean;
   tdc,tbmp:dword;
   {constructor}procedure create;
   {destructor}procedure destroy;{override;}
   procedure _destroy(wp,lp:dword);
   procedure establish(sx,sy,ssx,ssy:longint;title:pchar);
   procedure resize(x,y:longint);
   procedure redraw;
   procedure display(wp,lp:dword);
   procedure setpixel(x,y:longint;col:color3);
   function getpixel(x,y:longint):color3;
  { end; }
 function make_color(r,g,b:longint):color3;
implementation
 procedure _procedure_null(wp,lp:dword);
 begin
  //What the fuck?
 end;
 {constructor}procedure {_window.}create;
 begin
  tdc:=CreateCompatibleDC(0);
  window_changed:=true;
  paint:=@_procedure_null;
  keydown:=@_procedure_null;
  keyup:=@_procedure_null;
  lbuttondown:=@_procedure_null;
  rbuttondown:=@_procedure_null;
  mbuttondown:=@_procedure_null;
  lbuttonup:=@_procedure_null;
  rbuttonup:=@_procedure_null;
  mbuttonup:=@_procedure_null;
  first_load:=true;
 end;
 {destructor}procedure destroy;{override;}
 begin
  _destroy(0,0);
 end;
 procedure _destroy(wp,lp:dword);
 begin
  PostQuitMessage(0);
  DeleteDC(tdc);
  DeleteObject(tbmp);
 end;
 procedure {_window.}establish(sx,sy,ssx,ssy:longint;title:pchar);
 begin
  resize(ssx,ssy);
  glaCreateWindow(sx,sy,ssx,ssy,title);
  glaBindFunc(WM_PAINT,@display);
  glaBindFunc(WM_DESTROY,@_destroy);
  
  glaBindFunc(WM_KEYDOWN,keydown);
  glaBindFunc(WM_KEYUP,keyup);
  glaBindFunc(WM_LBUTTONDOWN,lbuttondown);
  glaBindFunc(WM_RBUTTONDOWN,rbuttondown);
  glaBindFunc(WM_MBUTTONDOWN,mbuttondown);
  glaBindFunc(WM_LBUTTONUP,lbuttonup);
  glaBindFunc(WM_RBUTTONUP,rbuttonup);
  glaBindFunc(WM_MBUTTONUP,mbuttonup);
  //glaBindFunc(WM_,@);
  glaloop;
 end;
 procedure {_window.}resize(x,y:longint);
 var
  i:longint;
 begin
  setlength(map,x);
  for i:=0 to x-1 do
   setlength(map[i],y);
 end;
 procedure {_window.}redraw;
 begin
  display(0,0);
 end;
 procedure {_window.}display(wp,lp:dword);
 var
  i,j:longint;
  writer:tfpcustomimagewriter;
  img:tfpmemoryimage;
  px:tfpcolor;
 begin
  paint(wp,lp);
  if window_changed then
   begin
    writer:=tfpwriterbmp.create;
    img:=tfpmemoryimage.create(length(map),length(map[0]));
    for i:=0 to img.width-1 do
     for j:=0 to img.height-1 do
      begin
       px:=img.colors[i,j];
       with px do
        begin
         red:=map[i,j].r*255;
         green:=map[i,j].g*255;
         blue:=map[i,j].b*255;
        end;
       img.colors[i,j]:=px;
      end;
    img.savetofile('cache.bmp',writer);
    img.destroy;
    if first_load then
     first_load:=false
    else
     DeleteObject(tbmp);
    tbmp:=LoadImage(0,'cache.bmp',IMAGE_BITMAP,length(map),length(map[0]),LR_LOADFROMFILE);
	SelectObject(tdc,tbmp);
	BitBlt(glaDC,0,0,length(map),length(map[0]),tdc,0,0,SRCCOPY);
    window_changed:=false;
   end
  else
   BitBlt(glaDC,0,0,length(map),length(map[0]),tdc,0,0,SRCCOPY);
 end;
 procedure {_window.}setpixel(x,y:longint;col:color3);
 begin
  if (col.r=map[x-1,y-1].r)and(col.g=map[x-1,y-1].g)and(col.b=map[x-1,y-1].b) then
   exit
  else
   begin
    window_changed:=true;
    map[x-1,y-1]:=col;
   end;
 end;
 function {_window.}getpixel(x,y:longint):color3;
 begin
  exit(map[x-1,y-1]);
 end;
 function make_color(r,g,b:longint):color3;
 begin
  make_color.r:=r;
  make_color.g:=g;
  make_color.b:=b;
 end;
begin
 glaInit;
end.

这里提供一个例子:

uses pixel2,sysutils;
var
 fps:longint;
 time:extended;
 procedure display(wp,lp:dword);
 var
  i,j:longint;
 begin
  for i:=1 to 400 do
   for j:=1 to 400 do
    if(i>40)or(j>40) then
     setpixel(i,j,make_color(random(256),random(256),random(256)))
    else
     if(i=j)or(i+j=41) then
      setpixel(i,j,make_color(255,0,0))
     else
      setpixel(i,j,make_color(255,255,255));
  fps:=fps+1;
  if (now-time)*86400>=1 then
   begin
    writeln(fps);
    fps:=0;
    time:=now;
   end;
 end;
 procedure click(wp,lp:longword);
 var
  x,y:longint;
 begin
  x:=lp mod 65536;
  y:=lp div 65536;
  if(x<=40)and(y<=40)then
   destroy;
 end;
begin
 time:=now;
 randomize;
 create;
 paint:=@display;
 lbuttondown:=@click;
 establish(100,100,400,400,'test');
end.

帧率从原先的47增加到了80