123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441 |
- {$MODE objfpc}
- {$ASMMODE intel}
- Unit CGA;
- Interface
- Procedure CGAText;
- Procedure CGA320;
- Procedure CGA640;
- Procedure CGADump(q : PByte);
- Procedure CGASetPalette(palette, border : Integer);
- Procedure CGAPrecalc;
- Implementation
- Uses
- go32, crt;
- Const
- palette : Array[0..15, 0..2] Of Byte = (
- ( 0, 0, 0), ( 0, 0,42), ( 0,42, 0), ( 0,42,42), (42, 0, 0), (42, 0,42), (42,21, 0), (42,42,42),
- (21,21,21), (21,21,63), (21,63,21), (21,63,63), (63,21,21), (63,21,63), (63,63,21), (63,63,63));
- cgaback : Array[0..3, 0..12] Of Integer = (
- ( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 15),
- ( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14),
- ( 0, 1, 3, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15),
- ( 0, 1, 2, 4, 6, 8, 9, 10, 11, 12, 13, 14, 15));
- Type
- Float = Extended;
- TCGAVideoBuffer = Array[0..16383] Of Byte;
- PCGAPrecalc = ^TCGAPrecalc;
- TCGAPrecalc = Array[0..15{r}, 0..15{g}, 0..15{b}, 0..3{y}, 0..3{x}] Of Byte;
- PCGAPrecalcError = ^TCGAPrecalcError;
- TCGAPrecalcError = Array[0..15{r}, 0..15{g}, 0..15{b}] Of Integer;
- Var
- cgapal : Array[0..3] Of Integer;
- videobuf : TCGAVideoBuffer;
- precalcbuf : Array[0..12, 0..3] Of PCGAPrecalc; {3.25mb}
- precalcerror : Array[0..12, 0..3] Of PCGAPrecalcError; {0.8125mb}
- error : Integer;
- lastpalette, lastback : Integer;
- Procedure CGA320;
- Var
- regs : TRealRegs;
- Begin
- regs.ax := $0004;
- RealIntr($10, regs);
- lastpalette := -1;
- lastback := -1;
- End;
- Procedure CGA640;
- Var
- regs : TRealRegs;
- Begin
- regs.ax := $0004;
- RealIntr($10, regs);
- End;
- Procedure CGAText;
- Var
- regs : TRealRegs;
- Begin
- regs.ax := $0003;
- RealIntr($10, regs);
- End;
- Procedure CGASetPalette(palette, border : Integer);
- Var
- regs : TRealRegs;
- Begin
- If (palette = lastpalette) And (border = lastback) Then
- Exit;
- lastpalette := palette;
- lastback := border;
- regs.ah := $0B;
- regs.bh := 1;
- regs.bl := palette And 1;
- RealIntr($10, regs);
- If (palette And 2) = 0 Then
- Inc(border, 16);
- regs.ah := $0B;
- regs.bh := 0;
- regs.bl := border;
- RealIntr($10, regs);
- End;
- Procedure CGABlitToScreen(p : Pointer); Assembler;
- Asm
- mov edi, $B8000
- push es
- mov ax, fs
- mov es, ax
- mov esi, [p]
- mov ecx, 16192/4
- rep movsd
- pop es
- End;
- Function CGACalc2(r, g, b : Integer; dx, dy : Integer; back, pal : Integer) : Integer;{ Inline;}
- Begin
- CGACalc2 := precalcbuf[back, pal]^[r Shr 4, g Shr 4, b Shr 4, dy, dx];
- End;
- Procedure CGACalc(r, g, b : Integer; {dx, dy : Integer;}
- Var dither, best1, best2 : Integer);
- Var
- I, J : Integer;
- mindist : Float;
- dist : Float;
- r1, g1, b1 : Integer;
- tmp : Integer;
- { dither : Integer;} {0-none; 1-50%; 2-25%; 3-12.5%; 4-37.5%}
- Begin
- r := Round(r*63 / 15);
- g := Round(g*63 / 15);
- b := Round(b*63 / 15);
- mindist := $7FFFFFFF;
- For I := 0 To 3 Do
- Begin
- dist := Sqr(r - palette[cgapal[I], 0]) +
- Sqr(g - palette[cgapal[I], 1]) +
- Sqr(b - palette[cgapal[I], 2]);
- If dist < mindist Then
- Begin
- mindist := dist;
- best1 := I;
- dither := 0;
- End;
- End;
- For J := 0 To 3 Do
- Begin
- r1 := palette[cgapal[J], 0];
- g1 := palette[cgapal[J], 1];
- b1 := palette[cgapal[J], 2];
- For I := 0 To 3 Do
- Begin
- If I = J Then
- Continue;
- dist := Sqr(r - (palette[cgapal[I], 0] + r1)*0.5) +
- Sqr(g - (palette[cgapal[I], 1] + g1)*0.5) +
- Sqr(b - (palette[cgapal[I], 2] + b1)*0.5);
- If dist < mindist Then
- Begin
- mindist := dist;
- best1 := J;
- best2 := I;
- dither := 1;
- End;
- dist := Sqr(r - (0.25*palette[cgapal[I], 0] + 0.75*r1)) +
- Sqr(g - (0.25*palette[cgapal[I], 1] + 0.75*g1)) +
- Sqr(b - (0.25*palette[cgapal[I], 2] + 0.75*b1));
- If dist < mindist Then
- Begin
- mindist := dist;
- best1 := J;
- best2 := I;
- dither := 2;
- End;
- dist := Sqr(r - (0.125*palette[cgapal[I], 0] + 0.875*r1)) +
- Sqr(g - (0.125*palette[cgapal[I], 1] + 0.875*g1)) +
- Sqr(b - (0.125*palette[cgapal[I], 2] + 0.875*b1));
- If dist < mindist Then
- Begin
- mindist := dist;
- best1 := J;
- best2 := I;
- dither := 3;
- End;
- dist := Sqr(r - (0.375*palette[cgapal[I], 0] + 0.625*r1)) +
- Sqr(g - (0.375*palette[cgapal[I], 1] + 0.625*g1)) +
- Sqr(b - (0.375*palette[cgapal[I], 2] + 0.625*b1));
- If dist < mindist Then
- Begin
- mindist := dist;
- best1 := J;
- best2 := I;
- dither := 4;
- End;
- End;
- End;
- error:=error+round(Sqrt(mindist) * 290);
- Case dither Of
- 0 : best2 := best1;
- 1 : Begin
- If best1 > best2 Then
- Begin
- tmp := best1;
- best1 := best2;
- best2 := tmp;
- End;
- End;
- End;
- End;
- Function CGACalcError(s : PByte; back, pal : Integer) : Integer;
- Var
- X, Y : Integer;
- r, g, b : Integer;
- Begin
- CGACalcError := 0;
- For Y := 0 To 199 {Div 4} Do
- Begin
- For X := 0 To 319 {Div 4} Do
- Begin
- b := s[0];
- g := s[1];
- r := s[2];
- inc(CGACalcError,precalcerror[back, pal]^[b Shr 4, g Shr 4, r Shr 4]);
- Inc(s, 4{ + 4 + 4 + 4});
- End;
- // Inc(s, 320*4*3);
- End;
- End;
- Procedure CGADump2(s, d : PByte; back, pal : Integer);
- Var
- I : Integer;
- src, dest : PByte;
- X, Y : Integer;
- r1, g1, b1 : Integer;
- r2, g2, b2 : Integer;
- r3, g3, b3 : Integer;
- r4, g4, b4 : Integer;
- Begin
- error := 0;
- src := s;
- dest := d;
- For Y := 0 To 99 Do
- Begin
- For X := 0 To 79 Do
- Begin
- b1 := src[0];
- g1 := src[1];
- r1 := src[2];
- b2 := src[4];
- g2 := src[5];
- r2 := src[6];
- b3 := src[8];
- g3 := src[9];
- r3 := src[10];
- b4 := src[12];
- g4 := src[13];
- r4 := src[14];
- dest^ := (CGACalc2(r1, g1, b1, 0, (Y And 1) Shl 1, back, pal) Shl 6) Or
- (CGACalc2(r2, g2, b2, 1, (Y And 1) Shl 1, back, pal) Shl 4) Or
- (CGACalc2(r3, g3, b3, 2, (Y And 1) Shl 1, back, pal) Shl 2) Or
- (CGACalc2(r4, g4, b4, 3, (Y And 1) Shl 1, back, pal));
- Inc(src, 4*4);
- Inc(dest);
- End;
- Inc(src, 320*4);
- End;
- src := s + 320*4;
- dest := d + 8192;
- For Y := 0 To 99 Do
- Begin
- For X := 0 To 79 Do
- Begin
- b1 := src[0];
- g1 := src[1];
- r1 := src[2];
- b2 := src[4];
- g2 := src[5];
- r2 := src[6];
- b3 := src[8];
- g3 := src[9];
- r3 := src[10];
- b4 := src[12];
- g4 := src[13];
- r4 := src[14];
- dest^ := (CGACalc2(r1, g1, b1, 0, ((Y And 1) Shl 1) + 1, back, pal) Shl 6) Or
- (CGACalc2(r2, g2, b2, 1, ((Y And 1) Shl 1) + 1, back, pal) Shl 4) Or
- (CGACalc2(r3, g3, b3, 2, ((Y And 1) Shl 1) + 1, back, pal) Shl 2) Or
- (CGACalc2(r4, g4, b4, 3, ((Y And 1) Shl 1) + 1, back, pal));
- Inc(src, 4*4);
- Inc(dest);
- End;
- Inc(src, 320*4);
- End;
- End;
- Procedure CGADump(q : PByte);
- Var
- pal, back : Integer;
- bestpal, bestback : Integer;
- besterror : Integer;
- Begin
- besterror := $7FFFFFFF;
- For pal := 0 To 3 Do
- Begin
- For back := 0 To 12 Do
- Begin
- error := CGACalcError(q, back, pal);
- If error < besterror Then
- Begin
- besterror := error;
- bestpal := pal;
- bestback := back;
- End;
- End;
- End;
- CGADump2(q, videobuf, bestback, bestpal);
- CGASetPalette(bestpal, cgaback[bestpal, bestback]);
- CGABlitToScreen(@videobuf);
- End;
- Procedure CGAPrecalc;
- Var
- pal, back : Integer;
- r, g, b : Integer;
- x, y : Integer;
- dither : Integer;
- best1, best2 : Integer;
- res : Integer;
- Begin
- For pal := 0 To 3 Do
- Begin
- Case pal Of
- 0 : Begin
- cgapal[1] := 10;
- cgapal[2] := 12;
- cgapal[3] := 14;
- End;
- 1 : Begin
- cgapal[1] := 11;
- cgapal[2] := 13;
- cgapal[3] := 15;
- End;
- 2 : Begin
- cgapal[1] := 2;
- cgapal[2] := 4;
- cgapal[3] := 6;
- End;
- 3 : Begin
- cgapal[1] := 3;
- cgapal[2] := 5;
- cgapal[3] := 7;
- End;
- End;
- For back := 0 To 12 Do
- Begin
- If (precalcbuf[back, pal] = Nil) And (precalcerror[back, pal] = Nil) Then
- Begin
- New(precalcbuf[back, pal]);
- New(precalcerror[back, pal]);
- End
- Else
- Continue;
- cgapal[0] := cgaback[pal, back];
- error := 0;
- Write(pal, back:3, ' ');
- TextAttr := cgapal[0];
- Write('*');
- TextAttr := cgapal[1];
- Write('*');
- TextAttr := cgapal[2];
- Write('*');
- TextAttr := cgapal[3];
- Writeln('*');
- TextAttr := 7;
- For r := 0 To 15 Do
- For g := 0 To 15 Do
- For b := 0 To 15 Do
- Begin
- error := 0;
- CGACalc(r, g, b, dither, best1, best2);
- precalcerror[back, pal]^[r, g, b] := error;
- For y := 0 To 3 Do
- For x := 0 To 3 Do
- Begin
- Case dither Of
- 0 : res := best1;
- 1 : Begin
- If ((x + y) And 1) <> 0 Then
- res := best1
- Else
- res := best2;
- End;
- 2 : Begin
- If ((x And 1) = 0) And ((y And 1) = 0) Then
- res := best2
- Else
- res := best1;
- End;
- 3 : Begin
- If (x = y) And ((x And 1) = 0) Then
- res := best2
- Else
- res := best1;
- End;
- 4 : Begin
- If (((x And 1) = 0) And ((y And 1) = 0)) Or (x = y) Then
- res := best2
- Else
- res := best1;
- End;
- End;
- precalcbuf[back, pal]^[r, g, b, y, x] := res;
- End;
- End;
- //Function CGACalc(r, g, b : Integer; dx, dy : Integer) : Integer;
- End;
- End;
- End;
- Begin
- FillChar(precalcbuf, SizeOf(precalcbuf), 0);
- FillChar(precalcerror, SizeOf(precalcerror), 0);
- End.
|