unit framebuffers; // maybe just name that "images" ? No, "framebuffer" is more common. "frame_buffers" ? {$MODE OBJFPC} interface uses type_fixes, colors; type { assert sizeof Cardinal >= 4 } //TPixelComponents = TColorspace; {(pcBlack, pcWhite, pcGray, pcRedGreenBlue, pcIndexed);} { TODO BGR, CYMK, YPbPr (= Y(R-Y)(B-Y)) } { (#bits, what), (#bits, what), ... } TPixelBitfieldName = (bnUnused, bnRed, bnGreen, bnBlue, bnWhite, //bnBlack, bnAlpha, bnCyan, bnYellow, bnMagenta, bnBlack, bnHue, bnSaturation, bnValue); TPixelBitfieldEntry = record Name : TPixelBitfieldName; Count : 0..32; end; { describes what the bits in a pixel are, starting from the least significant bit, going up, one record per meaning } TPixelBitfield = array[0..9] of TPixelBitfieldEntry; TMatrixOrder = (moColumnRow { recommended }, moRowColumn); TFramebufferInfoP = ^TFramebufferInfo; TFramebufferInfo = object InfoSize : TCardinal; InfoVersion : TCardinal; Start : Pointer; Frontier : Pointer; { could be calculated, but just to be on the safe side. } Size : TCardinal; { could be calculated, but just to be on the safe side. } //FIXME needed? no... OriginX : Integer; { to be able to represent a smaller clipping area of some bigger framebuffer. } //FIXME needed? no... OriginY : Integer; { to be able to represent a smaller clipping area of some bigger framebuffer. } Width : TCardinal; { in pixels } Height : TCardinal; { in pixels } PixelSize : 1..64; // bits. PixelComponents : TColorspace; RowStride : TCardinal; { in bytes, 0 for dummy framebuffer. } MatrixOrder : TMatrixOrder; // PaletteResolver : array of IColor; useless here... PixelsPerMeterX : TCardinal; PixelsPerMeterY : TCardinal; PixelBitfield : TPixelBitfield; // if any. constructor Init; constructor Init(const aPixelBitfield : TPixelBitfield; aWidth, aHeight : TCardinal); procedure SetStart(aStart : Pointer); end; const pbR8G8B8 : TPixelBitfield = ((Name: bnRed; Count: 8), (Name: bnGreen; Count: 8), (Name: bnBlue; Count: 8), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0)); pbGray8 : TPixelBitfield = ( (Name: bnValue; Count: 8), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0)); pbGray8Alpha8 : TPixelBitfield = ( (Name: bnValue; Count: 8), (Name: bnAlpha; Count: 8), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0)); pbGray4Alpha4 : TPixelBitfield = ( (Name: bnValue; Count: 4), (Name: bnAlpha; Count: 4), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0)); pbAlpha1 : TPixelBitfield = ( (Name: bnAlpha; Count: 1), // much alpha is opaque. (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0), (Name: bnUnused; Count: 0)); implementation const FramebufferVersion = $0100; constructor TFramebufferInfo.Init(const aPixelBitfield : TPixelBitfield; aWidth, aHeight : TCardinal); var VRowLengthInBits : TCardinal; VBitfieldIndex : Integer; VBitCount : TCardinal; VBRGB : Boolean = True; VBGray : Boolean = True; VBHSV : Boolean = True; VBCMYK : Boolean = True; // VBYUV : Boolean = True; begin Init(); // don't forget "alpha". Width := aWidth; Height := aHeight; PixelComponents := csCustom; MatrixOrder := moColumnRow; VBitCount := 0; for VBitfieldIndex := Low(aPixelBitfield) to High(aPixelBitfield) do with aPixelBitfield[VBitfieldIndex] do begin // shorthand: case Name of bnRed, bnGreen, bnBlue: begin VBGray := False; VBHSV := False; VBCMYK := False; // RGB = True end; bnWhite, bnBlack: begin VBHSV := False; VBCMYK := False; VBRGB := False; // VBGray = True end; bnCyan, bnYellow, bnMagenta: // Black not unique. begin VBGray := False; VBHSV := False; VBRGB := False; // VBCMYK = True end; bnHue, bnSaturation, bnValue: begin VBGray := False; VBCMYK := False; VBRGB := False; // VBHSV = True end; end; //Name bnUnused, bnAlpha Inc(VBitCount, Count); //Count // TODO ignore "unused", "alpha"? end; assert(Integer(VBRGB) + Integer(VBGray) + Integer(VBHSV) + Integer(VBCMYK) <= 1); if VBRGB then PixelComponents := csRGB else if VBGray then PixelComponents := csGray else if VBHSV then PixelComponents := csHSV else if VBCMYK then PixelComponents := csCMYK; PixelSize := VBitCount; PixelBitfield := aPixelBitfield; VRowLengthInBits := aWidth * PixelSize; RowStride := (VRowLengthInBits + 7) shr 3; // in bytes. At the very least. Size := RowStride * aHeight; // at least. end; constructor TFramebufferInfo.Init; begin Self.InfoSize := Sizeof(TFramebufferInfo); Self.InfoVersion := FramebufferVersion; Self.Start := nil; Self.Size := 0; Self.Frontier := nil; //Self.OriginX := 0; //Self.OriginY := 0; Self.Width := 0; Self.Height := 0; Self.PixelSize := 1; Self.PixelComponents := csGray; Self.RowStride := 0; Self.MatrixOrder := moColumnRow; Self.PixelsPerMeterX := 1; Self.PixelsPerMeterY := 1; end; procedure TFramebufferInfo.SetStart(aStart : Pointer); begin Start := aStart; // AllocMem(Size); Frontier := PByte(Start) + Size; end; end.