index bd409d38f9218b6579041ec92f52066b3c18ffd6..e543fc0e7023a9700a08ddf705f83f439aa8958c 100644 (file)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
+ * the Free Software Foundation, version 3 of the License ONLY.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
interface
uses
+ {$INCLUDE ../nogl/noGLuses.inc}
SysUtils, Classes,
- GL, GLExt, SDL2,
+ SDL2,
sdlcarcass,
fui_common, fui_events;
function combineClip (constref aclip: TGxRect): TGxRect; // returns previous clip
+ // vertical scrollbar
+ procedure drawVSBar (x, y, wdt, hgt: Integer; cur, min, max: Integer; constref clrfull, clrempty: TGxRGBA);
+ // horizontal scrollbar
+ procedure drawHSBar (x, y, wdt, hgt: Integer; cur, min, max: Integer; constref clrfull, clrempty: TGxRGBA);
+
+ class function sbarFilled (wh: Integer; cur, min, max: Integer): Integer;
+ class function sbarPos (cxy: Integer; xy, wh: Integer; min, max: Integer): Integer;
+
public //HACK!
procedure glSetScale (ascale: Single);
procedure glSetTrans (ax, ay: Single);
procedure oglDrawCursorAt (msX, msY: Integer);
+procedure fuiGfxLoadFont (const fontname: AnsiString; const fontFile: AnsiString; proportional: Boolean=false);
+procedure fuiGfxLoadFont (const fontname: AnsiString; st: TStream; proportional: Boolean=false);
+
// ////////////////////////////////////////////////////////////////////////// //
var
implementation
uses
+ fui_wadread,
utils;
function isScaled (): Boolean;
var
- mt: packed array [0..15] of Double;
+ mt: packed array [0..15] of GLfloat;
begin
- glGetDoublev(GL_MODELVIEW_MATRIX, @mt[0]);
+ glGetFloatv(GL_MODELVIEW_MATRIX, @mt[0]);
result := (mt[0] <> 1.0) or (mt[1*4+1] <> 1.0);
end;
// set active context; `ctx` can be `nil`
procedure gxSetContextInternal (ctx: TGxContext; ascale: Single; domatrix: Boolean);
var
- mt: packed array [0..15] of Double;
+ mt: packed array [0..15] of GLfloat;
begin
if (savedGLState.saved) then savedGLState.restore();
else
begin
// assume uniform scale
- glGetDoublev(GL_MODELVIEW_MATRIX, @mt[0]);
+ glGetFloatv(GL_MODELVIEW_MATRIX, @mt[0]);
ctx.mScaled := (mt[0] <> 1.0) or (mt[1*4+1] <> 1.0);
ctx.mScale := mt[0];
oglSetup2DState();
// ////////////////////////////////////////////////////////////////////////// //
-{$INCLUDE fui_gfx_gl_fonts.inc}
-
type
TGxBmpFont = class(TGxFont)
private
mFontBmp: PByte;
mFontWdt: PByte;
mFreeFontWdt: Boolean;
+ mFreeFontBmp: Boolean;
protected
procedure oglCreateTexture ();
function drawTextInternal (x, y: Integer; const s: AnsiString): Integer; // return width (not including last empty pixel)
public
- constructor Create (const aname: AnsiString; awdt, ahgt: Integer; const afont: PByte; const awdtable: PByte=nil);
+ constructor Create (const aname: AnsiString; st: TStream; proportional: Boolean);
destructor Destroy (); override;
function charWidth (const ch: AnsiChar): Integer; override;
end;
-constructor TGxBmpFont.Create (const aname: AnsiString; awdt, ahgt: Integer; const afont: PByte; const awdtable: PByte=nil);
+constructor TGxBmpFont.Create (const aname: AnsiString; st: TStream; proportional: Boolean);
var
- c: Integer;
-begin
- if (afont = nil) then raise Exception.Create('internal error in font creation');
- if (ahgt < 1) then raise Exception.Create('internal error in font creation');
- if (awdt > 0) then
+ sign: packed array [0..7] of AnsiChar;
+ enc: packed array [0..16] of AnsiChar;
+ b: Byte;
+ wdt, hgt, elen: Integer;
+ ch, dy: Integer;
+ fntbwdt: Integer;
+ wrd: Word;
+begin
+ mFreeFontBmp := true;
+ mFreeFontWdt := true;
+ mName := aname;
+ mTexId := 0;
+ // signature
+ st.ReadBuffer(sign[0], 8);
+ if (sign <> 'FUIFONT0') then raise Exception.Create('FlexUI: invalid font file signature');
+ // encoding length and width
+ st.ReadBuffer(b, 1);
+ wdt := (b and $0f)+1; // 16 is not supported
+ if (wdt = 16) then raise Exception.Create('FlexUI: 16-wdt fonts aren''t supported yet');
+ elen := ((b shr 4) and $0f);
+ if (elen = 0) then raise Exception.CreateFmt('FlexUI: invalid font encoding length: %d', [elen]);
+ // height
+ st.ReadBuffer(b, 1);
+ hgt := b;
+ if (hgt < 2) then raise Exception.CreateFmt('FlexUI: invalid font height: %d', [hgt]);
+ // encoding
+ st.ReadBuffer(enc[0], elen);
+ // check for 'cp1251' here (it can also be 'koi8')
+ if (wdt <= 8) then fntbwdt := 1 else fntbwdt := 2;
+ // shift and width table (hi nibble: left shift for proportional print; lo nibble: shifted character width for proportional print)
+ GetMem(mFontWdt, 256);
+ st.ReadBuffer(mFontWdt^, 256);
+ // font bitmap
+ GetMem(mFontBmp, (hgt*fntbwdt)*256);
+ st.ReadBuffer(mFontBmp^, (hgt*fntbwdt)*256);
+ mWidth := wdt;
+ mHeight := hgt;
+ mBaseLine := hgt-1; //FIXME
+ if (proportional) then
begin
- //if (awdtable <> nil) then raise Exception.Create('internal error in font creation');
- mFreeFontWdt := true;
- // create width table
- GetMem(mFontWdt, 256);
- for c := 0 to 255 do mFontWdt[c] := awdt-1;
+ // shift font
+ for ch := 0 to 255 do
+ begin
+ for dy := 0 to hgt-1 do
+ begin
+ if (fntbwdt = 1) then
+ begin
+ mFontBmp[ch*hgt+dy] := mFontBmp[ch*hgt+dy] shl (mFontWdt[ch] shr 4);
+ end
+ else
+ begin
+ wrd := mFontBmp[ch*(hgt*2)+(dy*2)]+256*mFontBmp[ch*(hgt*2)+(dy*2)+1];
+ wrd := wrd shl (mFontWdt[ch] shr 4);
+ mFontBmp[ch*(hgt*2)+(dy*2)+0] := (wrd and $ff);
+ mFontBmp[ch*(hgt*2)+(dy*2)+1] := ((wrd shr 16) and $ff);
+ end;
+ end;
+ end;
end
else
begin
- if (awdtable = nil) then raise Exception.Create('internal error in font creation');
- awdt := 0;
- mFontWdt := awdtable;
+ FillChar(mFontWdt^, 256, wdt);
end;
- mName := aname;
- mWidth := awdt;
- mHeight := ahgt;
- mBaseLine := ahgt-1; //FIXME
- mFontBmp := afont;
- mTexId := 0;
end;
destructor TGxBmpFont.Destroy ();
begin
+ if (mFreeFontBmp) and (mFontBmp <> nil) then FreeMem(mFontBmp);
if (mFreeFontWdt) and (mFontWdt <> nil) then FreeMem(mFontWdt);
mName := '';
mWidth := 0;
mFontBmp := nil;
mFontWdt := nil;
mFreeFontWdt := false;
+ mFreeFontBmp := false;
mTexId := 0;
inherited;
end;
procedure TGxBmpFont.oglCreateTexture ();
+const
+ TxWidth = 16*16;
+ TxHeight = 16*16;
+var
+ tex, tpp: PByte;
+ b: Byte;
+ cc: Integer;
+ x, y, dx, dy: Integer;
begin
- mTexId := createFontTexture(mFontBmp, mFontWdt, mHeight, (mWidth <= 0));
+ GetMem(tex, TxWidth*TxHeight*4);
+ FillChar(tex^, TxWidth*TxHeight*4, 0);
+
+ for cc := 0 to 255 do
+ begin
+ x := (cc mod 16)*16;
+ y := (cc div 16)*16;
+ for dy := 0 to mHeight-1 do
+ begin
+ if (mWidth <= 8) then b := mFontBmp[cc*mHeight+dy] else b := mFontBmp[cc*(mHeight*2)+(dy*2)+1];
+ //if prop then b := b shl (fontwdt[cc] shr 4);
+ tpp := tex+((y+dy)*(TxWidth*4))+x*4;
+ for dx := 0 to 7 do
+ begin
+ if ((b and $80) <> 0) then
+ begin
+ tpp^ := 255; Inc(tpp);
+ tpp^ := 255; Inc(tpp);
+ tpp^ := 255; Inc(tpp);
+ tpp^ := 255; Inc(tpp);
+ end
+ else
+ begin
+ tpp^ := 0; Inc(tpp);
+ tpp^ := 0; Inc(tpp);
+ tpp^ := 0; Inc(tpp);
+ tpp^ := 0; Inc(tpp);
+ end;
+ b := (b and $7f) shl 1;
+ end;
+ if (mWidth > 8) then
+ begin
+ b := mFontBmp[cc*(mHeight*2)+(dy*2)+0];
+ for dx := 0 to 7 do
+ begin
+ if ((b and $80) <> 0) then
+ begin
+ tpp^ := 255; Inc(tpp);
+ tpp^ := 255; Inc(tpp);
+ tpp^ := 255; Inc(tpp);
+ tpp^ := 255; Inc(tpp);
+ end
+ else
+ begin
+ tpp^ := 0; Inc(tpp);
+ tpp^ := 0; Inc(tpp);
+ tpp^ := 0; Inc(tpp);
+ tpp^ := 0; Inc(tpp);
+ end;
+ b := (b and $7f) shl 1;
+ end;
+ end;
+ end;
+ end;
+
+ glGenTextures(1, @mTexId);
+ if (mTexId = 0) then raise Exception.Create('can''t create FlexUI font texture');
+
+ glBindTexture(GL_TEXTURE_2D, mTexId);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TxWidth, TxHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex);
+ glFinish();
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ FreeMem(tex);
end;
@@ -473,13 +601,13 @@ function TGxBmpFont.drawCharInterim (x, y: Integer; const ch: AnsiChar): Integer
var
tx, ty: Integer;
begin
- tx := (Integer(ch) mod 16)*8;
+ tx := (Integer(ch) mod 16)*16;
ty := (Integer(ch) div 16)*16;
glBegin(GL_QUADS);
- glTexCoord2f((tx+0)/128.0, (ty+0)/256.0); glVertex2i(x+0, y+0); // top-left
- glTexCoord2f((tx+8)/128.0, (ty+0)/256.0); glVertex2i(x+8, y+0); // top-right
- glTexCoord2f((tx+8)/128.0, (ty+mHeight)/256.0); glVertex2i(x+8, y+mHeight); // bottom-right
- glTexCoord2f((tx+0)/128.0, (ty+mHeight)/256.0); glVertex2i(x+0, y+mHeight); // bottom-left
+ glTexCoord2f((tx+0)/256.0, (ty+0)/256.0); glVertex2i(x+0, y+0); // top-left
+ glTexCoord2f((tx+mWidth)/256.0, (ty+0)/256.0); glVertex2i(x+mWidth, y+0); // top-right
+ glTexCoord2f((tx+mWidth)/256.0, (ty+mHeight)/256.0); glVertex2i(x+mWidth, y+mHeight); // bottom-right
+ glTexCoord2f((tx+0)/256.0, (ty+mHeight)/256.0); glVertex2i(x+0, y+mHeight); // bottom-left
glEnd();
result := (mFontWdt[Byte(ch)] and $0f);
end;
// ////////////////////////////////////////////////////////////////////////// //
var
fontList: array of TGxBmpFont = nil;
- defaultFontName: AnsiString = 'dos';
+ defaultFontName: AnsiString = 'win14';
function strEquCI (const s0, s1: AnsiString): Boolean;
end;
+{
procedure deleteFonts ();
var
f: Integer;
for f := 0 to High(fontList) do freeAndNil(fontList[f]);
fontList := nil;
end;
+}
-procedure createFonts ();
+procedure fuiGfxLoadFont (const fontname: AnsiString; const fontFile: AnsiString; proportional: Boolean=false);
+var
+ st: TStream;
+begin
+ if (Length(fontname) = 0) then raise Exception.Create('FlexUI: cannot load nameless font '''+fontFile+'''');
+ st := fuiOpenFile(fontFile);
+ if (st = nil) then raise Exception.Create('FlexUI: cannot load font '''+fontFile+'''');
+ try
+ fuiGfxLoadFont(fontname, st, proportional);
+ except on e: Exception do
+ begin
+ writeln('FlexUI font loadin error: ', e.message);
+ FreeAndNil(st);
+ raise Exception.Create('FlexUI: cannot load font '''+fontFile+'''');
+ end;
+ else
+ raise;
+ end;
+ FreeAndNil(st);
+end;
+
+
+procedure fuiGfxLoadFont (const fontname: AnsiString; st: TStream; proportional: Boolean=false);
+var
+ fnt: TGxBmpFont = nil;
+ f: Integer;
begin
- deleteFonts();
- SetLength(fontList, 10);
- fontList[0] := TGxBmpFont.Create('dos', 8, 8, @kgiFont8[0], @kgiFont8PropWidth[0]);
- fontList[1] := TGxBmpFont.Create('dos-prop', 0, 8, @kgiFont8[0], @kgiFont8PropWidth[0]);
- fontList[2] := TGxBmpFont.Create('msx', 6, 8, @kgiFont6[0], @kgiFont6PropWidth[0]);
- fontList[3] := TGxBmpFont.Create('msx-prop', 0, 8, @kgiFont6[0], @kgiFont6PropWidth[0]);
- fontList[4] := TGxBmpFont.Create('win8', 8, 8, @kgiWFont8[0], @kgiWFont8Wdt[0]);
- fontList[5] := TGxBmpFont.Create('win8-prop', 0, 8, @kgiWFont8[0], @kgiWFont8Wdt[0]);
- fontList[6] := TGxBmpFont.Create('win14', 8, 14, @kgiFont14[0], @kgiFont14Wdt[0]);
- fontList[7] := TGxBmpFont.Create('win14-prop', 0, 14, @kgiFont14[0], @kgiFont14Wdt[0]);
- fontList[8] := TGxBmpFont.Create('win16', 8, 16, @kgiFont16[0], @kgiFont16Wdt[0]);
- fontList[9] := TGxBmpFont.Create('win16-prop', 0, 16, @kgiFont16[0], @kgiFont16Wdt[0]);
+ if (Length(fontname) = 0) then raise Exception.Create('FlexUI: cannot load nameless font');
+ fnt := TGxBmpFont.Create(fontname, st, proportional);
+ try
+ for f := 0 to High(fontList) do
+ begin
+ if (strEquCI(fontList[f].name, fontname)) then
+ begin
+ if (fontList[f].mTexId <> 0) then raise Exception.Create('FlexUI: cannot reload generated font named '''+fontname+'''');
+ FreeAndNil(fontList[f]);
+ fontList[f] := fnt;
+ exit;
+ end;
+ end;
+ SetLength(fontList, Length(fontList)+1);
+ fontList[High(fontList)] := fnt;
+ except
+ FreeAndNil(fnt);
+ raise;
+ end;
end;
end;
+// vertical scroll bar
+procedure TGxContext.drawVSBar (x, y, wdt, hgt: Integer; cur, min, max: Integer; constref clrfull, clrempty: TGxRGBA);
+var
+ filled: Integer;
+begin
+ if (wdt < 1) or (hgt < 1) then exit;
+ filled := sbarFilled(hgt, cur, min, max);
+ color := clrfull;
+ fillRect(x, y, wdt, filled);
+ color := clrempty;
+ fillRect(x, y+filled, wdt, hgt-filled);
+end;
+
+
+// horizontal scrollbar
+procedure TGxContext.drawHSBar (x, y, wdt, hgt: Integer; cur, min, max: Integer; constref clrfull, clrempty: TGxRGBA);
+var
+ filled: Integer;
+begin
+ if (wdt < 1) or (hgt < 1) then exit;
+ filled := sbarFilled(wdt, cur, min, max);
+ color := clrfull;
+ fillRect(x, y, filled, hgt);
+ color := clrempty;
+ fillRect(x+filled, y, wdt-filled, hgt);
+end;
+
+
+class function TGxContext.sbarFilled (wh: Integer; cur, min, max: Integer): Integer;
+begin
+ if (wh < 1) then result := 0
+ else if (min > max) then result := 0
+ else if (min = max) then result := wh
+ else
+ begin
+ if (cur < min) then cur := min else if (cur > max) then cur := max;
+ result := wh*(cur-min) div (max-min);
+ end;
+end;
+
+
+class function TGxContext.sbarPos (cxy: Integer; xy, wh: Integer; min, max: Integer): Integer;
+begin
+ if (wh < 1) then begin result := 0; exit; end;
+ if (min > max) then begin result := 0; exit; end;
+ if (min = max) then begin result := max; exit; end;
+ if (cxy < xy) then begin result := min; exit; end;
+ if (cxy >= xy+wh) then begin result := max; exit; end;
+ result := min+((max-min)*(cxy-xy) div wh);
+ assert((result >= min) and (result <= max));
+end;
+
+
+
+
// ////////////////////////////////////////////////////////////////////////// //
(*
procedure oglRestoreMode (doClear: Boolean);
*)
-//procedure onWinFocus (); begin end;
-//procedure onWinBlur (); begin fuiResetKMState(true); end;
+//procedure onWinFocus (); begin uiFocus(); end;
+//procedure onWinBlur (); begin fuiResetKMState(true); uiBlur(); end;
//procedure onPreRender (); begin oglRestoreMode(gGfxDoClear); end;
procedure onPostRender (); begin oglDrawCursor(); end;
// ////////////////////////////////////////////////////////////////////////// //
initialization
savedGLState := TSavedGLState.Create(false);
- createFonts();
+ //createFonts();
//winFocusCB := onWinFocus;
//winBlurCB := onWinBlur;
//prerenderFrameCB := onPreRender;