Contributor: JOHN BIDDISCOMBE

{
this is not complete but it may help someone
 - code for 256 colour DIBs

I've nearly finished a little DIB demo that I'll upload to DSP soon

John B
===================================
}

unit DIB_surface_object;

interface

uses
  { Borland }
  Windows,Sysutils,Graphics,Classes,
  { Mine }
  Palunit;

type
  Pshape = ^shape;
  shape  = array[0..0] of Tpoint;

type
  DIBsurfaceobject = Class(TObject)
    DIBheader    : TMyBitmapInfo;
    DIBPalette   : TMyLogPalette;
    DIBhpalette  : hPalette;
    DIBpalsize   : integer;
    DIBbits      : Pointer;
    DIBhandle    : THandle;
    DIBDC        : hDC;
    Original_BMP : hBitmap;
    Original_PAL : hPalette;
    DIBWidth     : integer;
    DIBHeight    : integer;
    DIBWidth_b   : integer;
    DIBSize      : integer;
    constructor Create(palette:TMyLogPalette; newsize:TPoint);
    destructor  destroy;  override;
    procedure   change_size(newsize:TPoint; force:boolean);
    procedure   change_palette(newpal:shortstring);
    procedure   draw_horizontal_line(x1,x2,y:integer; b:byte);
    procedure   set_pixel(x,y:integer; b:byte);
    procedure   safe_set_pixel(x,y:integer; b:byte);
    procedure   fill_polygon(n:integer; poly:Pshape; fillcol:byte);
    procedure   copy_surface_to_screen(destDC:hDC);
    procedure   copy_screen_to_surface(sourceDC:hDC);
    procedure   clear_surface;
  end;

implementation

{ ------------------------------------------------------------------------ }
{                             DIB surface object                           }
{ ------------------------------------------------------------------------ }
constructor DIBsurfaceobject.Create(palette:TMyLogPalette; newsize:TPoint);
var lp1 : integer;
begin
  inherited Create;
  DIBbits      := nil;
  DIBhandle    := 0;
  DIBPalette   := palette;
  DIBhpalette  := CreatePalette(PLogPalette(@palette)^);
  DIBDC        := CreateCompatibleDC(0);
  Original_PAL := SelectPalette(DIBDC,DIBhpalette,false);
  with DIBheader do begin
    with bmiHeader do begin
      biSize          := sizeof(TBITMAPINFOHEADER);
      biWidth         := newsize.x;
      biHeight        := newsize.y;
      biPlanes        := 1;
      biBitCount      := 8;
      biCompression   := BI_RGB;
      biSizeImage     := 0;
      biXPelsPerMeter := 0;
      biYPelsPerMeter := 0;
      biClrUsed       := 0;
      biClrImportant  := 0;
    end;
    for lp1:=0 to 255 do BMIcolors[lp1] := (lp1+0) and 255; { Pal_indices - no offset }
  end;
  Original_BMP := 0;
  DIBWidth     := 0;
  DIBHeight    := 0;
  change_size(newsize,false);
end;

destructor DIBsurfaceobject.destroy;
begin
  if Original_BMP<>0 then SelectObject(DIBDC,Original_BMP);
  if Original_PAL<>0 then SelectPalette(DIBDC,Original_PAL,false);
  if DIBhandle<>0    then DeleteObject(DIBhandle);
  if DIBhpalette<>0  then DeleteObject(DIBhpalette);
  DeleteDC(DIBDC);
  inherited destroy;
end;

procedure DIBsurfaceobject.change_size(newsize:TPoint; force:boolean);
begin
  if (not force) and (newsize.x=DIBWidth) and (newsize.y=DIBHeight) then exit;
  DIBWidth   := newsize.x;
  DIBHeight  := newsize.y;
  DIBWidth_b := ((DIBWidth+3)shr 2)shl 2;
  DIBSize    := DIBWidth_b*DIBHeight;
  if Original_BMP<>0 then SelectObject(DIBDC,Original_BMP);
  if DIBhandle<>0 then DeleteObject(DIBhandle);
  DIBheader.BMIheader.biWidth  := DIBWidth;
  DIBheader.BMIheader.biHeight :=-DIBHeight; { Top down for me please...}
  DIBhandle    := CreateDIBSection(DIBDC,pBitmapInfo(@DIBheader)^,DIB_PAL_COLORS,DIBbits,nil,0);
  Original_BMP := SelectObject(DIBDC,DIBhandle);
end;

procedure DIBsurfaceobject.change_palette(newpal:shortstring);
begin
  SelectPalette(DIBDC,Original_PAL,false);
  create_256_identity_palette_from_file(DIBpalette,DIBhpalette,newpal);
  Original_PAL := SelectPalette(DIBDC,DIBhpalette,false);
  change_size(Point(DIBwidth,DIBheight),true);
end;

procedure DIBsurfaceobject.draw_horizontal_line(x1,x2,y:integer; b:byte);
var lp1,offset : integer;
begin
  offset:=integer(DIBbits)+ y*DIBWidth_b;
  for lp1:=x1 to x2 do Pbyte( offset+lp1 )^ := b;
end;

procedure DIBsurfaceobject.set_pixel(x,y:integer; b:byte);
begin
  Pbyte( integer(DIBbits) + y*DIBWidth_b + x )^ := b;
end;

procedure DIBsurfaceobject.safe_set_pixel(x,y:integer; b:byte);
begin
  if (x=0) then begin
    if (y=0) then begin
      Pbyte( integer(DIBbits) + y*DIBWidth_b + x )^ := b;
    end;
  end;
end;

procedure DIBsurfaceobject.fill_polygon(n:integer; poly:Pshape; fillcol:byte);
var loop1                   : integer;
    yval,ymax,ymin          : integer;
    yval0,yval1,yval2,yval3 : integer;
    ydifl,ydifr             : integer;
    xval0,xval1,xval2,xval3 : integer;
    xleft,xright            : integer;
    mu                      : integer;
    minvertex               : integer;
    vert0,vert1,vert2,vert3 : integer;
begin
  ymax:=-99999; ymin:=99999;
  { get top & bottom scan lines to work with }
  for loop1:=0 to n-1 do begin
    yval:=poly^[loop1].y;
    if yval>ymax then ymax:=yval;
    if yvalydifl then begin
      vert0:=vert1; vert1:=(vert1+1) mod n-1;
      yval0 := poly^[vert0].y; yval1 := poly^[vert1].y;
      xval0 := poly^[vert0].x; xval1 := poly^[vert1].x;
      ydifl := yval1-yval0;
      mu:=(loop1-yval0)
    end;
    if ydifl<>0 then xleft:=xval0 - (mu*integer(xval0-xval1) div ydifl)
    else             xleft:=xval0;

    {intersection on right hand side }
    if ydifr<>0 then mu:=(loop1-yval2)
    else mu:=ydifr;
    if mu>ydifr then begin
      vert2:=vert3; vert3:=(vert3-1) mod n-1;
      yval2 := poly^[vert2].y; yval3 := poly^[vert3].y;
      xval2 := poly^[vert2].x; xval3 := poly^[vert3].x;
      ydifr := yval3-yval2;
      if ydifr<>0 then mu:=(loop1-yval2)
      else mu:=ydifr;
    end;
    if ydifr<>0 then xright:=xval2 + (mu*integer(xval3-xval2) div ydifr)
    else             xright:=xval2;
    draw_horizontal_line(xleft,xright,loop1,fillcol);
  end;
end;

procedure DIBsurfaceobject.copy_surface_to_screen(destDC:hDC);
begin
  SelectPalette(destDC,DIBhpalette,false);
  BitBlt(destDC,0,0,DIBWidth,DIBHeight,DIBDC,0,0,SRCCOPY);
end;

procedure DIBsurfaceobject.copy_screen_to_surface(sourceDC:hDC);
begin
  BitBlt(DIBDC,0,0,DIBWidth,DIBHeight,sourceDC,0,0,SRCCOPY);
end;

procedure DIBsurfaceobject.clear_surface;
var DWORDptr : Plongint;
    lp1      : integer;
begin
  for lp1:=0 to DIBheight-1 do
    draw_horizontal_line(0,DIBwidth,lp1,lp1);
  exit;

  DWORDptr:=DIBbits;
  for lp1:=0 to (DIBsize div 4)-1 do begin
    Plongint(DWORDptr)^:=$00000000;
    inc(DWORDptr);
  end;
end;

initialization
end.