HD6845图形模式,一个图片块(8X8象素组成的一个小图片,称为Tile)最多只能支持8种颜色,整个屏幕最多可显示64种颜色。这点和任天堂红白机不太一样。差不多用一个星期的工作日时间,改写RAM、内存数据,查资料,并通过获得的数据,推算出结果,在IC板上确认。最终结果就是:一个Tile最多8种颜色,整个屏幕64色。CRT显示管拍照方式无法找到正确颜色显示值,最终只能采取近似的方法确定:R,G,B的颜色值只能取 $0, $40,$BF, $FF,这4个。组合成的64色,如下图: (图一) 用Tile显示图形字符时,如显示A时会出下面这的情况: 一个或者多Tile组成。(图二)
控件必须要有上面两种功能!! 那么接下来的目标是要实现:定义行列个数;每个小正方形之间的间隔可调整,8X8个小正方形之间在用粗线分开(直观的显示出Tile)。 控件要增加属性Row,Col,相应的定义:FPaletteBin:: array [0 .. 16*16-1] of TRGBColor就要改变了,跟据实际需要,4X4个TILE(32X32个小正方形)完全能够满足需要,那么数组就改为:FPaletteBin:: array [0 .. 32*32-1] of TRGBColor。为了方便操作增加一个私有变量:PalCount:共有多少个小正方形:
private FPalCount: Integer; published property Col: Integer read FCol write SetCOL; //不能write FCol因为FCol有最大限制 property Row: Integer read FRow write SetRow; …… constructor TPaletteBoxVCL.Create(AOwner: TComponent); begin inherited Create(AOwner); FCanDraw:=true; FCol := 16; //初始值 FRow := 16; end; procedure TPaletteBoxVCL.SetCol(const Value: Integer); begin if Value > 0 then begin if (Value * FRow) <= 1024 then begin FCol := Value; FPalCount := FCol * FRow; Paint; end; end; end; procedure TPaletteBoxVCL.SetRow(const Value: Integer); begin if Value > 0 then begin if (FCol * Value) <= 1024 then begin FRow := Value; FPalCount := FCol * FRow; Paint; end; end; end;接下来就要改Paint里面代码了。分三步走: 第一步,按设定的Col,Row画控件:这个很简单(见 16 改为 FCol 或 FRow) 将Pw := (Width - 2) div 16 改为 : Pw := (Width - 2) div FCol Ph := (Height - 2) div 16 改为: Ph := (Height - 2) div FRow; for i := 0 to 15 do begin 改为:for i := 0 to Row-1 do begin for j := 0 to 15 do begin 改为:for j := 0 to Col-1 do begin 就OK了。 第二步,实现可调整间隔,在这这前代码,间隔值是默认为2。需将它改为属性变量。
published property Interval: Integer read FInterval write SetInterva; …… //初始值 2 代码略 procedure TPaletteBoxVCL.SetInterva(const Value: Integer); begin if Value >= 0 then begin FInterval := Value; Paint; //设计期间立即看到效果 end; end;同时更改 Paint 内代码:见 2 改为 FInterval ;同时增加FInterval := 0 只画细线。更改后代码:
procedure TPaletteBoxVCL.Paint; function RGBtoColor(R,G,B:Byte):TColor; begin result:=TColor((B shl 16) +(G shl 8)+R); end; var i, j, a: integer; Pw, Ph: integer; R: TRect; BMP:TBitmap; begin if not FCanDraw then exit; BMP:=TBitmap.Create; //防闪烁 BMP.Width:=Width; BMP.Height:=Height; Pw := (Width - FInterval) div FCol; // 留边 2Pix Ph := (Height - FInterval) div FRow; Pw := min(Pw, Ph); Pw := Pw - FInterval; // 相距 2PIX Ph:= Pw; with BMP do begin Canvas.Pen.Color:=clGray; Canvas.Brush.Color := clbtnFace; Canvas.Rectangle(0, 0, Width, Height); Canvas.Brush.Color := clGray; Canvas.Pen.Width:=1; a:=0; for i := 0 to Row-1 do begin R := RECT(0, 0, Pw, Ph); R.Offset(FInterval, FInterval); R.Offset(0, i*(Ph+FInterval)); for j := 0 to Col-1 do begin Canvas.Pen.Color:=clGray; Canvas.Brush.Color := RGBtoColor(FPaletteBin[a].R,FPaletteBin[a].G,FPaletteBin[a].B); if FInterval > 0 then //加判断 Canvas.Rectangle(R.Left, R.Top, R.Right, R.Bottom) else begin //新增代码 间隔为 0 ,画线, Canvas.FillRect(RECT(R.Left + 1, R.Top + 1, R.Right, R.Bottom)); if i = 0 then begin // 顶上一根线 Canvas.MoveTo(R.Left, R.Top); Canvas.LineTo(R.Right, R.Top); end; if j = 0 then begin Canvas.MoveTo(R.Left, R.Top); Canvas.LineTo(R.Left, R.Bottom); end; Canvas.MoveTo(R.Left, R.Bottom); Canvas.LineTo(R.Right, R.Bottom); Canvas.MoveTo(R.Right, R.Top); Canvas.LineTo(R.Right, R.Bottom); end; R.Offset(Pw+FInterval, 0); inc(a); end; end; end; Canvas.Draw(0,0,BMP); BMP.Free; end;每三步:8X8之间用粗线分隔,一个8X8就是一个Tile,为了以后方便使用增加一个属性:ShowTile:boolean。定义略过, 为方便维护,不加入原有循环中,代码如下:
procedure TPaletteBoxVCL.Paint; …… with BMP do begin …… if (FInterval = 0) and FShowTile then begin Canvas.Pen.Width := 2; Canvas.Pen.Color := clGray; for i := 1 to (FCol div 8) - 1 do begin Canvas.MoveTo(i * 8 * Pw, 0); Canvas.LineTo(i * 8 * Pw, Ph * FRow); end; for i := 1 to (FRow div 8) - 1 do begin Canvas.MoveTo(0, i * 8 * Ph); Canvas.LineTo(Ph * Col, i * 8 * Ph); end; end; end; Canvas.Draw(0,0,BMP); BMP.Free; end;实现目标:
图一的实现: 属性设置: Col:16,Row:4;Interval:2; 代码:
procedure TForm3.Button1Click(Sender: TObject); function RGBtoColor(R, G, B: Byte): Dword; begin result := (B shl 16) + (G shl 8) + R; end; const Cs: array [0 .. 3] of Byte = ($0, $40, $BF, $FF); var i, j, k, a: Integer; Cl: TColor; begin a := 0; PaletteBoxVCL1.BeginUpdate; for i := 0 to 3 do for j := 0 to 3 do for k := 0 to 3 do begin Cl := RGBtoColor(Cs[k], Cs[j], Cs[i]); PaletteBoxVCL1.SetColor(a, Cl); inc(a); end; PaletteBoxVCL1.EndUpdate; end;