From b4265979da0b4b264d3cd4685af9566d6ae37f2f Mon Sep 17 00:00:00 2001 From: Ketmar Dark Date: Tue, 3 Oct 2017 01:28:58 +0300 Subject: [PATCH] FlexUI: completely reworked graphics layer -- it is using drawing contexts now --- src/flexui/fui_common.pas | 40 +- src/flexui/fui_ctls.pas | 333 +++---- src/flexui/fui_gfx_gl.pas | 1393 +++++++++++++++--------------- src/flexui/fui_gfx_gl_cursor.inc | 171 ++++ src/flexui/fui_gfx_gl_fonts.inc | 311 +++++++ 5 files changed, 1376 insertions(+), 872 deletions(-) create mode 100644 src/flexui/fui_gfx_gl_cursor.inc create mode 100644 src/flexui/fui_gfx_gl_fonts.inc diff --git a/src/flexui/fui_common.pas b/src/flexui/fui_common.pas index 76354c3..744ddff 100644 --- a/src/flexui/fui_common.pas +++ b/src/flexui/fui_common.pas @@ -92,6 +92,29 @@ type function blend (ar, ag, ab, aa: Integer): TGxRGBA; inline; end; + TGxRect = packed record + public + x, y, w, h: Integer; + + public + constructor Create (ax, ay, aw, ah: Integer); + + function empty (): Boolean; inline; // invalid rects are empty too + function valid (): Boolean; inline; + + // modifies this rect, so it won't be bigger than `r` + // returns `false` if this rect becomes empty + function intersect (constref r: TGxRect): Boolean; inline; + end; + + TGxOfs = packed record + public + xofs, yofs: Integer; + + public + constructor Create (axofs, ayofs: Integer); + end; + // ////////////////////////////////////////////////////////////////////////// // // return `false` if destination rect is empty @@ -105,7 +128,6 @@ implementation uses utils; - // ////////////////////////////////////////////////////////////////////////// // constructor TLaySize.Create (aw, ah: Integer); begin w := aw; h := ah; end; function TLaySize.getIdx (idx: Integer): Integer; inline; begin if (idx = 0) then result := w else if (idx = 1) then result := h else result := -1; end; @@ -174,6 +196,22 @@ begin end; +// ////////////////////////////////////////////////////////////////////////// // +constructor TGxRect.Create (ax, ay, aw, ah: Integer); begin x := ax; y := ay; w := aw; h := ah; end; + +function TGxRect.empty (): Boolean; inline; begin result := (w <= 0) or (h <= 0); end; +function TGxRect.valid (): Boolean; inline; begin result := (w < 0) or (h < 0); end; + +function TGxRect.intersect (constref r: TGxRect): Boolean; inline; +begin + result := intersectRect(x, y, w, h, r.x, r.y, r.w, r.h); +end; + + +// ////////////////////////////////////////////////////////////////////////// // +constructor TGxOfs.Create (axofs, ayofs: Integer); begin xofs := axofs; yofs := ayofs; end; + + // ////////////////////////////////////////////////////////////////////////// // //TODO: overflow checks function intersectRect (var x0, y0, w0, h0: Integer; const x1, y1, w1, h1: Integer): Boolean; inline; diff --git a/src/flexui/fui_ctls.pas b/src/flexui/fui_ctls.pas index b7d5bfa..c573de8 100644 --- a/src/flexui/fui_ctls.pas +++ b/src/flexui/fui_ctls.pas @@ -70,11 +70,7 @@ type mFrameColor: array[0..ClrIdxMax] of TGxRGBA; mFrameTextColor: array[0..ClrIdxMax] of TGxRGBA; mFrameIconColor: array[0..ClrIdxMax] of TGxRGBA; - mDarken: array[0..ClrIdxMax] of Integer; // -1: none - - private - scis: TScissorSave; - scallowed: Boolean; + mDarken: array[0..ClrIdxMax] of Integer; // >255: none protected procedure updateStyle (); virtual; @@ -110,15 +106,11 @@ type procedure calcFullClientSize (); + protected + var savedClip: TGxRect; // valid only in `draw*()` calls //WARNING! do not call scissor functions outside `.draw*()` API! // set scissor to this rect (in local coords) - procedure setScissor (lx, ly, lw, lh: Integer); - // reset scissor to whole control - procedure resetScissor (fullArea: Boolean); inline; // "full area" means "with frame" - - // DO NOT USE! - // set scissor to this rect (in global coords) - procedure setScissorGLInternal (x, y, w, h: Integer); + procedure setScissor (lx, ly, lw, lh: Integer); // valid only in `draw*()` calls public actionCB: TActionCB; @@ -474,8 +466,7 @@ type protected mBoolVar: PBoolean; mChecked: Boolean; - mCheckedStr: AnsiString; - mUncheckedStr: AnsiString; + mIcon: TGxContext.TMarkIcon; mSwitchColor: array[0..ClrIdxMax] of TGxRGBA; protected @@ -553,6 +544,7 @@ procedure uiLayoutCtl (ctl: TUIControl); // ////////////////////////////////////////////////////////////////////////// // var fuiRenderScale: Single = 1.0; + uiContext: TGxContext = nil; implementation @@ -780,7 +772,9 @@ var ctl: TUIControl; begin processKills(); - gxBeginUIDraw(fuiRenderScale); + //if (uiContext = nil) then uiContext := TGxContext.Create(); + gxSetContext(uiContext, fuiRenderScale); + uiContext.resetClip(); try for f := 0 to High(uiTopList) do begin @@ -789,11 +783,11 @@ begin if (f <> High(uiTopList)) then begin cidx := ctl.getColorIndex; - if (ctl.mDarken[cidx] > 0) then darkenRect(ctl.x0, ctl.y0, ctl.width, ctl.height, ctl.mDarken[cidx]); + uiContext.darkenRect(ctl.x0, ctl.y0, ctl.width, ctl.height, ctl.mDarken[cidx]); end; end; finally - gxEndUIDraw(); + gxSetContext(nil); end; end; @@ -884,7 +878,7 @@ begin mX := 0; mY := 0; mWidth := 64; - mHeight := 8; + mHeight := uiContext.charHeight(' '); mFrameWidth := 0; mFrameHeight := 0; mEnabled := true; @@ -892,11 +886,10 @@ begin mChildren := nil; mFocused := nil; mEscClose := false; - scallowed := false; mDrawShadow := false; actionCB := nil; // layouter interface - //mDefSize := TLaySize.Create(64, 8); // default size + //mDefSize := TLaySize.Create(64, uiContext.charHeight(' ')); // default size mDefSize := TLaySize.Create(0, 0); // default size mMaxSize := TLaySize.Create(-1, -1); // maximum size mPadding := TLaySize.Create(0, 0); @@ -983,21 +976,21 @@ begin mFrameColor[ClrIdxActive] := root.get('frame-color', 'active', cst).asRGBADef(TGxRGBA.Create(255, 255, 255)); mFrameTextColor[ClrIdxActive] := root.get('frame-text-color', 'active', cst).asRGBADef(TGxRGBA.Create(255, 255, 255)); mFrameIconColor[ClrIdxActive] := root.get('frame-icon-color', 'active', cst).asRGBADef(TGxRGBA.Create(0, 255, 0)); - mDarken[ClrIdxActive] := root.get('darken', 'active', cst).asInt(-1); + mDarken[ClrIdxActive] := root.get('darken', 'active', cst).asInt(666); // disabled mBackColor[ClrIdxDisabled] := root.get('back-color', 'disabled', cst).asRGBADef(TGxRGBA.Create(0, 0, 128)); mTextColor[ClrIdxDisabled] := root.get('text-color', 'disabled', cst).asRGBADef(TGxRGBA.Create(127, 127, 127)); mFrameColor[ClrIdxDisabled] := root.get('frame-color', 'disabled', cst).asRGBADef(TGxRGBA.Create(127, 127, 127)); mFrameTextColor[ClrIdxDisabled] := root.get('frame-text-color', 'disabled', cst).asRGBADef(TGxRGBA.Create(127, 127, 127)); mFrameIconColor[ClrIdxDisabled] := root.get('frame-icon-color', 'disabled', cst).asRGBADef(TGxRGBA.Create(0, 127, 0)); - mDarken[ClrIdxDisabled] := root.get('darken', 'disabled', cst).asInt(-1); + mDarken[ClrIdxDisabled] := root.get('darken', 'disabled', cst).asInt(666); // inactive mBackColor[ClrIdxInactive] := root.get('back-color', 'inactive', cst).asRGBADef(TGxRGBA.Create(0, 0, 128)); mTextColor[ClrIdxInactive] := root.get('text-color', 'inactive', cst).asRGBADef(TGxRGBA.Create(255, 255, 255)); mFrameColor[ClrIdxInactive] := root.get('frame-color', 'inactive', cst).asRGBADef(TGxRGBA.Create(255, 255, 255)); mFrameTextColor[ClrIdxInactive] := root.get('frame-text-color', 'inactive', cst).asRGBADef(TGxRGBA.Create(255, 255, 255)); mFrameIconColor[ClrIdxInactive] := root.get('frame-icon-color', 'inactive', cst).asRGBADef(TGxRGBA.Create(0, 255, 0)); - mDarken[ClrIdxInactive] := root.get('darken', 'inactive', cst).asInt(-1); + mDarken[ClrIdxInactive] := root.get('darken', 'inactive', cst).asInt(666); end; @@ -1838,51 +1831,30 @@ end; // ////////////////////////////////////////////////////////////////////////// // -procedure TUIControl.setScissorGLInternal (x, y, w, h: Integer); -begin - if not scallowed then exit; - x := trunc(x*fuiRenderScale); - y := trunc(y*fuiRenderScale); - w := trunc(w*fuiRenderScale); - h := trunc(h*fuiRenderScale); - scis.combineRect(x, y, w, h); -end; - procedure TUIControl.setScissor (lx, ly, lw, lh: Integer); var gx, gy, wdt, hgt, cgx, cgy: Integer; begin - if not scallowed then exit; - - if not intersectRect(lx, ly, lw, lh, 0, 0, mWidth, mHeight) then + if (not intersectRect(lx, ly, lw, lh, 0, 0, mWidth, mHeight)) then begin - scis.combineRect(0, 0, 0, 0); + uiContext.clip := TGxRect.Create(0, 0, 0, 0); exit; end; getDrawRect(gx, gy, wdt, hgt); + toGlobal(lx, ly, cgx, cgy); - if not intersectRect(gx, gy, wdt, hgt, cgx, cgy, lw, lh) then + if (not intersectRect(gx, gy, wdt, hgt, cgx, cgy, lw, lh)) then begin - scis.combineRect(0, 0, 0, 0); + uiContext.clip := TGxRect.Create(0, 0, 0, 0); exit; end; - setScissorGLInternal(gx, gy, wdt, hgt); + uiContext.clip := savedClip; + uiContext.combineClip(TGxRect.Create(gx, gy, wdt, hgt)); + //uiContext.clip := TGxRect.Create(gx, gy, wdt, hgt); end; -procedure TUIControl.resetScissor (fullArea: Boolean); inline; -begin - if not scallowed then exit; - if (fullArea) then - begin - setScissor(0, 0, mWidth, mHeight); - end - else - begin - setScissor(mFrameWidth, mFrameHeight, mWidth-mFrameWidth*2, mHeight-mFrameHeight*2); - end; -end; // ////////////////////////////////////////////////////////////////////////// // @@ -1890,13 +1862,26 @@ procedure TUIControl.draw (); var f: Integer; gx, gy: Integer; + + procedure resetScissor (fullArea: Boolean); inline; + begin + uiContext.clip := savedClip; + if (fullArea) then + begin + setScissor(0, 0, mWidth, mHeight); + end + else + begin + setScissor(mFrameWidth, mFrameHeight, mWidth-mFrameWidth*2, mHeight-mFrameHeight*2); + end; + end; + begin - if (mWidth < 1) or (mHeight < 1) then exit; + if (mWidth < 1) or (mHeight < 1) or (uiContext = nil) or (not uiContext.active) then exit; toGlobal(0, 0, gx, gy); - scis.save(true); // scissoring enabled + savedClip := uiContext.clip; try - scallowed := true; resetScissor(true); // full area drawControl(gx, gy); resetScissor(false); // client area @@ -1904,8 +1889,7 @@ begin resetScissor(true); // full area drawControlPost(gx, gy); finally - scis.restore(); - scallowed := false; + uiContext.clip := savedClip; end; end; @@ -1917,11 +1901,12 @@ end; procedure TUIControl.drawControlPost (gx, gy: Integer); begin // shadow - if mDrawShadow and (mWidth > 0) and (mHeight > 0) then + if (mParent = nil) and (mDrawShadow) and (mWidth > 0) and (mHeight > 0) then begin - setScissorGLInternal(gx+8, gy+8, mWidth, mHeight); - darkenRect(gx+mWidth, gy+8, 8, mHeight, 128); - darkenRect(gx+8, gy+mHeight, mWidth-8, 8, 128); + //setScissorGLInternal(gx+8, gy+8, mWidth, mHeight); + uiContext.resetClip(); + uiContext.darkenRect(gx+mWidth, gy+8, 8, mHeight, 128); + uiContext.darkenRect(gx+8, gy+mHeight, mWidth-8, 8, 128); end; end; @@ -2061,11 +2046,14 @@ begin mFitToScreen := true; mFrameWidth := 8; mFrameHeight := 8; - if (mWidth < mFrameWidth*2+3*8) then mWidth := mFrameWidth*2+3*8; + if (mWidth < mFrameWidth*2+uiContext.iconWinWidth(TGxContext.TWinIcon.Close)) then mWidth := mFrameWidth*2+uiContext.iconWinWidth(TGxContext.TWinIcon.Close); if (mHeight < mFrameHeight*2) then mHeight := mFrameHeight*2; if (Length(mTitle) > 0) then begin - if (mWidth < Length(mTitle)*8+mFrameWidth*2+3*8) then mWidth := Length(mTitle)*8+mFrameWidth*2+3*8; + if (mWidth < uiContext.textWidth(mTitle)+mFrameWidth*2+uiContext.iconWinWidth(TGxContext.TWinIcon.Close)) then + begin + mWidth := uiContext.textWidth(mTitle)+mFrameWidth*2+uiContext.iconWinWidth(TGxContext.TWinIcon.Close); + end; end; mCanFocus := false; mDragScroll := TXMode.None; @@ -2126,54 +2114,61 @@ end; procedure TUITopWindow.drawControl (gx, gy: Integer); begin - fillRect(gx, gy, mWidth, mHeight, mBackColor[getColorIndex]); + uiContext.color := mBackColor[getColorIndex]; + uiContext.fillRect(gx, gy, mWidth, mHeight); end; procedure TUITopWindow.drawControlPost (gx, gy: Integer); var cidx: Integer; - tx, hgt, sbhgt: Integer; + tx, hgt, sbhgt, iwdt: Integer; begin cidx := getColorIndex; if (mDragScroll = TXMode.Drag) then begin - drawRectUI(gx+4, gy+4, mWidth-8, mHeight-8, mFrameColor[cidx]); + uiContext.color := mFrameColor[cidx]; + uiContext.rect(gx+4, gy+4, mWidth-8, mHeight-8); end else begin - drawRectUI(gx+3, gy+3, mWidth-6, mHeight-6, mFrameColor[cidx]); - drawRectUI(gx+5, gy+5, mWidth-10, mHeight-10, mFrameColor[cidx]); + uiContext.color := mFrameColor[cidx]; + uiContext.rect(gx+3, gy+3, mWidth-6, mHeight-6); + uiContext.rect(gx+5, gy+5, mWidth-10, mHeight-10); // vertical scroll bar hgt := mHeight-mFrameHeight*2; if (hgt > 0) and (mFullSize.h > hgt) then begin //writeln(mTitle, ': height=', mHeight-mFrameHeight*2, '; fullsize=', mFullSize.toString); sbhgt := mHeight-mFrameHeight*2+2; - fillRect(gx+mWidth-mFrameWidth+1, gy+7, mFrameWidth-3, sbhgt, mFrameColor[cidx]); + uiContext.fillRect(gx+mWidth-mFrameWidth+1, gy+7, mFrameWidth-3, sbhgt); hgt += mScrollY; if (hgt > mFullSize.h) then hgt := mFullSize.h; hgt := sbhgt*hgt div mFullSize.h; if (hgt > 0) then begin setScissor(mWidth-mFrameWidth+1, 7, mFrameWidth-3, sbhgt); - darkenRect(gx+mWidth-mFrameWidth+1, gy+7+hgt, mFrameWidth-3, sbhgt, 128); + uiContext.darkenRect(gx+mWidth-mFrameWidth+1, gy+7+hgt, mFrameWidth-3, sbhgt, 128); end; end; // frame icon - setScissor(mFrameWidth, 0, 3*8, 8); - fillRect(gx+mFrameWidth, gy, 3*8, 8, mBackColor[cidx]); - drawText8(gx+mFrameWidth, gy, '[ ]', mFrameColor[cidx]); - if mInClose then drawText8(gx+mFrameWidth+7, gy, '#', mFrameIconColor[cidx]) - else drawText8(gx+mFrameWidth+7, gy, '*', mFrameIconColor[cidx]); + iwdt := uiContext.iconWinWidth(TGxContext.TWinIcon.Close); + setScissor(mFrameWidth, 0, iwdt, 8); + uiContext.color := mBackColor[cidx]; + uiContext.fillRect(gx+mFrameWidth, gy, iwdt, 8); + uiContext.color := mFrameIconColor[cidx]; + uiContext.drawIconWin(TGxContext.TWinIcon.Close, gx+mFrameWidth, gy, mInClose); end; // title if (Length(mTitle) > 0) then begin - setScissor(mFrameWidth+3*8, 0, mWidth-mFrameWidth*2-3*8, 8); - tx := (gx+3*8)+((mWidth-3*8)-Length(mTitle)*8) div 2; - fillRect(tx-3, gy, Length(mTitle)*8+3+2, 8, mBackColor[cidx]); - drawText8(tx, gy, mTitle, mFrameTextColor[cidx]); + iwdt := uiContext.iconWinWidth(TGxContext.TWinIcon.Close); + setScissor(mFrameWidth+iwdt, 0, mWidth-mFrameWidth*2-iwdt, 8); + tx := (gx+iwdt)+((mWidth-iwdt)-uiContext.textWidth(mTitle)) div 2; + uiContext.color := mBackColor[cidx]; + uiContext.fillRect(tx-3, gy, uiContext.textWidth(mTitle)+3+2, 8); + uiContext.color := mFrameTextColor[cidx]; + uiContext.drawText(tx, gy, mTitle); end; // shadow inherited drawControlPost(gx, gy); @@ -2268,7 +2263,7 @@ begin if (ly < 8) then begin uiGrabCtl := self; - if (lx >= mFrameWidth) and (lx < mFrameWidth+3*8) then + if (lx >= mFrameWidth) and (lx < mFrameWidth+uiContext.iconWinWidth(TGxContext.TWinIcon.Close)) then begin //uiRemoveWindow(self); mWaitingClose := true; @@ -2314,7 +2309,7 @@ begin begin if mWaitingClose then begin - if (lx >= mFrameWidth) and (lx < mFrameWidth+3*8) then + if (lx >= mFrameWidth) and (lx < mFrameWidth+uiContext.iconWinWidth(TGxContext.TWinIcon.Close)) then begin if (not assigned(closeRequestCB)) or (closeRequestCB(self)) then begin @@ -2332,7 +2327,7 @@ begin begin if mWaitingClose then begin - mInClose := (lx >= mFrameWidth) and (lx < mFrameWidth+3*8); + mInClose := (lx >= mFrameWidth) and (lx < mFrameWidth+uiContext.iconWinWidth(TGxContext.TWinIcon.Close)); ev.eat(); exit; end; @@ -2368,7 +2363,7 @@ end; procedure TUIBox.setCaption (const acap: AnsiString); begin mCaption := acap; - mDefSize := TLaySize.Create(Length(mCaption)*8+3, 8); + mDefSize := TLaySize.Create(uiContext.textWidth(mCaption)+3, uiContext.textHeight(mCaption)); end; @@ -2423,23 +2418,30 @@ var xpos: Integer; begin cidx := getColorIndex; - fillRect(gx, gy, mWidth, mHeight, mBackColor[cidx]); + uiContext.color := mBackColor[cidx]; + uiContext.fillRect(gx, gy, mWidth, mHeight); if mHasFrame then begin // draw frame - drawRectUI(gx+3, gy+3, mWidth-6, mHeight-6, mFrameColor[cidx]); + uiContext.color := mFrameColor[cidx]; + uiContext.rect(gx+3, gy+3, mWidth-6, mHeight-6); end; // draw caption if (Length(mCaption) > 0) then begin if (mHAlign < 0) then xpos := 3 - else if (mHAlign > 0) then xpos := mWidth-mFrameWidth*2-Length(mCaption)*8 - else xpos := (mWidth-mFrameWidth*2-Length(mCaption)*8) div 2; + else if (mHAlign > 0) then xpos := mWidth-mFrameWidth*2-uiContext.textWidth(mCaption) + else xpos := (mWidth-mFrameWidth*2-uiContext.textWidth(mCaption)) div 2; xpos += gx+mFrameWidth; setScissor(mFrameWidth+1, 0, mWidth-mFrameWidth-2, 8); - if mHasFrame then fillRect(xpos-3, gy, Length(mCaption)*8+4, 8, mBackColor[cidx]); - drawText8(xpos, gy, mCaption, mFrameTextColor[cidx]); + if mHasFrame then + begin + uiContext.color := mBackColor[cidx]; + uiContext.fillRect(xpos-3, gy, uiContext.textWidth(mCaption)+4, 8); + end; + uiContext.color := mFrameTextColor[cidx]; + uiContext.drawText(xpos, gy, mCaption); end; end; @@ -2554,14 +2556,9 @@ var cidx: Integer; begin cidx := getColorIndex; - if mHoriz then - begin - drawHLine(gx, gy+(mHeight div 2), mWidth, mTextColor[cidx]); - end - else - begin - drawVLine(gx+(mWidth div 2), gy, mHeight, mTextColor[cidx]); - end; + uiContext.color := mTextColor[cidx]; + if mHoriz then uiContext.hline(gx, gy+(mHeight div 2), mWidth) + else uiContext.vline(gx+(mWidth div 2), gy, mHeight); end; @@ -2593,7 +2590,7 @@ begin mHoriz := true; // nobody cares mHeader := false; mLine := false; - mDefSize.h := 8; + mDefSize.h := uiContext.charHeight(' '); mCtl4Style := 'static'; end; @@ -2601,7 +2598,7 @@ end; procedure TUIStaticText.setText (const atext: AnsiString); begin mText := atext; - mDefSize := TLaySize.Create(Length(mText)*8, 8); + mDefSize := TLaySize.Create(uiContext.textWidth(mText), uiContext.textHeight(mText)); end; @@ -2639,29 +2636,29 @@ procedure TUIStaticText.drawControl (gx, gy: Integer); var xpos, ypos: Integer; cidx: Integer; - clr: TGxRGBA; begin cidx := getColorIndex; - fillRect(gx, gy, mWidth, mHeight, mBackColor[cidx]); + uiContext.color := mBackColor[cidx]; + uiContext.fillRect(gx, gy, mWidth, mHeight); if (mHAlign < 0) then xpos := 0 - else if (mHAlign > 0) then xpos := mWidth-Length(mText)*8 - else xpos := (mWidth-Length(mText)*8) div 2; + else if (mHAlign > 0) then xpos := mWidth-uiContext.textWidth(mText) + else xpos := (mWidth-uiContext.textWidth(mText)) div 2; if (Length(mText) > 0) then begin - if (mHeader) then clr := mFrameTextColor[cidx] else clr := mTextColor[cidx]; + if (mHeader) then uiContext.color := mFrameTextColor[cidx] else uiContext.color := mTextColor[cidx]; if (mVAlign < 0) then ypos := 0 - else if (mVAlign > 0) then ypos := mHeight-8 - else ypos := (mHeight-8) div 2; + else if (mVAlign > 0) then ypos := mHeight-uiContext.textHeight(mText) + else ypos := (mHeight-uiContext.textHeight(mText)) div 2; - drawText8(gx+xpos, gy+ypos, mText, clr); + uiContext.drawText(gx+xpos, gy+ypos, mText); end; if (mLine) then begin - if (mHeader) then clr := mFrameColor[cidx] else clr := mTextColor[cidx]; + if (mHeader) then uiContext.color := mFrameColor[cidx] else uiContext.color := mTextColor[cidx]; if (mVAlign < 0) then ypos := 0 else if (mVAlign > 0) then ypos := mHeight-1 @@ -2670,12 +2667,12 @@ begin if (Length(mText) = 0) then begin - drawHLine(gx, ypos, mWidth, clr); + uiContext.hline(gx, ypos, mWidth); end else begin - drawHLine(gx, ypos, xpos-1, clr); - drawHLine(gx+xpos+Length(mText)*8, ypos, mWidth, clr); + uiContext.hline(gx, ypos, xpos-1); + uiContext.hline(gx+xpos+uiContext.textWidth(mText), ypos, mWidth); end; end; end; @@ -2688,7 +2685,7 @@ begin mHAlign := -1; mVAlign := 0; mCanFocus := false; - mDefSize := TLaySize.Create(Length(mText)*8, 8); + mDefSize := TLaySize.Create(uiContext.textWidth(mText), uiContext.textHeight(mText)); mCtl4Style := 'label'; mLinkId := ''; end; @@ -2730,7 +2727,7 @@ begin if (mHotChar = #0) then begin mHotChar := s[f]; - mHotOfs := Length(mText)*8; + mHotOfs := Length(mText); end; mText += s[f]; end; @@ -2742,7 +2739,13 @@ begin Inc(f); end; end; - mDefSize := TLaySize.Create(Length(mText)*8, 8); + // fix hotchar offset + if (mHotChar <> #0) and (mHotOfs > 0) then + begin + mHotOfs := uiContext.textWidth(Copy(mText, 1, mHotOfs+1))-uiContext.charWidth(mText[mHotOfs+1]); + end; + // fix size + mDefSize := TLaySize.Create(uiContext.textWidth(mText), uiContext.textHeight(mText)); end; @@ -2776,22 +2779,25 @@ var cidx: Integer; begin cidx := getColorIndex; - fillRect(gx, gy, mWidth, mHeight, mBackColor[cidx]); + uiContext.color := mBackColor[cidx]; + uiContext.fillRect(gx, gy, mWidth, mHeight); if (Length(mText) > 0) then begin if (mHAlign < 0) then xpos := 0 - else if (mHAlign > 0) then xpos := mWidth-Length(mText)*8 - else xpos := (mWidth-Length(mText)*8) div 2; + else if (mHAlign > 0) then xpos := mWidth-uiContext.textWidth(mText) + else xpos := (mWidth-uiContext.textWidth(mText)) div 2; if (mVAlign < 0) then ypos := 0 - else if (mVAlign > 0) then ypos := mHeight-8 - else ypos := (mHeight-8) div 2; + else if (mVAlign > 0) then ypos := mHeight-uiContext.textHeight(mText) + else ypos := (mHeight-uiContext.textHeight(mText)) div 2; - drawText8(gx+xpos, gy+ypos, mText, mTextColor[cidx]); + uiContext.color := mTextColor[cidx]; + uiContext.drawText(gx+xpos, gy+ypos, mText); if (Length(mLinkId) > 0) and (mHotChar <> #0) and (mHotChar <> ' ') then begin - drawText8(gx+xpos+8+mHotOfs, gy+ypos, mHotChar, mHotColor[cidx]); + uiContext.color := mHotColor[cidx]; + uiContext.drawChar(gx+xpos+mHotOfs, gy+ypos, mHotChar); end; end; end; @@ -2848,7 +2854,7 @@ begin mHAlign := -1; mVAlign := 0; mCanFocus := true; - mDefSize := TLaySize.Create(Length(mText)*8+8, 10); + mDefSize := TLaySize.Create(uiContext.textWidth(mText)+8*2, uiContext.textHeight(mText)+2); mCtl4Style := 'button'; end; @@ -2856,7 +2862,7 @@ end; procedure TUIButton.setText (const s: AnsiString); begin inherited setText(s); - mDefSize := TLaySize.Create(Length(mText)*8+8*2, 10); + mDefSize := TLaySize.Create(uiContext.textWidth(mText)+8*2, uiContext.textHeight(mText)+2); end; @@ -2867,24 +2873,30 @@ var begin cidx := getColorIndex; - fillRect(gx+1, gy, mWidth-2, mHeight, mBackColor[cidx]); - fillRect(gx, gy+1, 1, mHeight-2, mBackColor[cidx]); - fillRect(gx+mWidth-1, gy+1, 1, mHeight-2, mBackColor[cidx]); + uiContext.color := mBackColor[cidx]; + uiContext.fillRect(gx+1, gy, mWidth-2, mHeight); + uiContext.fillRect(gx, gy+1, 1, mHeight-2); + uiContext.fillRect(gx+mWidth-1, gy+1, 1, mHeight-2); if (Length(mText) > 0) then begin if (mHAlign < 0) then xpos := 0 - else if (mHAlign > 0) then xpos := mWidth-Length(mText)*8 - else xpos := (mWidth-Length(mText)*8) div 2; + else if (mHAlign > 0) then xpos := mWidth-uiContext.textWidth(mText) + else xpos := (mWidth-uiContext.textWidth(mText)) div 2; if (mVAlign < 0) then ypos := 0 - else if (mVAlign > 0) then ypos := mHeight-8 - else ypos := (mHeight-8) div 2; + else if (mVAlign > 0) then ypos := mHeight-uiContext.textHeight(mText) + else ypos := (mHeight-uiContext.textHeight(mText)) div 2; setScissor(8, 0, mWidth-16, mHeight); - drawText8(gx+xpos+8, gy+ypos, mText, mTextColor[cidx]); + uiContext.color := mTextColor[cidx]; + uiContext.drawText(gx+xpos+8, gy+ypos, mText); - if (mHotChar <> #0) and (mHotChar <> ' ') then drawText8(gx+xpos+8+mHotOfs, gy+ypos, mHotChar, mHotColor[cidx]); + if (mHotChar <> #0) and (mHotChar <> ' ') then + begin + uiContext.color := mHotColor[cidx]; + uiContext.drawChar(gx+xpos+8+mHotOfs, gy+ypos, mHotChar); + end; end; end; @@ -2930,7 +2942,8 @@ begin mHAlign := -1; mVAlign := 0; mCanFocus := true; - mDefSize := TLaySize.Create(Length(mText)*8+8*3, 8); + mIcon := TGxContext.TMarkIcon.Checkbox; + mDefSize := TLaySize.Create(uiContext.textWidth(mText)+3+uiContext.iconMarkWidth(mIcon), uiContext.iconMarkHeight(mIcon)); mCtl4Style := 'switchbox'; mChecked := false; mBoolVar := @mChecked; @@ -2952,7 +2965,7 @@ end; procedure TUISwitchBox.setText (const s: AnsiString); begin inherited setText(s); - mDefSize := TLaySize.Create(Length(mText)*8+8*3, 8); + mDefSize := TLaySize.Create(uiContext.textWidth(mText)+3+uiContext.iconMarkWidth(mIcon), uiContext.iconMarkHeight(mIcon)); end; @@ -2993,37 +3006,31 @@ begin cidx := getColorIndex; if (mHAlign < 0) then xpos := 0 - else if (mHAlign > 0) then xpos := mWidth-(Length(mText)+4)*8 - else xpos := (mWidth-(Length(mText)+4)*8) div 2; + else if (mHAlign > 0) then xpos := mWidth-(uiContext.textWidth(mText)+3+uiContext.iconMarkWidth(mIcon)) + else xpos := (mWidth-(uiContext.textWidth(mText)+3+uiContext.iconMarkWidth(mIcon))) div 2; if (mVAlign < 0) then ypos := 0 - else if (mVAlign > 0) then ypos := mHeight-8 - else ypos := (mHeight-8) div 2; + else if (mVAlign > 0) then ypos := mHeight-uiContext.iconMarkHeight(mIcon) + else ypos := (mHeight-uiContext.iconMarkHeight(mIcon)) div 2; + uiContext.color := mBackColor[cidx]; + uiContext.fillRect(gx, gy, mWidth, mHeight); - fillRect(gx, gy, mWidth, mHeight, mBackColor[cidx]); + uiContext.color := mSwitchColor[cidx]; + uiContext.drawIconMark(mIcon, gx, gy, checked); - if (checked) then - begin - if (Length(mCheckedStr) <> 3) or (mCheckedStr[2] <> '*') then - begin - drawText8(gx+xpos, gy+ypos, mCheckedStr, mSwitchColor[cidx]); - end - else - begin - drawText8(gx+xpos, gy+ypos, mCheckedStr[1], mSwitchColor[cidx]); - drawText8(gx+xpos+2*8, gy+ypos, mCheckedStr[3], mSwitchColor[cidx]); - drawText8(gx+xpos+7, gy+ypos, '*', mSwitchColor[cidx]); - end; - end - else - begin - drawText8(gx+xpos, gy+ypos, mUncheckedStr, mSwitchColor[cidx]); - end; + if (mVAlign < 0) then ypos := 0 + else if (mVAlign > 0) then ypos := mHeight-uiContext.textHeight(mText) + else ypos := (mHeight-uiContext.textHeight(mText)) div 2; - drawText8(gx+xpos+8*3, gy+ypos, mText, mTextColor[cidx]); + uiContext.color := mTextColor[cidx]; + uiContext.drawText(gx+xpos+3+uiContext.iconMarkWidth(mIcon), gy+ypos, mText); - if (mHotChar <> #0) and (mHotChar <> ' ') then drawText8(gx+xpos+8*3+mHotOfs, gy+ypos, mHotChar, mHotColor[cidx]); + if (mHotChar <> #0) and (mHotChar <> ' ') then + begin + uiContext.color := mHotColor[cidx]; + uiContext.drawChar(gx+xpos+3+uiContext.iconMarkWidth(mIcon)+mHotOfs, gy+ypos, mHotChar); + end; end; @@ -3067,8 +3074,8 @@ begin inherited; mChecked := false; mBoolVar := @mChecked; - mCheckedStr := '[x]'; - mUncheckedStr := '[ ]'; + mIcon := TGxContext.TMarkIcon.Checkbox; + setText(''); end; @@ -3097,9 +3104,9 @@ begin inherited; mChecked := false; mBoolVar := @mChecked; - mCheckedStr := '(*)'; - mUncheckedStr := '( )'; mRadioGroup := ''; + mIcon := TGxContext.TMarkIcon.Radiobox; + setText(''); end; @@ -3164,4 +3171,6 @@ initialization registerCtlClass(TUIButton, 'button'); registerCtlClass(TUICheckBox, 'checkbox'); registerCtlClass(TUIRadioBox, 'radiobox'); + + uiContext := TGxContext.Create(); end. diff --git a/src/flexui/fui_gfx_gl.pas b/src/flexui/fui_gfx_gl.pas index 4a2e5bf..b0ccd22 100644 --- a/src/flexui/fui_gfx_gl.pas +++ b/src/flexui/fui_gfx_gl.pas @@ -27,58 +27,112 @@ uses // ////////////////////////////////////////////////////////////////////////// // -// setup 2D OpenGL mode; will be called automatically in `glInit()` -procedure oglSetup2D (winWidth, winHeight: Integer; upsideDown: Boolean=false); - -// the following calls MUST be paired AT ALL COSTS! -procedure gxBeginUIDraw (scale: Single=1.0); -procedure gxEndUIDraw (); +type + TGxFont = class + protected + mName: AnsiString; + mHeight: Integer; + mBaseLine: Integer; + public + function charWidth (const ch: AnsiChar): Integer; virtual; abstract; + function textWidth (const s: AnsiString): Integer; virtual; abstract; -type - TScissorSave = record public - wassc: Boolean; - scxywh: packed array[0..3] of GLint; + property name: AnsiString read mName; + property height: Integer read mHeight; + property baseLine: Integer read mBaseLine; + end; + TGxContext = class public + type + TMarkIcon = ( + Checkbox, + Radiobox + ); + + type + TWinIcon = ( + Close + ); + + protected + mActive: Boolean; + mColor: TGxRGBA; + mFont: TGxFont; + // for active contexts + mScaled: Boolean; + mScale: Single; + mClipRect: TGxRect; + mClipOfs: TGxOfs; + + protected + function getFont (): AnsiString; + procedure setFont (const aname: AnsiString); + + procedure onActivate (); + procedure onDeactivate (); + + procedure setColor (const clr: TGxRGBA); + + procedure realizeClip (); // setup scissoring + + procedure setClipOfs (const aofs: TGxOfs); + procedure setClipRect (const aclip: TGxRect); public - procedure save (enableScissoring: Boolean); - procedure restore (); + constructor Create (); + destructor Destroy (); override; - // set new scissor rect, bounded by the saved scissor rect - procedure combineRect (x, y, w, h: Integer); + procedure line (x1, y1, x2, y2: Integer); + procedure hline (x, y, len: Integer); + procedure vline (x, y, len: Integer); + procedure rect (x, y, w, h: Integer); + procedure fillRect (x, y, w, h: Integer); + procedure darkenRect (x, y, w, h: Integer; a: Integer); + + function charWidth (const ch: AnsiChar): Integer; + function charHeight (const ch: AnsiChar): Integer; + function textWidth (const s: AnsiString): Integer; + function textHeight (const s: AnsiString): Integer; + function drawChar (x, y: Integer; const ch: AnsiChar): Integer; // returns char width + function drawText (x, y: Integer; const s: AnsiString): Integer; // returns text width + + function iconMarkWidth (ic: TMarkIcon): Integer; + function iconMarkHeight (ic: TMarkIcon): Integer; + procedure drawIconMark (ic: TMarkIcon; x, y: Integer; marked: Boolean); + + function iconWinWidth (ic: TWinIcon): Integer; + function iconWinHeight (ic: TWinIcon): Integer; + procedure drawIconWin (ic: TWinIcon; x, y: Integer; pressed: Boolean); + + procedure resetClip (); + + function setOffset (constref aofs: TGxOfs): TGxOfs; // returns previous offset + function setClip (constref aclip: TGxRect): TGxRect; // returns previous clip + + function combineClip (constref aclip: TGxRect): TGxRect; // returns previous clip + + public + property active: Boolean read mActive; + property color: TGxRGBA read mColor write setColor; + property font: AnsiString read getFont write setFont; + property offset: TGxOfs read mClipOfs write setClipOfs; + property clip: TGxRect read mClipRect write setClipRect; // clipping is unaffected by offset end; +// set active context; `ctx` can be `nil` +procedure gxSetContext (ctx: TGxContext; ascale: Single=1.0); + + +// setup 2D OpenGL mode; will be called automatically in `glInit()` +procedure oglSetup2D (winWidth, winHeight: Integer; upsideDown: Boolean=false); + procedure oglDrawCursor (); procedure oglDrawCursorAt (msX, msY: Integer); -function setupGLColor (r, g, b, a: Integer): Boolean; -function setupGLColor (constref clr: TGxRGBA): Boolean; -function isScaled (): Boolean; - -function textWidth6 (const s: AnsiString): Integer; -function textWidth8 (const s: AnsiString): Integer; -// return width (including last empty pixel) -function drawTextInternal (wdt, x, y: Integer; const s: AnsiString; constref clr: TGxRGBA; tid: GLuint; constref fontwdt: array of Byte; prop: Boolean): Integer; -procedure drawLine (x1, y1, x2, y2: Integer; constref clr: TGxRGBA); -procedure drawVLine (x, y, len: Integer; constref clr: TGxRGBA); -procedure drawHLine (x, y, len: Integer; constref clr: TGxRGBA); -procedure drawRect (x, y, w, h: Integer; constref clr: TGxRGBA); -procedure drawRectUI (x, y, w, h: Integer; constref clr: TGxRGBA); -procedure darkenRect (x, y, w, h: Integer; a: Integer); -procedure fillRect (x, y, w, h: Integer; constref clr: TGxRGBA); -function drawText6 (x, y: Integer; const s: AnsiString; constref clr: TGxRGBA): Integer; -function drawText8 (x, y: Integer; const s: AnsiString; constref clr: TGxRGBA): Integer; -function drawText6Prop (x, y: Integer; const s: AnsiString; constref clr: TGxRGBA): Integer; -function drawText8Prop (x, y: Integer; const s: AnsiString; constref clr: TGxRGBA): Integer; -// x-centered at `x` -function drawText6XC (x, y: Integer; const s: AnsiString; constref clr: TGxRGBA): Integer; -function drawText8XC (x, y: Integer; const s: AnsiString; constref clr: TGxRGBA): Integer; -function drawText6PropXC (x, y: Integer; const s: AnsiString; constref clr: TGxRGBA): Integer; -function drawText8PropXC (x, y: Integer; const s: AnsiString; constref clr: TGxRGBA): Integer; // ////////////////////////////////////////////////////////////////////////// // @@ -90,559 +144,427 @@ implementation // ////////////////////////////////////////////////////////////////////////// // -procedure oglSetup2D (winWidth, winHeight: Integer; upsideDown: Boolean=false); +//TODO: OpenGL framebuffers and shaders state +type + TSavedGLState = record + public + glmatmode: GLint; + gltextbinding: GLint; + //oldprg: GLint; + //oldfbr, oldfbw: GLint; + glvport: packed array [0..3] of GLint; + saved: Boolean; + + public + constructor Create (dosave: Boolean); + procedure save (); + procedure restore (); + end; + +constructor TSavedGLState.Create (dosave: Boolean); begin - glViewport(0, 0, winWidth, winHeight); + FillChar(self, sizeof(self), 0); + if (dosave) then save(); +end; - glDisable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDisable(GL_LINE_SMOOTH); - glDisable(GL_POINT_SMOOTH); - glDisable(GL_DEPTH_TEST); - glDisable(GL_TEXTURE_2D); - glDisable(GL_LIGHTING); - glDisable(GL_DITHER); - glDisable(GL_STENCIL_TEST); - glDisable(GL_SCISSOR_TEST); - glDisable(GL_CULL_FACE); +procedure TSavedGLState.save (); +begin + if (saved) then raise Exception.Create('cannot save into already saved OpenGL state'); + glGetIntegerv(GL_MATRIX_MODE, @glmatmode); + glGetIntegerv(GL_TEXTURE_BINDING_2D, @gltextbinding); + glGetIntegerv(GL_VIEWPORT, @glvport[0]); + //glGetIntegerv(GL_CURRENT_PROGRAM, &oldprg); + //glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &oldfbr); + //glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldfbw); + glMatrixMode(GL_PROJECTION); glPushMatrix(); + glMatrixMode(GL_MODELVIEW); glPushMatrix(); + glMatrixMode(GL_TEXTURE); glPushMatrix(); + glMatrixMode(GL_COLOR); glPushMatrix(); + glPushAttrib({GL_ENABLE_BIT|GL_COLOR_BUFFER_BIT|GL_CURRENT_BIT}GL_ALL_ATTRIB_BITS); // let's play safe + saved := true; +end; - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - if (upsideDown) then +procedure TSavedGLState.restore (); +begin + if (not saved) then raise Exception.Create('cannot restore unsaved OpenGL state'); + glPopAttrib({GL_ENABLE_BIT}); + glMatrixMode(GL_PROJECTION); glPopMatrix(); + glMatrixMode(GL_MODELVIEW); glPopMatrix(); + glMatrixMode(GL_TEXTURE); glPopMatrix(); + glMatrixMode(GL_COLOR); glPopMatrix(); + glMatrixMode(glmatmode); + //if (glHasFunc!"glBindFramebufferEXT") glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, oldfbr); + //if (glHasFunc!"glBindFramebufferEXT") glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, oldfbw); + glBindTexture(GL_TEXTURE_2D, gltextbinding); + //if (glHasFunc!"glUseProgram") glUseProgram(oldprg); + glViewport(glvport[0], glvport[1], glvport[2], glvport[3]); + saved := false; +end; + + +var + curCtx: TGxContext = nil; + savedGLState: TSavedGLState; + + +// ////////////////////////////////////////////////////////////////////////// // +// set active context; `ctx` can be `nil` +procedure gxSetContext (ctx: TGxContext; ascale: Single=1.0); +begin + if (savedGLState.saved) then savedGLState.restore(); + + if (curCtx <> nil) then begin - glOrtho(0, winWidth, 0, winHeight, -1, 1); // set origin to bottom left - end - else + curCtx.onDeactivate(); + curCtx.mActive := false; + end; + + curCtx := ctx; + if (ctx <> nil) then begin - glOrtho(0, winWidth, winHeight, 0, -1, 1); // set origin to top left + ctx.mActive := true; + savedGLState.save(); + oglSetup2D(fuiScrWdt, fuiScrHgt); + glScalef(ascale, ascale, 1.0); + ctx.mScaled := (ascale <> 1.0); + ctx.mScale := ascale; + ctx.onActivate(); end; +end; - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glClearColor(0, 0, 0, 0); - glColor4f(1, 1, 1, 1); -end; +// ////////////////////////////////////////////////////////////////////////// // +type + TScissorSave = record + public + wassc: Boolean; + scxywh: packed array[0..3] of GLint; + + public + + public + procedure save (enableScissoring: Boolean); + procedure restore (); + + // set new scissor rect, bounded by the saved scissor rect + procedure combineRect (x, y, w, h: Integer); + end; -procedure gxBeginUIDraw (scale: Single=1.0); +procedure TScissorSave.save (enableScissoring: Boolean); begin - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - glScalef(scale, scale, 1); + wassc := (glIsEnabled(GL_SCISSOR_TEST) <> 0); + if wassc then glGetIntegerv(GL_SCISSOR_BOX, @scxywh[0]) else glGetIntegerv(GL_VIEWPORT, @scxywh[0]); + //conwritefln('(%d,%d)-(%d,%d)', [scxywh[0], scxywh[1], scxywh[2], scxywh[3]]); + if enableScissoring and (not wassc) then glEnable(GL_SCISSOR_TEST); end; -procedure gxEndUIDraw (); +procedure TScissorSave.restore (); begin - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); + glScissor(scxywh[0], scxywh[1], scxywh[2], scxywh[3]); + if wassc then glEnable(GL_SCISSOR_TEST) else glDisable(GL_SCISSOR_TEST); +end; + +procedure TScissorSave.combineRect (x, y, w, h: Integer); +//var ox, oy, ow, oh: Integer; +begin + if (w < 1) or (h < 1) then begin glScissor(0, 0, 0, 0); exit; end; + y := fuiScrHgt-(y+h); + //ox := x; oy := y; ow := w; oh := h; + if not intersectRect(x, y, w, h, scxywh[0], scxywh[1], scxywh[2], scxywh[3]) then + begin + //writeln('oops: COMBINE: old=(', ox, ',', oy, ')-(', ox+ow-1, ',', oy+oh-1, '); sci: (', scxywh[0], ',', scxywh[1], ')-(', scxywh[0]+scxywh[2]-1, ',', scxywh[1]+scxywh[3]-1, ')'); + //writeln('oops: COMBINE: oldx=<', ox, '-', ox+ow-1, '>; oldy=<', oy, ',', oy+oh-1, '> : scix=<', scxywh[0], '-', scxywh[0]+scxywh[2]-1, '>; sciy=<', scxywh[1], '-', scxywh[1]+scxywh[3]-1, '>'); + glScissor(0, 0, 0, 0); + end + else + begin + glScissor(x, y, w, h); + end; end; // ////////////////////////////////////////////////////////////////////////// // -// cursor (hi, Death Track!) -const curTexWidth = 32; -const curTexHeight = 32; -const curWidth = 17; -const curHeight = 23; - -const cursorImg: array[0..curWidth*curHeight-1] of Byte = ( - 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 3,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 3,3,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0, - 3,3,4,2,2,0,0,0,0,0,0,0,0,0,0,0,0, - 3,3,4,4,2,2,0,0,0,0,0,0,0,0,0,0,0, - 3,3,4,4,4,2,2,0,0,0,0,0,0,0,0,0,0, - 3,3,4,4,4,4,2,2,0,0,0,0,0,0,0,0,0, - 3,3,4,4,4,5,6,2,2,0,0,0,0,0,0,0,0, - 3,3,4,4,5,6,7,5,2,2,0,0,0,0,0,0,0, - 3,3,4,5,6,7,5,4,5,2,2,0,0,0,0,0,0, - 3,3,5,6,7,5,4,5,6,7,2,2,0,0,0,0,0, - 3,3,6,7,5,4,5,6,7,7,7,2,2,0,0,0,0, - 3,3,7,5,4,5,6,7,7,7,7,7,2,2,0,0,0, - 3,3,5,4,5,6,8,8,8,8,8,8,8,8,2,0,0, - 3,3,4,5,6,3,8,8,8,8,8,8,8,8,8,0,0, - 3,3,5,6,3,3,0,0,0,0,0,0,0,0,0,0,0, - 3,3,6,3,3,0,0,0,0,0,0,0,0,0,0,0,0, - 3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0, - 3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -); -const cursorPal: array[0..9*4-1] of Byte = ( - 0, 0, 0, 0, - 0, 0, 0,163, - 85,255,255,255, - 85, 85,255,255, - 255, 85, 85,255, - 170, 0,170,255, - 85, 85, 85,255, - 0, 0, 0,255, - 0, 0,170,255 -); +{$INCLUDE fui_gfx_gl_fonts.inc} +type + TGxBmpFont = class(TGxFont) + private + mTexId: GLuint; // OpenGL texture id + mWidth: Integer; // <=0: proportional + mFontBmp: PByte; + mFontWdt: PByte; + mFreeFontWdt: Boolean; + + protected + procedure oglCreateTexture (); + procedure oglDestroyTexture (); + + 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); + destructor Destroy (); override; + + function charWidth (const ch: AnsiChar): Integer; override; + function textWidth (const s: AnsiString): Integer; override; + end; -var - curtexid: GLuint = 0; -procedure createCursorTexture (); +constructor TGxBmpFont.Create (const aname: AnsiString; awdt, ahgt: Integer; const afont: PByte; const awdtable: PByte=nil); var - tex, tpp: PByte; c: Integer; - x, y: Integer; begin - if (curtexid <> 0) then exit; //begin glDeleteTextures(1, @curtexid); curtexid := 0; end; - - GetMem(tex, curTexWidth*curTexHeight*4); - try - FillChar(tex^, curTexWidth*curTexHeight*4, 0); + 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 + 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; + end + else + begin + if (awdtable = nil) then raise Exception.Create('internal error in font creation'); + awdt := 0; + mFontWdt := awdtable; + end; + mName := aname; + mWidth := awdt; + mHeight := ahgt; + mBaseLine := ahgt-1; //FIXME + mFontBmp := afont; + mTexId := 0; +end; - // draw shadow - for y := 0 to curHeight-1 do - begin - for x := 0 to curWidth-1 do - begin - if (cursorImg[y*curWidth+x] <> 0) then - begin - c := 1*4; - tpp := tex+((y+1)*(curTexWidth*4)+(x+3)*4); - tpp^ := cursorPal[c+0]; Inc(tpp); - tpp^ := cursorPal[c+1]; Inc(tpp); - tpp^ := cursorPal[c+2]; Inc(tpp); - tpp^ := cursorPal[c+3]; Inc(tpp); - tpp^ := cursorPal[c+0]; Inc(tpp); - tpp^ := cursorPal[c+1]; Inc(tpp); - tpp^ := cursorPal[c+2]; Inc(tpp); - tpp^ := cursorPal[c+3]; Inc(tpp); - end; - end; - end; - // draw cursor - for y := 0 to curHeight-1 do - begin - for x := 0 to curWidth-1 do - begin - c := cursorImg[y*curWidth+x]*4; - if (c <> 0) then - begin - tpp := tex+(y*(curTexWidth*4)+x*4); - tpp^ := cursorPal[c+0]; Inc(tpp); - tpp^ := cursorPal[c+1]; Inc(tpp); - tpp^ := cursorPal[c+2]; Inc(tpp); - tpp^ := cursorPal[c+3]; Inc(tpp); - end; - end; - end; +destructor TGxBmpFont.Destroy (); +begin + if (mFreeFontWdt) and (mFontWdt <> nil) then FreeMem(mFontWdt); + mName := ''; + mWidth := 0; + mHeight := 0; + mBaseLine := 0; + mFontBmp := nil; + mFontWdt := nil; + mFreeFontWdt := false; + mTexId := 0; + inherited; +end; - glGenTextures(1, @curtexid); - if (curtexid = 0) then raise Exception.Create('can''t create cursor texture'); - glBindTexture(GL_TEXTURE_2D, curtexid); - 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); +procedure TGxBmpFont.oglCreateTexture (); +begin + mTexId := createFontTexture(mFontBmp, mFontWdt, (mWidth <= 0)); +end; - //GLfloat[4] bclr = 0.0; - //glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, bclr.ptr); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, curTexWidth, curTexHeight, 0, GL_RGBA{gltt}, GL_UNSIGNED_BYTE, tex); - glFlush(); - finally - FreeMem(tex); +procedure TGxBmpFont.oglDestroyTexture (); +begin + if (mTexId <> 0) then + begin + glDeleteTextures(1, @mTexId); + mTexId := 0; end; end; -procedure oglDrawCursorAt (msX, msY: Integer); + +function TGxBmpFont.charWidth (const ch: AnsiChar): Integer; begin - //if (curtexid = 0) then createCursorTexture() else glBindTexture(GL_TEXTURE_2D, curtexid); - glBindTexture(GL_TEXTURE_2D, curtexid); - // blend it - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_TEXTURE_2D); - glDisable(GL_STENCIL_TEST); - glDisable(GL_SCISSOR_TEST); - glDisable(GL_LIGHTING); - glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - // color and opacity - glColor4f(1, 1, 1, 0.9); - //Dec(msX, 2); - glBegin(GL_QUADS); - glTexCoord2f(0.0, 0.0); glVertex2i(msX, msY); // top-left - glTexCoord2f(1.0, 0.0); glVertex2i(msX+curTexWidth, msY); // top-right - glTexCoord2f(1.0, 1.0); glVertex2i(msX+curTexWidth, msY+curTexHeight); // bottom-right - glTexCoord2f(0.0, 1.0); glVertex2i(msX, msY+curTexHeight); // bottom-left - glEnd(); - //Inc(msX, 2); - glDisable(GL_BLEND); - glDisable(GL_TEXTURE_2D); - glColor4f(1, 1, 1, 1); - glBindTexture(GL_TEXTURE_2D, 0); + result := (mFontWdt[Byte(ch)] and $0f); end; -procedure oglDrawCursor (); begin oglDrawCursorAt(fuiMouseX, fuiMouseY); end; + +function TGxBmpFont.textWidth (const s: AnsiString): Integer; +var + ch: AnsiChar; +begin + if (Length(s) > 0) then + begin + result := -1; + for ch in s do result += (mFontWdt[Byte(ch)] and $0f)+1; + end + else + begin + result := 0; + end; +end; -// ////////////////////////////////////////////////////////////////////////// // -// fonts -const kgiFont6: array[0..256*8-1] of Byte = ( -$00,$00,$00,$00,$00,$00,$00,$00,$3c,$42,$a5,$81,$a5,$99,$42,$3c,$3c,$7e,$db,$ff,$ff,$db,$66,$3c,$6c,$fe, -$fe,$fe,$7c,$38,$10,$00,$10,$38,$7c,$fe,$7c,$38,$10,$00,$10,$38,$54,$fe,$54,$10,$38,$00,$10,$38,$7c,$fe, -$fe,$10,$38,$00,$00,$00,$00,$30,$30,$00,$00,$00,$ff,$ff,$ff,$e7,$e7,$ff,$ff,$ff,$38,$44,$82,$82,$82,$44, -$38,$00,$c7,$bb,$7d,$7d,$7d,$bb,$c7,$ff,$0f,$03,$05,$79,$88,$88,$88,$70,$38,$44,$44,$44,$38,$10,$7c,$10, -$30,$28,$24,$24,$28,$20,$e0,$c0,$3c,$24,$3c,$24,$24,$e4,$dc,$18,$10,$54,$38,$ee,$38,$54,$10,$00,$10,$10, -$10,$7c,$10,$10,$10,$10,$10,$10,$10,$ff,$00,$00,$00,$00,$00,$00,$00,$ff,$10,$10,$10,$10,$10,$10,$10,$f0, -$10,$10,$10,$10,$10,$10,$10,$1f,$10,$10,$10,$10,$10,$10,$10,$ff,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10, -$10,$10,$00,$00,$00,$ff,$00,$00,$00,$00,$00,$00,$00,$1f,$10,$10,$10,$10,$00,$00,$00,$f0,$10,$10,$10,$10, -$10,$10,$10,$1f,$00,$00,$00,$00,$10,$10,$10,$f0,$00,$00,$00,$00,$81,$42,$24,$18,$18,$24,$42,$81,$01,$02, -$04,$08,$10,$20,$40,$80,$80,$40,$20,$10,$08,$04,$02,$01,$00,$10,$10,$ff,$10,$10,$00,$00,$00,$00,$00,$00, -$00,$00,$00,$00,$20,$20,$20,$20,$00,$00,$20,$00,$50,$50,$50,$00,$00,$00,$00,$00,$50,$50,$f8,$50,$f8,$50, -$50,$00,$20,$78,$a0,$70,$28,$f0,$20,$00,$c0,$c8,$10,$20,$40,$98,$18,$00,$40,$a0,$40,$a8,$90,$98,$60,$00, -$10,$20,$40,$00,$00,$00,$00,$00,$10,$20,$40,$40,$40,$20,$10,$00,$40,$20,$10,$10,$10,$20,$40,$00,$88,$50, -$20,$f8,$20,$50,$88,$00,$00,$20,$20,$f8,$20,$20,$00,$00,$00,$00,$00,$00,$00,$20,$20,$40,$00,$00,$00,$78, -$00,$00,$00,$00,$00,$00,$00,$00,$00,$60,$60,$00,$00,$00,$08,$10,$20,$40,$80,$00,$70,$88,$98,$a8,$c8,$88, -$70,$00,$20,$60,$a0,$20,$20,$20,$f8,$00,$70,$88,$08,$10,$60,$80,$f8,$00,$70,$88,$08,$30,$08,$88,$70,$00, -$10,$30,$50,$90,$f8,$10,$10,$00,$f8,$80,$e0,$10,$08,$10,$e0,$00,$30,$40,$80,$f0,$88,$88,$70,$00,$f8,$88, -$10,$20,$20,$20,$20,$00,$70,$88,$88,$70,$88,$88,$70,$00,$70,$88,$88,$78,$08,$10,$60,$00,$00,$00,$20,$00, -$00,$20,$00,$00,$00,$00,$20,$00,$00,$20,$20,$40,$18,$30,$60,$c0,$60,$30,$18,$00,$00,$00,$f8,$00,$f8,$00, -$00,$00,$c0,$60,$30,$18,$30,$60,$c0,$00,$70,$88,$08,$10,$20,$00,$20,$00,$70,$88,$08,$68,$a8,$a8,$70,$00, -$20,$50,$88,$88,$f8,$88,$88,$00,$f0,$48,$48,$70,$48,$48,$f0,$00,$30,$48,$80,$80,$80,$48,$30,$00,$e0,$50, -$48,$48,$48,$50,$e0,$00,$f8,$80,$80,$f0,$80,$80,$f8,$00,$f8,$80,$80,$f0,$80,$80,$80,$00,$70,$88,$80,$b8, -$88,$88,$70,$00,$88,$88,$88,$f8,$88,$88,$88,$00,$70,$20,$20,$20,$20,$20,$70,$00,$38,$10,$10,$10,$90,$90, -$60,$00,$88,$90,$a0,$c0,$a0,$90,$88,$00,$80,$80,$80,$80,$80,$80,$f8,$00,$88,$d8,$a8,$a8,$88,$88,$88,$00, -$88,$c8,$c8,$a8,$98,$98,$88,$00,$70,$88,$88,$88,$88,$88,$70,$00,$f0,$88,$88,$f0,$80,$80,$80,$00,$70,$88, -$88,$88,$a8,$90,$68,$00,$f0,$88,$88,$f0,$a0,$90,$88,$00,$70,$88,$80,$70,$08,$88,$70,$00,$f8,$20,$20,$20, -$20,$20,$20,$00,$88,$88,$88,$88,$88,$88,$70,$00,$88,$88,$88,$88,$50,$50,$20,$00,$88,$88,$88,$a8,$a8,$d8, -$88,$00,$88,$88,$50,$20,$50,$88,$88,$00,$88,$88,$88,$70,$20,$20,$20,$00,$f8,$08,$10,$20,$40,$80,$f8,$00, -$70,$40,$40,$40,$40,$40,$70,$00,$00,$00,$80,$40,$20,$10,$08,$00,$70,$10,$10,$10,$10,$10,$70,$00,$20,$50, -$88,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$f8,$00,$40,$20,$10,$00,$00,$00,$00,$00,$00,$00,$70,$08, -$78,$88,$78,$00,$80,$80,$b0,$c8,$88,$c8,$b0,$00,$00,$00,$70,$88,$80,$88,$70,$00,$08,$08,$68,$98,$88,$98, -$68,$00,$00,$00,$70,$88,$f8,$80,$70,$00,$10,$28,$20,$f8,$20,$20,$20,$00,$00,$00,$68,$98,$98,$68,$08,$70, -$80,$80,$f0,$88,$88,$88,$88,$00,$20,$00,$60,$20,$20,$20,$70,$00,$10,$00,$30,$10,$10,$10,$90,$60,$40,$40, -$48,$50,$60,$50,$48,$00,$60,$20,$20,$20,$20,$20,$70,$00,$00,$00,$d0,$a8,$a8,$a8,$a8,$00,$00,$00,$b0,$c8, -$88,$88,$88,$00,$00,$00,$70,$88,$88,$88,$70,$00,$00,$00,$b0,$c8,$c8,$b0,$80,$80,$00,$00,$68,$98,$98,$68, -$08,$08,$00,$00,$b0,$c8,$80,$80,$80,$00,$00,$00,$78,$80,$f0,$08,$f0,$00,$40,$40,$f0,$40,$40,$48,$30,$00, -$00,$00,$90,$90,$90,$90,$68,$00,$00,$00,$88,$88,$88,$50,$20,$00,$00,$00,$88,$a8,$a8,$a8,$50,$00,$00,$00, -$88,$50,$20,$50,$88,$00,$00,$00,$88,$88,$98,$68,$08,$70,$00,$00,$f8,$10,$20,$40,$f8,$00,$18,$20,$20,$40, -$20,$20,$18,$00,$20,$20,$20,$00,$20,$20,$20,$00,$c0,$20,$20,$10,$20,$20,$c0,$00,$40,$a8,$10,$00,$00,$00, -$00,$00,$00,$00,$20,$50,$f8,$00,$00,$00,$00,$00,$00,$00,$00,$00,$ff,$ff,$f0,$f0,$f0,$f0,$0f,$0f,$0f,$0f, -$00,$00,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3c,$3c,$00,$00,$00,$ff,$ff, -$ff,$ff,$ff,$ff,$00,$00,$c0,$c0,$c0,$c0,$c0,$c0,$c0,$c0,$0f,$0f,$0f,$0f,$f0,$f0,$f0,$f0,$fc,$fc,$fc,$fc, -$fc,$fc,$fc,$fc,$03,$03,$03,$03,$03,$03,$03,$03,$3f,$3f,$3f,$3f,$3f,$3f,$3f,$3f,$11,$22,$44,$88,$11,$22, -$44,$88,$88,$44,$22,$11,$88,$44,$22,$11,$fe,$7c,$38,$10,$00,$00,$00,$00,$00,$00,$00,$00,$10,$38,$7c,$fe, -$80,$c0,$e0,$f0,$e0,$c0,$80,$00,$01,$03,$07,$0f,$07,$03,$01,$00,$ff,$7e,$3c,$18,$18,$3c,$7e,$ff,$81,$c3, -$e7,$ff,$ff,$e7,$c3,$81,$f0,$f0,$f0,$f0,$00,$00,$00,$00,$00,$00,$00,$00,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f, -$00,$00,$00,$00,$00,$00,$00,$00,$f0,$f0,$f0,$f0,$33,$33,$cc,$cc,$33,$33,$cc,$cc,$00,$20,$20,$50,$50,$88, -$f8,$00,$20,$20,$70,$20,$70,$20,$20,$00,$00,$00,$00,$50,$88,$a8,$50,$00,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff, -$00,$00,$00,$00,$ff,$ff,$ff,$ff,$f0,$f0,$f0,$f0,$f0,$f0,$f0,$f0,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$ff,$ff, -$ff,$ff,$00,$00,$00,$00,$00,$00,$68,$90,$90,$90,$68,$00,$30,$48,$48,$70,$48,$48,$70,$c0,$f8,$88,$80,$80, -$80,$80,$80,$00,$00,$50,$70,$88,$f8,$80,$70,$00,$00,$00,$78,$80,$f0,$80,$78,$00,$00,$00,$78,$90,$90,$90, -$60,$00,$20,$00,$60,$20,$20,$20,$70,$00,$50,$00,$70,$20,$20,$20,$70,$00,$f8,$20,$70,$a8,$a8,$70,$20,$f8, -$20,$50,$88,$f8,$88,$50,$20,$00,$70,$88,$88,$88,$50,$50,$d8,$00,$30,$40,$40,$20,$50,$50,$50,$20,$00,$00, -$00,$50,$a8,$a8,$50,$00,$08,$70,$a8,$a8,$a8,$70,$80,$00,$38,$40,$80,$f8,$80,$40,$38,$00,$70,$88,$88,$88, -$88,$88,$88,$00,$00,$f8,$00,$f8,$00,$f8,$00,$00,$20,$20,$f8,$20,$20,$00,$f8,$00,$c0,$30,$08,$30,$c0,$00, -$f8,$00,$50,$f8,$80,$f0,$80,$80,$f8,$00,$78,$80,$80,$f0,$80,$80,$78,$00,$20,$20,$20,$20,$20,$20,$a0,$40, -$70,$20,$20,$20,$20,$20,$70,$00,$50,$70,$20,$20,$20,$20,$70,$00,$00,$18,$24,$24,$18,$00,$00,$00,$00,$30, -$78,$78,$30,$00,$00,$00,$00,$00,$00,$00,$30,$00,$00,$00,$3e,$20,$20,$20,$a0,$60,$20,$00,$a0,$50,$50,$50, -$00,$00,$00,$00,$40,$a0,$20,$40,$e0,$00,$00,$00,$00,$38,$38,$38,$38,$38,$38,$00,$3c,$42,$99,$a1,$a1,$99, -$42,$3c,$00,$00,$90,$a8,$e8,$a8,$90,$00,$00,$00,$60,$10,$70,$90,$68,$00,$00,$00,$f0,$80,$f0,$88,$f0,$00, -$00,$00,$90,$90,$90,$f8,$08,$00,$00,$00,$30,$50,$50,$70,$88,$00,$00,$00,$70,$88,$f8,$80,$70,$00,$00,$20, -$70,$a8,$a8,$70,$20,$00,$00,$00,$78,$48,$40,$40,$40,$00,$00,$00,$88,$50,$20,$50,$88,$00,$00,$00,$88,$98, -$a8,$c8,$88,$00,$00,$50,$20,$00,$98,$a8,$c8,$00,$00,$00,$90,$a0,$c0,$a0,$90,$00,$00,$00,$38,$28,$28,$48, -$88,$00,$00,$00,$88,$d8,$a8,$88,$88,$00,$00,$00,$88,$88,$f8,$88,$88,$00,$00,$00,$70,$88,$88,$88,$70,$00, -$00,$00,$78,$48,$48,$48,$48,$00,$00,$00,$78,$88,$78,$28,$48,$00,$00,$00,$f0,$88,$f0,$80,$80,$00,$00,$00, -$78,$80,$80,$80,$78,$00,$00,$00,$f8,$20,$20,$20,$20,$00,$00,$00,$88,$50,$20,$40,$80,$00,$00,$00,$a8,$70, -$20,$70,$a8,$00,$00,$00,$f0,$48,$70,$48,$f0,$00,$00,$00,$40,$40,$70,$48,$70,$00,$00,$00,$88,$88,$c8,$a8, -$c8,$00,$00,$00,$f0,$08,$70,$08,$f0,$00,$00,$00,$a8,$a8,$a8,$a8,$f8,$00,$00,$00,$70,$88,$38,$88,$70,$00, -$00,$00,$a8,$a8,$a8,$f8,$08,$00,$00,$00,$48,$48,$78,$08,$08,$00,$00,$00,$c0,$40,$70,$48,$70,$00,$90,$a8, -$a8,$e8,$a8,$a8,$90,$00,$20,$50,$88,$88,$f8,$88,$88,$00,$f8,$88,$80,$f0,$88,$88,$f0,$00,$90,$90,$90,$90, -$90,$f8,$08,$00,$38,$28,$28,$48,$48,$f8,$88,$00,$f8,$80,$80,$f0,$80,$80,$f8,$00,$20,$70,$a8,$a8,$a8,$70, -$20,$00,$f8,$88,$88,$80,$80,$80,$80,$00,$88,$88,$50,$20,$50,$88,$88,$00,$88,$88,$98,$a8,$c8,$88,$88,$00, -$50,$20,$88,$98,$a8,$c8,$88,$00,$88,$90,$a0,$c0,$a0,$90,$88,$00,$18,$28,$48,$48,$48,$48,$88,$00,$88,$d8, -$a8,$a8,$88,$88,$88,$00,$88,$88,$88,$f8,$88,$88,$88,$00,$70,$88,$88,$88,$88,$88,$70,$00,$f8,$88,$88,$88, -$88,$88,$88,$00,$78,$88,$88,$78,$28,$48,$88,$00,$f0,$88,$88,$f0,$80,$80,$80,$00,$70,$88,$80,$80,$80,$88, -$70,$00,$f8,$20,$20,$20,$20,$20,$20,$00,$88,$88,$88,$50,$20,$40,$80,$00,$a8,$a8,$70,$20,$70,$a8,$a8,$00, -$f0,$48,$48,$70,$48,$48,$f0,$00,$80,$80,$80,$f0,$88,$88,$f0,$00,$88,$88,$88,$c8,$a8,$a8,$c8,$00,$f0,$08, -$08,$30,$08,$08,$f0,$00,$a8,$a8,$a8,$a8,$a8,$a8,$f8,$00,$70,$88,$08,$78,$08,$88,$70,$00,$a8,$a8,$a8,$a8, -$a8,$f8,$08,$00,$88,$88,$88,$88,$78,$08,$08,$00,$c0,$40,$40,$70,$48,$48,$70,$00 -); - -const kgiFont8: array[0..256*8-1] of Byte = ( -$00,$00,$00,$00,$00,$00,$00,$00,$7e,$81,$a5,$81,$bd,$99,$81,$7e,$7e,$ff,$db,$ff,$c3,$e7,$ff,$7e,$6c,$fe, -$fe,$fe,$7c,$38,$10,$00,$10,$38,$7c,$fe,$7c,$38,$10,$00,$38,$7c,$38,$fe,$fe,$d6,$10,$38,$10,$10,$38,$7c, -$fe,$7c,$10,$38,$00,$00,$18,$3c,$3c,$18,$00,$00,$ff,$ff,$e7,$c3,$c3,$e7,$ff,$ff,$00,$3c,$66,$42,$42,$66, -$3c,$00,$ff,$c3,$99,$bd,$bd,$99,$c3,$ff,$0f,$07,$0f,$7d,$cc,$cc,$cc,$78,$3c,$66,$66,$66,$3c,$18,$7e,$18, -$3f,$33,$3f,$30,$30,$70,$f0,$e0,$7f,$63,$7f,$63,$63,$67,$e6,$c0,$99,$5a,$3c,$e7,$e7,$3c,$5a,$99,$80,$e0, -$f8,$fe,$f8,$e0,$80,$00,$02,$0e,$3e,$fe,$3e,$0e,$02,$00,$18,$3c,$7e,$18,$18,$7e,$3c,$18,$66,$66,$66,$66, -$66,$00,$66,$00,$7f,$db,$db,$7b,$1b,$1b,$1b,$00,$7e,$c3,$78,$cc,$cc,$78,$8c,$f8,$00,$00,$00,$00,$7e,$7e, -$7e,$00,$18,$3c,$7e,$18,$7e,$3c,$18,$ff,$18,$3c,$7e,$18,$18,$18,$18,$00,$18,$18,$18,$18,$7e,$3c,$18,$00, -$00,$18,$0c,$fe,$0c,$18,$00,$00,$00,$30,$60,$fe,$60,$30,$00,$00,$00,$00,$c0,$c0,$c0,$fe,$00,$00,$00,$24, -$66,$ff,$66,$24,$00,$00,$00,$18,$3c,$7e,$ff,$ff,$00,$00,$00,$ff,$ff,$7e,$3c,$18,$00,$00,$00,$00,$00,$00, -$00,$00,$00,$00,$30,$78,$78,$30,$30,$00,$30,$00,$6c,$6c,$6c,$00,$00,$00,$00,$00,$6c,$6c,$fe,$6c,$fe,$6c, -$6c,$00,$30,$7c,$c0,$78,$0c,$f8,$30,$00,$00,$c6,$cc,$18,$30,$66,$c6,$00,$38,$6c,$38,$76,$dc,$cc,$76,$00, -$60,$60,$c0,$00,$00,$00,$00,$00,$18,$30,$60,$60,$60,$30,$18,$00,$60,$30,$18,$18,$18,$30,$60,$00,$00,$66, -$3c,$ff,$3c,$66,$00,$00,$00,$30,$30,$fc,$30,$30,$00,$00,$00,$00,$00,$00,$00,$70,$30,$60,$00,$00,$00,$fc, -$00,$00,$00,$00,$00,$00,$00,$00,$00,$30,$30,$00,$06,$0c,$18,$30,$60,$c0,$80,$00,$78,$cc,$dc,$fc,$ec,$cc, -$78,$00,$30,$f0,$30,$30,$30,$30,$fc,$00,$78,$cc,$0c,$38,$60,$cc,$fc,$00,$78,$cc,$0c,$38,$0c,$cc,$78,$00, -$1c,$3c,$6c,$cc,$fe,$0c,$0c,$00,$fc,$c0,$f8,$0c,$0c,$cc,$78,$00,$38,$60,$c0,$f8,$cc,$cc,$78,$00,$fc,$cc, -$0c,$18,$30,$60,$60,$00,$78,$cc,$cc,$78,$cc,$cc,$78,$00,$78,$cc,$cc,$7c,$0c,$18,$70,$00,$00,$00,$30,$30, -$00,$30,$30,$00,$00,$00,$30,$30,$00,$70,$30,$60,$18,$30,$60,$c0,$60,$30,$18,$00,$00,$00,$fc,$00,$fc,$00, -$00,$00,$60,$30,$18,$0c,$18,$30,$60,$00,$78,$cc,$0c,$18,$30,$00,$30,$00,$7c,$c6,$de,$de,$de,$c0,$78,$00, -$30,$78,$cc,$cc,$fc,$cc,$cc,$00,$fc,$66,$66,$7c,$66,$66,$fc,$00,$3c,$66,$c0,$c0,$c0,$66,$3c,$00,$fc,$6c, -$66,$66,$66,$6c,$fc,$00,$fe,$62,$68,$78,$68,$62,$fe,$00,$fe,$62,$68,$78,$68,$60,$f0,$00,$3c,$66,$c0,$c0, -$ce,$66,$3e,$00,$cc,$cc,$cc,$fc,$cc,$cc,$cc,$00,$78,$30,$30,$30,$30,$30,$78,$00,$1e,$0c,$0c,$0c,$cc,$cc, -$78,$00,$e6,$66,$6c,$78,$6c,$66,$e6,$00,$f0,$60,$60,$60,$62,$66,$fe,$00,$c6,$ee,$fe,$d6,$c6,$c6,$c6,$00, -$c6,$e6,$f6,$de,$ce,$c6,$c6,$00,$38,$6c,$c6,$c6,$c6,$6c,$38,$00,$fc,$66,$66,$7c,$60,$60,$f0,$00,$78,$cc, -$cc,$cc,$dc,$78,$1c,$00,$fc,$66,$66,$7c,$78,$6c,$e6,$00,$78,$cc,$e0,$38,$1c,$cc,$78,$00,$fc,$b4,$30,$30, -$30,$30,$78,$00,$cc,$cc,$cc,$cc,$cc,$cc,$fc,$00,$cc,$cc,$cc,$cc,$cc,$78,$30,$00,$c6,$c6,$c6,$d6,$fe,$ee, -$c6,$00,$c6,$c6,$6c,$38,$6c,$c6,$c6,$00,$cc,$cc,$cc,$78,$30,$30,$78,$00,$fe,$cc,$98,$30,$62,$c6,$fe,$00, -$78,$60,$60,$60,$60,$60,$78,$00,$c0,$60,$30,$18,$0c,$06,$02,$00,$78,$18,$18,$18,$18,$18,$78,$00,$10,$38, -$6c,$c6,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$ff,$30,$30,$18,$00,$00,$00,$00,$00,$00,$00,$78,$0c, -$7c,$cc,$76,$00,$e0,$60,$7c,$66,$66,$66,$bc,$00,$00,$00,$78,$cc,$c0,$cc,$78,$00,$1c,$0c,$0c,$7c,$cc,$cc, -$76,$00,$00,$00,$78,$cc,$fc,$c0,$78,$00,$38,$6c,$60,$f0,$60,$60,$f0,$00,$00,$00,$76,$cc,$cc,$7c,$0c,$f8, -$e0,$60,$6c,$76,$66,$66,$e6,$00,$30,$00,$70,$30,$30,$30,$78,$00,$18,$00,$78,$18,$18,$18,$d8,$70,$e0,$60, -$66,$6c,$78,$6c,$e6,$00,$70,$30,$30,$30,$30,$30,$78,$00,$00,$00,$ec,$fe,$d6,$c6,$c6,$00,$00,$00,$f8,$cc, -$cc,$cc,$cc,$00,$00,$00,$78,$cc,$cc,$cc,$78,$00,$00,$00,$dc,$66,$66,$7c,$60,$f0,$00,$00,$76,$cc,$cc,$7c, -$0c,$1e,$00,$00,$d8,$6c,$6c,$60,$f0,$00,$00,$00,$7c,$c0,$78,$0c,$f8,$00,$10,$30,$7c,$30,$30,$34,$18,$00, -$00,$00,$cc,$cc,$cc,$cc,$76,$00,$00,$00,$cc,$cc,$cc,$78,$30,$00,$00,$00,$c6,$c6,$d6,$fe,$6c,$00,$00,$00, -$c6,$6c,$38,$6c,$c6,$00,$00,$00,$cc,$cc,$cc,$7c,$0c,$f8,$00,$00,$fc,$98,$30,$64,$fc,$00,$1c,$30,$30,$e0, -$30,$30,$1c,$00,$18,$18,$18,$00,$18,$18,$18,$00,$e0,$30,$30,$1c,$30,$30,$e0,$00,$76,$dc,$00,$00,$00,$00, -$00,$00,$10,$38,$6c,$c6,$c6,$c6,$fe,$00,$78,$cc,$c0,$cc,$78,$18,$0c,$78,$00,$cc,$00,$cc,$cc,$cc,$7e,$00, -$1c,$00,$78,$cc,$fc,$c0,$78,$00,$7e,$c3,$3c,$06,$3e,$66,$3f,$00,$cc,$00,$78,$0c,$7c,$cc,$7e,$00,$e0,$00, -$78,$0c,$7c,$cc,$7e,$00,$30,$30,$78,$0c,$7c,$cc,$7e,$00,$00,$00,$7c,$c0,$c0,$7c,$06,$3c,$7e,$c3,$3c,$66, -$7e,$60,$3c,$00,$cc,$00,$78,$cc,$fc,$c0,$78,$00,$e0,$00,$78,$cc,$fc,$c0,$78,$00,$cc,$00,$70,$30,$30,$30, -$78,$00,$7c,$c6,$38,$18,$18,$18,$3c,$00,$e0,$00,$70,$30,$30,$30,$78,$00,$cc,$30,$78,$cc,$cc,$fc,$cc,$00, -$30,$30,$00,$78,$cc,$fc,$cc,$00,$1c,$00,$fc,$60,$78,$60,$fc,$00,$00,$00,$7f,$0c,$7f,$cc,$7f,$00,$3e,$6c, -$cc,$fe,$cc,$cc,$ce,$00,$78,$cc,$00,$78,$cc,$cc,$78,$00,$00,$cc,$00,$78,$cc,$cc,$78,$00,$00,$e0,$00,$78, -$cc,$cc,$78,$00,$78,$cc,$00,$cc,$cc,$cc,$7e,$00,$00,$e0,$00,$cc,$cc,$cc,$7e,$00,$00,$cc,$00,$cc,$cc,$fc, -$0c,$f8,$c6,$38,$7c,$c6,$c6,$7c,$38,$00,$cc,$00,$cc,$cc,$cc,$cc,$78,$00,$18,$18,$7e,$c0,$c0,$7e,$18,$18, -$38,$6c,$64,$f0,$60,$e6,$fc,$00,$cc,$cc,$78,$fc,$30,$fc,$30,$00,$f0,$d8,$d8,$f4,$cc,$de,$cc,$0e,$0e,$1b, -$18,$7e,$18,$18,$d8,$70,$1c,$00,$78,$0c,$7c,$cc,$7e,$00,$38,$00,$70,$30,$30,$30,$78,$00,$00,$1c,$00,$78, -$cc,$cc,$78,$00,$00,$1c,$00,$cc,$cc,$cc,$7e,$00,$00,$f8,$00,$f8,$cc,$cc,$cc,$00,$fc,$00,$cc,$ec,$fc,$dc, -$cc,$00,$3c,$6c,$6c,$3e,$00,$7e,$00,$00,$3c,$66,$66,$3c,$00,$7e,$00,$00,$30,$00,$30,$60,$c0,$cc,$78,$00, -$00,$00,$00,$fc,$c0,$c0,$00,$00,$00,$00,$00,$fc,$0c,$0c,$00,$00,$c6,$cc,$d8,$3e,$63,$ce,$98,$1f,$c6,$cc, -$d8,$f3,$67,$cf,$9f,$03,$00,$18,$00,$18,$18,$3c,$3c,$18,$00,$33,$66,$cc,$66,$33,$00,$00,$00,$cc,$66,$33, -$66,$cc,$00,$00,$22,$88,$22,$88,$22,$88,$22,$88,$55,$aa,$55,$aa,$55,$aa,$55,$aa,$dc,$76,$dc,$76,$dc,$76, -$dc,$76,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$f8,$18,$18,$18,$18,$18,$f8,$18,$f8,$18,$18,$18, -$36,$36,$36,$36,$f6,$36,$36,$36,$00,$00,$00,$00,$fe,$36,$36,$36,$00,$00,$f8,$18,$f8,$18,$18,$18,$36,$36, -$f6,$06,$f6,$36,$36,$36,$36,$36,$36,$36,$36,$36,$36,$36,$00,$00,$fe,$06,$f6,$36,$36,$36,$36,$36,$f6,$06, -$fe,$00,$00,$00,$36,$36,$36,$36,$fe,$00,$00,$00,$18,$18,$f8,$18,$f8,$00,$00,$00,$00,$00,$00,$00,$f8,$18, -$18,$18,$18,$18,$18,$18,$1f,$00,$00,$00,$18,$18,$18,$18,$ff,$00,$00,$00,$00,$00,$00,$00,$ff,$18,$18,$18, -$18,$18,$18,$18,$1f,$18,$18,$18,$00,$00,$00,$00,$ff,$00,$00,$00,$18,$18,$18,$18,$ff,$18,$18,$18,$18,$18, -$1f,$18,$1f,$18,$18,$18,$36,$36,$36,$36,$37,$36,$36,$36,$36,$36,$37,$30,$3f,$00,$00,$00,$00,$00,$3f,$30, -$37,$36,$36,$36,$36,$36,$f7,$00,$ff,$00,$00,$00,$00,$00,$ff,$00,$f7,$36,$36,$36,$36,$36,$37,$30,$37,$36, -$36,$36,$00,$00,$ff,$00,$ff,$00,$00,$00,$36,$36,$f7,$00,$f7,$36,$36,$36,$18,$18,$ff,$00,$ff,$00,$00,$00, -$36,$36,$36,$36,$ff,$00,$00,$00,$00,$00,$ff,$00,$ff,$18,$18,$18,$00,$00,$00,$00,$ff,$36,$36,$36,$36,$36, -$36,$36,$3f,$00,$00,$00,$18,$18,$1f,$18,$1f,$00,$00,$00,$00,$00,$1f,$18,$1f,$18,$18,$18,$00,$00,$00,$00, -$3f,$36,$36,$36,$36,$36,$36,$36,$f7,$36,$36,$36,$18,$18,$ff,$00,$ff,$18,$18,$18,$18,$18,$18,$18,$f8,$00, -$00,$00,$00,$00,$00,$00,$1f,$18,$18,$18,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$00,$00,$00,$00,$ff,$ff,$ff,$ff, -$f0,$f0,$f0,$f0,$f0,$f0,$f0,$f0,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$ff,$ff,$ff,$ff,$00,$00,$00,$00,$00,$00, -$76,$dc,$c8,$dc,$76,$00,$00,$78,$cc,$f8,$cc,$f8,$c0,$c0,$00,$fe,$c6,$c0,$c0,$c0,$c0,$00,$00,$fe,$6c,$6c, -$6c,$6c,$6c,$00,$fe,$66,$30,$18,$30,$66,$fe,$00,$00,$00,$7e,$cc,$cc,$cc,$78,$00,$00,$66,$66,$66,$66,$7c, -$60,$c0,$00,$76,$dc,$18,$18,$18,$18,$00,$fc,$30,$78,$cc,$cc,$78,$30,$fc,$38,$6c,$c6,$fe,$c6,$6c,$38,$00, -$38,$6c,$c6,$c6,$6c,$6c,$ee,$00,$1c,$30,$18,$7c,$cc,$cc,$78,$00,$00,$00,$7e,$db,$db,$7e,$00,$00,$06,$0c, -$7e,$db,$db,$7e,$60,$c0,$3c,$60,$c0,$fc,$c0,$60,$3c,$00,$78,$cc,$cc,$cc,$cc,$cc,$cc,$00,$00,$fc,$00,$fc, -$00,$fc,$00,$00,$30,$30,$fc,$30,$30,$00,$fc,$00,$60,$30,$18,$30,$60,$00,$fc,$00,$18,$30,$60,$30,$18,$00, -$fc,$00,$0e,$1b,$1b,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$d8,$d8,$70,$30,$30,$00,$fc,$00,$30,$30,$00, -$00,$72,$9c,$00,$72,$9c,$00,$00,$38,$6c,$6c,$38,$00,$00,$00,$00,$00,$00,$00,$18,$18,$00,$00,$00,$00,$00, -$00,$00,$18,$00,$00,$00,$0f,$0c,$0c,$0c,$ec,$6c,$3c,$1c,$78,$6c,$6c,$6c,$6c,$00,$00,$00,$78,$0c,$38,$60, -$7c,$00,$00,$00,$00,$00,$3c,$3c,$3c,$3c,$00,$00,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff -); - -const kgiFont6PropWidth: array[0..256-1] of Byte = ( - $08,$08,$08,$07,$07,$07,$07,$04,$08,$07,$08,$08,$06,$06,$06,$07, - $06,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08, - $85,$21,$13,$05,$05,$05,$05,$13,$13,$13,$05,$05,$12,$14,$12,$05, - $05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$21,$12,$05,$05,$05,$05, - $05,$05,$05,$05,$05,$05,$05,$05,$05,$13,$05,$05,$05,$05,$05,$05, - $05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$13,$05,$13,$05,$05, - $13,$05,$05,$05,$05,$05,$05,$05,$05,$13,$04,$14,$13,$05,$05,$05, - $05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$14,$21,$04,$05,$08, - $08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$04, - $44,$08,$08,$08,$08,$08,$08,$08,$05,$04,$05,$08,$08,$08,$08,$08, - $05,$05,$05,$05,$05,$05,$13,$13,$05,$05,$05,$04,$05,$05,$05,$05, - $05,$05,$05,$05,$05,$03,$04,$04,$06,$05,$04,$07,$04,$03,$05,$08, - $05,$05,$05,$05,$05,$05,$05,$14,$05,$05,$05,$04,$05,$05,$05,$05, - $14,$05,$05,$05,$05,$05,$05,$05,$14,$05,$05,$05,$05,$05,$14,$05, - $05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05, - $05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05 -); - -const kgiFont8PropWidth: array[0..256-1] of Byte = ( - $08,$08,$08,$07,$07,$07,$07,$06,$08,$07,$08,$08,$07,$08,$08,$08, - $07,$07,$07,$07,$08,$08,$07,$08,$07,$07,$07,$07,$07,$08,$08,$08, - $85,$14,$15,$07,$06,$07,$07,$03,$14,$14,$08,$06,$13,$06,$22,$07, - $05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$22,$13,$05,$06,$15,$06, - $07,$06,$07,$07,$07,$07,$07,$07,$06,$14,$07,$07,$07,$07,$07,$07, - $07,$06,$07,$06,$06,$06,$06,$07,$07,$06,$07,$14,$07,$14,$07,$08, - $23,$07,$07,$06,$07,$06,$06,$07,$07,$14,$05,$07,$14,$07,$06,$06, - $07,$07,$06,$06,$15,$07,$06,$07,$07,$06,$06,$06,$32,$06,$07,$07, - $06,$07,$06,$08,$07,$07,$07,$07,$08,$06,$06,$06,$07,$05,$06,$06, - $06,$08,$07,$06,$06,$06,$07,$07,$06,$07,$06,$07,$07,$06,$07,$08, - $07,$05,$06,$07,$06,$06,$16,$16,$06,$06,$06,$08,$08,$06,$08,$08, - $08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08, - $38,$08,$08,$38,$08,$08,$38,$28,$28,$28,$08,$08,$28,$08,$08,$08, - $08,$08,$08,$28,$38,$38,$28,$08,$08,$08,$38,$08,$08,$08,$48,$08, - $07,$06,$07,$07,$07,$07,$07,$07,$06,$07,$07,$06,$08,$08,$06,$06, - $06,$06,$06,$06,$35,$05,$06,$07,$15,$32,$32,$08,$15,$15,$24,$08 -); - - -function createFontTexture (constref font: array of Byte; constref fontwdt: array of Byte; prop: Boolean): GLuint; -const - Width = 16*8; - Height = 16*8; +// return width (not including last empty pixel) +function TGxBmpFont.drawTextInternal (x, y: Integer; const s: AnsiString): Integer; var - tex, tpp: PByte; - b: Byte; - cc: Integer; - x, y, dx, dy: Integer; + ch: AnsiChar; + tx, ty: Integer; begin - GetMem(tex, Width*Height*4); + if (Length(s) = 0) then begin result := 0; exit; end; + + result := -1; + + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_NOTEQUAL, 0.0); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, mTexId); - for cc := 0 to 255 do + for ch in s do begin - x := (cc mod 16)*8; - y := (cc div 16)*8; - for dy := 0 to 7 do - begin - b := font[cc*8+dy]; - if prop then b := b shl (fontwdt[cc] shr 4); - tpp := tex+((y+dy)*(Width*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; - end; + tx := (Integer(ch) mod 16)*8; + ty := (Integer(ch) div 16)*8; + glBegin(GL_QUADS); + glTexCoord2f((tx+0)/128.0, (ty+0)/128.0); glVertex2i(x+0, y+0); // top-left + glTexCoord2f((tx+8)/128.0, (ty+0)/128.0); glVertex2i(x+8, y+0); // top-right + glTexCoord2f((tx+8)/128.0, (ty+8)/128.0); glVertex2i(x+8, y+8); // bottom-right + glTexCoord2f((tx+0)/128.0, (ty+8)/128.0); glVertex2i(x+0, y+8); // bottom-left + glEnd(); + x += (mFontWdt[Byte(ch)] and $0f)+1; + result += (mFontWdt[Byte(ch)] and $0f)+1; end; - glGenTextures(1, @result); - if (result = 0) then raise Exception.Create('can''t create Holmes font texture'); + glDisable(GL_ALPHA_TEST); + glDisable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, 0); +end; - glBindTexture(GL_TEXTURE_2D, result); - 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); - //GLfloat[4] bclr = 0.0; - //glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, bclr.ptr); +// ////////////////////////////////////////////////////////////////////////// // +var + fontList: array of TGxBmpFont = nil; + defaultFontName: AnsiString = 'dos'; - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Width, Height, 0, GL_RGBA{gltt}, GL_UNSIGNED_BYTE, tex); - glFlush(); - //FreeMem(tex); +function strEquCI (const s0, s1: AnsiString): Boolean; +var + f: Integer; + c0, c1: AnsiChar; +begin + result := (Length(s0) = Length(s1)); + if (result) then + begin + for f := 1 to Length(s0) do + begin + c0 := s0[f]; + if (c0 >= 'a') and (c0 <= 'z') then Dec(c0, 32); // poor man's `toupper()` + c1 := s1[f]; + if (c1 >= 'a') and (c1 <= 'z') then Dec(c1, 32); // poor man's `toupper()` + if (c0 <> c1) then begin result := false; exit; end; + end; + end; end; +function getFontByName (const aname: AnsiString): TGxBmpFont; var - font6texid: GLuint = 0; - font8texid: GLuint = 0; - prfont6texid: GLuint = 0; - prfont8texid: GLuint = 0; + f: Integer; + fname: AnsiString; +begin + if (Length(fontList) = 0) then raise Exception.Create('font subsystem not initialized'); + if (Length(aname) = 0) or (strEquCI(aname, 'default')) then fname := defaultFontName else fname := aname; + for f := 0 to High(fontList) do + begin + result := fontList[f]; + if (result = nil) then continue; + if (strEquCI(result.name, fname)) then exit; + end; + if (fontList[0] = nil) then raise Exception.Create('font subsystem not properly initialized'); + result := fontList[0]; +end; procedure deleteFonts (); +var + f: Integer; begin - if (font6texid <> 0) then glDeleteTextures(1, @font6texid); - if (font8texid <> 0) then glDeleteTextures(1, @font8texid); - if (prfont6texid <> 0) then glDeleteTextures(1, @prfont6texid); - if (prfont8texid <> 0) then glDeleteTextures(1, @prfont8texid); - font6texid := 0; - font8texid := 0; - prfont6texid := 0; - prfont8texid := 0; + for f := 0 to High(fontList) do freeAndNil(fontList[f]); + fontList := nil; end; procedure createFonts (); begin - if (font6texid = 0) then font6texid := createFontTexture(kgiFont6, kgiFont6PropWidth, false); - if (font8texid = 0) then font8texid := createFontTexture(kgiFont8, kgiFont8PropWidth, false); - if (prfont6texid = 0) then prfont6texid := createFontTexture(kgiFont6, kgiFont6PropWidth, true); - if (prfont8texid = 0) then prfont8texid := createFontTexture(kgiFont8, kgiFont8PropWidth, true); + deleteFonts(); + SetLength(fontList, 4); + 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]); end; -// ////////////////////////////////////////////////////////////////////////// // -procedure TScissorSave.save (enableScissoring: Boolean); +procedure oglInitFonts (); +var + f: Integer; begin - wassc := (glIsEnabled(GL_SCISSOR_TEST) <> 0); - if wassc then glGetIntegerv(GL_SCISSOR_BOX, @scxywh[0]) else glGetIntegerv(GL_VIEWPORT, @scxywh[0]); - //conwritefln('(%d,%d)-(%d,%d)', [scxywh[0], scxywh[1], scxywh[2], scxywh[3]]); - if enableScissoring and (not wassc) then glEnable(GL_SCISSOR_TEST); + for f := 0 to High(fontList) do if (fontList[f] <> nil) then fontList[f].oglCreateTexture(); end; -procedure TScissorSave.restore (); -begin - glScissor(scxywh[0], scxywh[1], scxywh[2], scxywh[3]); - if wassc then glEnable(GL_SCISSOR_TEST) else glDisable(GL_SCISSOR_TEST); -end; -procedure TScissorSave.combineRect (x, y, w, h: Integer); -//var ox, oy, ow, oh: Integer; +procedure oglDeinitFonts (); +var + f: Integer; begin - if (w < 1) or (h < 1) then begin glScissor(0, 0, 0, 0); exit; end; - y := fuiScrHgt-(y+h); - //ox := x; oy := y; ow := w; oh := h; - if not intersectRect(x, y, w, h, scxywh[0], scxywh[1], scxywh[2], scxywh[3]) then - begin - //writeln('oops: COMBINE: old=(', ox, ',', oy, ')-(', ox+ow-1, ',', oy+oh-1, '); sci: (', scxywh[0], ',', scxywh[1], ')-(', scxywh[0]+scxywh[2]-1, ',', scxywh[1]+scxywh[3]-1, ')'); - //writeln('oops: COMBINE: oldx=<', ox, '-', ox+ow-1, '>; oldy=<', oy, ',', oy+oh-1, '> : scix=<', scxywh[0], '-', scxywh[0]+scxywh[2]-1, '>; sciy=<', scxywh[1], '-', scxywh[1]+scxywh[3]-1, '>'); - glScissor(0, 0, 0, 0); - end - else - begin - glScissor(x, y, w, h); - end; + for f := 0 to High(fontList) do if (fontList[f] <> nil) then fontList[f].oglDestroyTexture(); end; // ////////////////////////////////////////////////////////////////////////// // -// returns `false` if the color is transparent -function setupGLColor (r, g, b, a: Integer): Boolean; +procedure oglSetup2D (winWidth, winHeight: Integer; upsideDown: Boolean=false); begin - normRGBA(r, g, b, a); - if (a < 255) then + glViewport(0, 0, winWidth, winHeight); + + glDisable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable(GL_LINE_SMOOTH); + glDisable(GL_POLYGON_SMOOTH); + glDisable(GL_POINT_SMOOTH); + glDisable(GL_DEPTH_TEST); + glDisable(GL_TEXTURE_2D); + glDisable(GL_LIGHTING); + glDisable(GL_DITHER); + glDisable(GL_STENCIL_TEST); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_CULL_FACE); + glDisable(GL_ALPHA_TEST); + + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + + glMatrixMode(GL_COLOR); + glLoadIdentity(); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + if (upsideDown) then begin - if (a = 0) then begin result := false; exit; end; - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glOrtho(0, winWidth, 0, winHeight, -1, 1); // set origin to bottom left end else begin - glDisable(GL_BLEND); + glOrtho(0, winWidth, winHeight, 0, -1, 1); // set origin to top left end; - glColor4ub(Byte(r), Byte(g), Byte(b), Byte(a)); - result := true; + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glClearColor(0, 0, 0, 0); + glColor4f(1, 1, 1, 1); end; + +// ////////////////////////////////////////////////////////////////////////// // +{$INCLUDE fui_gfx_gl_cursor.inc} + +procedure oglDrawCursor (); begin oglDrawCursorAt(fuiMouseX, fuiMouseY); end; + + +// ////////////////////////////////////////////////////////////////////////// // +// returns `false` if the color is transparent // returns `false` if the color is transparent function setupGLColor (constref clr: TGxRGBA): Boolean; begin if (clr.a < 255) then begin - if (clr.a = 0) then begin result := false; exit; end; glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); end @@ -651,10 +573,10 @@ begin glDisable(GL_BLEND); end; glColor4ub(clr.r, clr.g, clr.b, clr.a); - result := true; + result := (clr.a <> 0); end; -function isScaled (): Boolean; +function mScaled (): Boolean; var mt: packed array [0..15] of Double; begin @@ -664,133 +586,147 @@ end; // ////////////////////////////////////////////////////////////////////////// // -function textWidth6 (const s: AnsiString): Integer; -var - f: Integer; +constructor TGxContext.Create (); begin - result := 0; - for f := 1 to Length(s) do Inc(result, Integer(kgiFont6PropWidth[Integer(s[f])] and $0f)+1); - if (result > 0) then Dec(result); // don't count last empty pixel + mActive := false; + mColor := TGxRGBA.Create(255, 255, 255); + mFont := getFontByName('default'); + mScaled := false; + mScale := 1.0; + mClipRect := TGxRect.Create(0, 0, 8192, 8192); + mClipOfs := TGxOfs.Create(0, 0); end; -function textWidth8 (const s: AnsiString): Integer; -var - f: Integer; +destructor TGxContext.Destroy (); begin - result := 0; - for f := 1 to Length(s) do Inc(result, Integer(kgiFont8PropWidth[Integer(s[f])] and $0f)+1); - if (result > 0) then Dec(result); // don't count last empty pixel + if (mActive) then gxSetContext(nil); + inherited; end; -// return width (including last empty pixel) -function drawTextInternal (wdt, x, y: Integer; const s: AnsiString; constref clr: TGxRGBA; tid: GLuint; constref fontwdt: array of Byte; prop: Boolean): Integer; -var - f, c: Integer; - tx, ty: Integer; +function TGxContext.getFont (): AnsiString; begin - result := 0; - if (Length(s) = 0) then exit; - if not setupGLColor(clr) then exit; + result := mFont.name; +end; + +procedure TGxContext.setFont (const aname: AnsiString); +begin + mFont := getFontByName(aname); +end; + + +procedure TGxContext.onActivate (); +begin + setupGLColor(mColor); + realizeClip(); +end; + +procedure TGxContext.onDeactivate (); +begin +end; + + +procedure TGxContext.setColor (const clr: TGxRGBA); +begin + mColor := clr; + if (mActive) then setupGLColor(mColor); +end; - glEnable(GL_ALPHA_TEST); - glAlphaFunc(GL_NOTEQUAL, 0.0); - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, tid); - for f := 1 to Length(s) do +procedure TGxContext.realizeClip (); +var + sx, sy, sw, sh: Integer; +begin + if (not mActive) then exit; // just in case + if (mClipRect.w <= 0) or (mClipRect.h <= 0) then begin - c := Integer(s[f]) and $ff; - tx := (c mod 16)*8; - ty := (c div 16)*8; - glBegin(GL_QUADS); - glTexCoord2f((tx+0)/128.0, (ty+0)/128.0); glVertex2i(x+0, y+0); // top-left - glTexCoord2f((tx+8)/128.0, (ty+0)/128.0); glVertex2i(x+8, y+0); // top-right - glTexCoord2f((tx+8)/128.0, (ty+8)/128.0); glVertex2i(x+8, y+8); // bottom-right - glTexCoord2f((tx+0)/128.0, (ty+8)/128.0); glVertex2i(x+0, y+8); // bottom-left - glEnd(); - if prop then + glEnable(GL_SCISSOR_TEST); + glScissor(0, 0, 0, 0); + end + else + begin + if (mScaled) then + begin + sx := trunc(mClipRect.x*mScale); + sy := trunc(mClipRect.y*mScale); + sw := trunc(mClipRect.w*mScale); + sh := trunc(mClipRect.h*mScale); + end + else + begin + sx := mClipRect.x; + sy := mClipRect.y; + sw := mClipRect.w; + sh := mClipRect.h; + end; + if (not intersectRect(sx, sy, sw, sh, 0, 0, fuiScrWdt, fuiScrHgt)) then + begin + glEnable(GL_SCISSOR_TEST); + glScissor(0, 0, 0, 0); + end + else if (sx = 0) and (sy = 0) and (sw = fuiScrWdt) and (sh = fuiScrHgt) then begin - x += Integer(fontwdt[c] and $0f)+1; - result += Integer(fontwdt[c] and $0f)+1; + glDisable(GL_SCISSOR_TEST); end else begin - x += wdt; - result += wdt; + glEnable(GL_SCISSOR_TEST); + sy := fuiScrHgt-(sy+sh); + glScissor(sx, sy, sw, sh); end; end; +end; - glDisable(GL_ALPHA_TEST); - glDisable(GL_BLEND); - glDisable(GL_TEXTURE_2D); - glColor4f(1, 1, 1, 1); - glBindTexture(GL_TEXTURE_2D, 0); + +procedure TGxContext.resetClip (); +begin + mClipRect := TGxRect.Create(0, 0, 8192, 8192); + if (mActive) then realizeClip(); end; -// ////////////////////////////////////////////////////////////////////////// // -procedure drawHLine (x, y, len: Integer; constref clr: TGxRGBA); +procedure TGxContext.setClipOfs (const aofs: TGxOfs); begin - if (len < 1) then exit; - if not setupGLColor(clr) then exit; - glDisable(GL_TEXTURE_2D); - if (not isScaled) then - begin - glLineWidth(1); - glBegin(GL_LINES); - glVertex2f(x+0.375, y+0.375); - glVertex2f(x+len+0.375, y+0.375); - glEnd(); - end - else - begin - glBegin(GL_QUADS); - glVertex2i(x, y); - glVertex2i(x+len, y); - glVertex2i(x+len, y+1); - glVertex2i(x, y+1); - glEnd(); - end; + mClipOfs := aofs; end; -procedure drawVLine (x, y, len: Integer; constref clr: TGxRGBA); +procedure TGxContext.setClipRect (const aclip: TGxRect); begin - if (len < 1) then exit; - if not setupGLColor(clr) then exit; - glDisable(GL_TEXTURE_2D); - if (not isScaled) then - begin - glLineWidth(1); - glBegin(GL_LINES); - glVertex2f(x+0.375, y+0.375); - glVertex2f(x+0.375, y+len+0.375); - glEnd(); - end - else - begin - glBegin(GL_QUADS); - glVertex2i(x, y); - glVertex2i(x, y+len); - glVertex2i(x+1, y+len); - glVertex2i(x+1, y); - glEnd(); - end; + mClipRect := aclip; + if (mActive) then realizeClip(); end; -procedure drawLine (x1, y1, x2, y2: Integer; constref clr: TGxRGBA); +function TGxContext.setOffset (constref aofs: TGxOfs): TGxOfs; begin - if not setupGLColor(clr) then exit; + result := mClipOfs; + mClipOfs := aofs; +end; - glDisable(GL_TEXTURE_2D); - glLineWidth(1); - glPointSize(1); +function TGxContext.setClip (constref aclip: TGxRect): TGxRect; +begin + result := mClipRect; + mClipRect := aclip; + if (mActive) then realizeClip(); +end; + + +function TGxContext.combineClip (constref aclip: TGxRect): TGxRect; +begin + result := mClipRect; + mClipRect.intersect(aclip); + if (mActive) then realizeClip(); +end; - if (not isScaled) then + +procedure TGxContext.line (x1, y1, x2, y2: Integer); +begin + if (not mActive) or (mClipRect.w < 1) or (mClipRect.h < 1) or (mColor.a = 0) then exit; + + if (not mScaled) then begin glLineWidth(1); glBegin(GL_LINES); @@ -800,6 +736,7 @@ begin if (x1 <> x2) or (y1 <> y2) then begin + glPointSize(1); glBegin(GL_POINTS); glVertex2f(x2+0.375, y2+0.375); glEnd(); @@ -816,44 +753,59 @@ begin glVertex2i(x2+1, y2+1); glEnd(); end; - - glColor4f(1, 1, 1, 1); - glDisable(GL_BLEND); end; -procedure drawRect (x, y, w, h: Integer; constref clr: TGxRGBA); +procedure TGxContext.hline (x, y, len: Integer); begin - if (w < 0) or (h < 0) then exit; - if not setupGLColor(clr) then exit; - glDisable(GL_TEXTURE_2D); - glLineWidth(1); - glDisable(GL_LINE_SMOOTH); - glDisable(GL_POLYGON_SMOOTH); - if (w = 1) and (h = 1) then + if (not mActive) or (mClipRect.w < 1) or (mClipRect.h < 1) or (mColor.a = 0) then exit; + if (len < 1) then exit; + if (not mScaled) then begin - glBegin(GL_POINTS); + glLineWidth(1); + glBegin(GL_LINES); glVertex2f(x+0.375, y+0.375); + glVertex2f(x+len+0.375, y+0.375); glEnd(); end else + begin + glBegin(GL_QUADS); + glVertex2i(x, y); + glVertex2i(x+len, y); + glVertex2i(x+len, y+1); + glVertex2i(x, y+1); + glEnd(); + end; +end; + + +procedure TGxContext.vline (x, y, len: Integer); +begin + if (not mActive) or (mClipRect.w < 1) or (mClipRect.h < 1) or (mColor.a = 0) then exit; + if (len < 1) then exit; + if (not mScaled) then begin glLineWidth(1); glBegin(GL_LINES); - glVertex2i(x, y); glVertex2i(x+w, y); // top - glVertex2i(x, y+h-1); glVertex2i(x+w, y+h-1); // bottom - glVertex2f(x+0.375, y+1); glVertex2f(x+0.375, y+h-1); // left - glVertex2f(x+w-1+0.375, y+1); glVertex2f(x+w-1+0.375, y+h-1); // right + glVertex2f(x+0.375, y+0.375); + glVertex2f(x+0.375, y+len+0.375); + glEnd(); + end + else + begin + glBegin(GL_QUADS); + glVertex2i(x, y); + glVertex2i(x, y+len); + glVertex2i(x+1, y+len); + glVertex2i(x+1, y); glEnd(); end; - //glRect(x, y, x+w, y+h); - glColor4f(1, 1, 1, 1); - glDisable(GL_BLEND); end; -procedure drawRectUI (x, y, w, h: Integer; constref clr: TGxRGBA); - procedure hline (x, y, len: Integer); +procedure TGxContext.rect (x, y, w, h: Integer); + procedure hlinex (x, y, len: Integer); begin if (len < 1) then exit; glBegin(GL_QUADS); @@ -864,7 +816,7 @@ procedure drawRectUI (x, y, w, h: Integer; constref clr: TGxRGBA); glEnd(); end; - procedure vline (x, y, len: Integer); + procedure vlinex (x, y, len: Integer); begin if (len < 1) then exit; glBegin(GL_QUADS); @@ -875,25 +827,19 @@ procedure drawRectUI (x, y, w, h: Integer; constref clr: TGxRGBA); glEnd(); end; -var - scaled: Boolean; begin + if (not mActive) or (mClipRect.w < 1) or (mClipRect.h < 1) or (mColor.a = 0) then exit; if (w < 0) or (h < 0) then exit; - if not setupGLColor(clr) then exit; - glDisable(GL_TEXTURE_2D); - glLineWidth(1); - glDisable(GL_LINE_SMOOTH); - glDisable(GL_POLYGON_SMOOTH); - scaled := isScaled(); if (w = 1) and (h = 1) then begin + glPointSize(1); glBegin(GL_POINTS); - if scaled then glVertex2i(x, y) else glVertex2f(x+0.375, y+0.375); + if mScaled then glVertex2i(x, y) else glVertex2f(x+0.375, y+0.375); glEnd(); end else begin - if not scaled then + if (not mScaled) then begin glLineWidth(1); glBegin(GL_LINES); @@ -905,28 +851,35 @@ begin end else begin - hline(x, y, w); - hline(x, y+h-1, w); - vline(x, y+1, h-2); - vline(x+w-1, y+1, h-2); + hlinex(x, y, w); + hlinex(x, y+h-1, w); + vlinex(x, y+1, h-2); + vlinex(x+w-1, y+1, h-2); end; end; - //glRect(x, y, x+w, y+h); - glColor4f(1, 1, 1, 1); - glDisable(GL_BLEND); end; -procedure darkenRect (x, y, w, h: Integer; a: Integer); +procedure TGxContext.fillRect (x, y, w, h: Integer); +begin + if (not mActive) or (mClipRect.w < 1) or (mClipRect.h < 1) or (mColor.a = 0) then exit; + if (w < 0) or (h < 0) then exit; + glBegin(GL_QUADS); + glVertex2f(x, y); + glVertex2f(x+w, y); + glVertex2f(x+w, y+h); + glVertex2f(x, y+h); + glEnd(); +end; + + +procedure TGxContext.darkenRect (x, y, w, h: Integer; a: Integer); begin + if (not mActive) or (mClipRect.w < 1) or (mClipRect.h < 1) or (a >= 255) then exit; if (w < 0) or (h < 0) then exit; if (a < 0) then a := 0; - if (a >= 255) then exit; glEnable(GL_BLEND); glBlendFunc(GL_ZERO, GL_SRC_ALPHA); - glDisable(GL_LINE_SMOOTH); - glDisable(GL_POLYGON_SMOOTH); - glDisable(GL_TEXTURE_2D); glColor4f(0.0, 0.0, 0.0, a/255.0); glBegin(GL_QUADS); glVertex2i(x, y); @@ -934,93 +887,114 @@ begin glVertex2i(x+w, y+h); glVertex2i(x, y+h); glEnd(); - //glRect(x, y, x+w, y+h); - glColor4f(1, 1, 1, 1); - glDisable(GL_BLEND); - //glBlendEquation(GL_FUNC_ADD); + setupGLColor(mColor); end; -procedure fillRect (x, y, w, h: Integer; constref clr: TGxRGBA); +function TGxContext.charWidth (const ch: AnsiChar): Integer; begin - if (w < 0) or (h < 0) then exit; - if not setupGLColor(clr) then exit; - glDisable(GL_LINE_SMOOTH); - glDisable(GL_POLYGON_SMOOTH); - glDisable(GL_TEXTURE_2D); - glBegin(GL_QUADS); - glVertex2f(x, y); - glVertex2f(x+w, y); - glVertex2f(x+w, y+h); - glVertex2f(x, y+h); - glEnd(); - glColor4f(1, 1, 1, 1); - glDisable(GL_BLEND); + result := mFont.charWidth(ch); end; - -// ////////////////////////////////////////////////////////////////////////// // -function drawText6 (x, y: Integer; const s: AnsiString; constref clr: TGxRGBA): Integer; +function TGxContext.charHeight (const ch: AnsiChar): Integer; begin - if (font6texid = 0) then createFonts(); - drawTextInternal(6, x, y, s, clr, font6texid, kgiFont6PropWidth, false); - result := Length(s)*6; + result := mFont.height; end; -function drawText8 (x, y: Integer; const s: AnsiString; constref clr: TGxRGBA): Integer; -begin - if (font8texid = 0) then createFonts(); - drawTextInternal(8, x, y, s, clr, font8texid, kgiFont8PropWidth, false); - result := Length(s)*8; -end; -function drawText6Prop (x, y: Integer; const s: AnsiString; constref clr: TGxRGBA): Integer; +function TGxContext.textWidth (const s: AnsiString): Integer; begin - if (prfont6texid = 0) then createFonts(); - result := drawTextInternal(6, x, y, s, clr, prfont6texid, kgiFont6PropWidth, true); + result := mFont.textWidth(s); end; -function drawText8Prop (x, y: Integer; const s: AnsiString; constref clr: TGxRGBA): Integer; +function TGxContext.textHeight (const s: AnsiString): Integer; begin - if (prfont8texid = 0) then createFonts(); - result := drawTextInternal(8, x, y, s, clr, prfont8texid, kgiFont8PropWidth, true); + result := mFont.height; end; -// ////////////////////////////////////////////////////////////////////////// // -// x-centered at `x` -function drawText6XC (x, y: Integer; const s: AnsiString; constref clr: TGxRGBA): Integer; +function TGxContext.drawChar (x, y: Integer; const ch: AnsiChar): Integer; // returns char width begin - if (font6texid = 0) then createFonts(); - x -= Length(s)*6 div 2; - drawTextInternal(6, x, y, s, clr, font6texid, kgiFont6PropWidth, false); - result := Length(s)*6; + result := mFont.charWidth(ch); + if (not mActive) or (mClipRect.w < 1) or (mClipRect.h < 1) or (mColor.a = 0) then exit; + TGxBmpFont(mFont).drawTextInternal(x, y, ch); end; -function drawText8XC (x, y: Integer; const s: AnsiString; constref clr: TGxRGBA): Integer; +function TGxContext.drawText (x, y: Integer; const s: AnsiString): Integer; // returns text width begin - if (font8texid = 0) then createFonts(); - x -= Length(s)*8 div 2; - drawTextInternal(8, x, y, s, clr, font8texid, kgiFont8PropWidth, false); - result := Length(s)*8; + result := mFont.textWidth(s); + if (not mActive) or (mClipRect.w < 1) or (mClipRect.h < 1) or (mColor.a = 0) or (Length(s) = 0) then exit; + TGxBmpFont(mFont).drawTextInternal(x, y, s); end; -function drawText6PropXC (x, y: Integer; const s: AnsiString; constref clr: TGxRGBA): Integer; + +function TGxContext.iconMarkWidth (ic: TMarkIcon): Integer; begin result := 11; end; +function TGxContext.iconMarkHeight (ic: TMarkIcon): Integer; begin result := 8; end; + +procedure TGxContext.drawIconMark (ic: TMarkIcon; x, y: Integer; marked: Boolean); +var + f: Integer; begin - if (prfont6texid = 0) then createFonts(); - x -= textWidth6(s) div 2; - result := drawTextInternal(6, x, y, s, clr, prfont6texid, kgiFont6PropWidth, true); + if (not mActive) or (mClipRect.w < 1) or (mClipRect.h < 1) or (mColor.a = 0) then exit; + if (ic = TMarkIcon.Checkbox) then + begin + vline(x, y, 7); + vline(x+10, y, 7); + hline(x+1, y, 1); + hline(x+1, y+6, 1); + hline(x+9, y, 1); + hline(x+9, y+6, 1); + end + else + begin + vline(x, y+1, 5); + vline(x+10, y+1, 5); + hline(x+1, y, 1); + hline(x+1, y+6, 1); + hline(x+9, y, 1); + hline(x+9, y+6, 1); + end; + if (not marked) then exit; + case ic of + TMarkIcon.Checkbox: + begin + for f := 0 to 4 do + begin + vline(x+3+f, y+1+f, 1); + vline(x+7-f, y+1+f, 1); + end; + end; + TMarkIcon.Radiobox: + begin + hline(x+4, y+1, 3); + hline(x+3, y+2, 5); + hline(x+3, y+3, 5); + hline(x+3, y+4, 5); + hline(x+4, y+5, 3); + end; + end; end; -function drawText8PropXC (x, y: Integer; const s: AnsiString; constref clr: TGxRGBA): Integer; + +function TGxContext.iconWinWidth (ic: TWinIcon): Integer; begin result := 9; end; +function TGxContext.iconWinHeight (ic: TWinIcon): Integer; begin result := 8; end; + +procedure TGxContext.drawIconWin (ic: TWinIcon; x, y: Integer; pressed: Boolean); +var + f: Integer; begin - if (prfont8texid = 0) then createFonts(); - x -= textWidth8(s) div 2; - result := drawTextInternal(8, x, y, s, clr, prfont8texid, kgiFont8PropWidth, true); + if (not mActive) or (mClipRect.w < 1) or (mClipRect.h < 1) or (mColor.a = 0) then exit; + if pressed then rect(x, y, 9, 8); + for f := 1 to 5 do + begin + vline(x+1+f, y+f, 1); + vline(x+1+6-f, y+f, 1); + end; end; // ////////////////////////////////////////////////////////////////////////// // +(* procedure oglRestoreMode (doClear: Boolean); begin oglSetup2D(fuiScrWdt, fuiScrHgt); @@ -1051,21 +1025,20 @@ begin glLoadIdentity(); //glScalef(4, 4, 1); end; +*) //procedure onWinFocus (); begin end; //procedure onWinBlur (); begin fuiResetKMState(true); end; -procedure onPreRender (); begin oglRestoreMode(gGfxDoClear); end; - -procedure onPostRender (); begin oglRestoreMode(false); oglDrawCursor(); end; +//procedure onPreRender (); begin oglRestoreMode(gGfxDoClear); end; +procedure onPostRender (); begin oglDrawCursor(); end; procedure onInit (); begin - oglSetup2D(fuiScrWdt, fuiScrHgt); - + //oglSetup2D(fuiScrWdt, fuiScrHgt); createCursorTexture(); - createFonts(); + oglInitFonts(); end; procedure onDeinit (); @@ -1073,7 +1046,7 @@ begin fuiResetKMState(false); if (curtexid <> 0) then glDeleteTextures(1, @curtexid); curtexid := 0; - deleteFonts(); + oglDeinitFonts(); fuiSetButState(0); fuiSetModState(0); fuiSetMouseX(0); @@ -1082,10 +1055,12 @@ end; // ////////////////////////////////////////////////////////////////////////// // -begin +initialization + savedGLState := TSavedGLState.Create(false); + createFonts(); //winFocusCB := onWinFocus; //winBlurCB := onWinBlur; - prerenderFrameCB := onPreRender; + //prerenderFrameCB := onPreRender; postrenderFrameCB := onPostRender; oglInitCB := onInit; oglDeinitCB := onDeinit; diff --git a/src/flexui/fui_gfx_gl_cursor.inc b/src/flexui/fui_gfx_gl_cursor.inc new file mode 100644 index 0000000..1884c9f --- /dev/null +++ b/src/flexui/fui_gfx_gl_cursor.inc @@ -0,0 +1,171 @@ +(* coded by Ketmar // Invisible Vector + * Understanding is not required. Only obedience. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *) +// ////////////////////////////////////////////////////////////////////////// // +// cursor (hi, Death Track!) +const curTexWidth = 32; +const curTexHeight = 32; +const curWidth = 17; +const curHeight = 23; + +const cursorImg: array[0..curWidth*curHeight-1] of Byte = ( + 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 3,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 3,3,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0, + 3,3,4,2,2,0,0,0,0,0,0,0,0,0,0,0,0, + 3,3,4,4,2,2,0,0,0,0,0,0,0,0,0,0,0, + 3,3,4,4,4,2,2,0,0,0,0,0,0,0,0,0,0, + 3,3,4,4,4,4,2,2,0,0,0,0,0,0,0,0,0, + 3,3,4,4,4,5,6,2,2,0,0,0,0,0,0,0,0, + 3,3,4,4,5,6,7,5,2,2,0,0,0,0,0,0,0, + 3,3,4,5,6,7,5,4,5,2,2,0,0,0,0,0,0, + 3,3,5,6,7,5,4,5,6,7,2,2,0,0,0,0,0, + 3,3,6,7,5,4,5,6,7,7,7,2,2,0,0,0,0, + 3,3,7,5,4,5,6,7,7,7,7,7,2,2,0,0,0, + 3,3,5,4,5,6,8,8,8,8,8,8,8,8,2,0,0, + 3,3,4,5,6,3,8,8,8,8,8,8,8,8,8,0,0, + 3,3,5,6,3,3,0,0,0,0,0,0,0,0,0,0,0, + 3,3,6,3,3,0,0,0,0,0,0,0,0,0,0,0,0, + 3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0, + 3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +); +const cursorPal: array[0..9*4-1] of Byte = ( + 0, 0, 0, 0, + 0, 0, 0, 92, // shadow + 85,255,255,255, + 85, 85,255,255, + 255, 85, 85,255, + 170, 0,170,255, + 85, 85, 85,255, + 0, 0, 0,255, + 0, 0,170,255 +); + + +var + curtexid: GLuint = 0; + + +procedure createCursorTexture (); +var + tex, tpp: PByte; + c: Integer; + x, y: Integer; +begin + if (curtexid <> 0) then exit; //begin glDeleteTextures(1, @curtexid); curtexid := 0; end; + + GetMem(tex, curTexWidth*curTexHeight*4); + try + FillChar(tex^, curTexWidth*curTexHeight*4, 0); + + // draw shadow + for y := 0 to curHeight-1 do + begin + for x := 0 to curWidth-1 do + begin + if (cursorImg[y*curWidth+x] <> 0) then + begin + c := 1*4; + tpp := tex+((y+1)*(curTexWidth*4)+(x+3)*4); + tpp^ := cursorPal[c+0]; Inc(tpp); + tpp^ := cursorPal[c+1]; Inc(tpp); + tpp^ := cursorPal[c+2]; Inc(tpp); + tpp^ := cursorPal[c+3]; Inc(tpp); + tpp^ := cursorPal[c+0]; Inc(tpp); + tpp^ := cursorPal[c+1]; Inc(tpp); + tpp^ := cursorPal[c+2]; Inc(tpp); + tpp^ := cursorPal[c+3]; Inc(tpp); + end; + end; + end; + + // draw cursor + for y := 0 to curHeight-1 do + begin + for x := 0 to curWidth-1 do + begin + c := cursorImg[y*curWidth+x]*4; + if (c <> 0) then + begin + tpp := tex+(y*(curTexWidth*4)+x*4); + tpp^ := cursorPal[c+0]; Inc(tpp); + tpp^ := cursorPal[c+1]; Inc(tpp); + tpp^ := cursorPal[c+2]; Inc(tpp); + tpp^ := cursorPal[c+3]; Inc(tpp); + end; + end; + end; + + glGenTextures(1, @curtexid); + if (curtexid = 0) then raise Exception.Create('can''t create cursor texture'); + + glBindTexture(GL_TEXTURE_2D, curtexid); + 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); + + //GLfloat[4] bclr = 0.0; + //glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, bclr.ptr); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, curTexWidth, curTexHeight, 0, GL_RGBA{gltt}, GL_UNSIGNED_BYTE, tex); + glFlush(); + finally + FreeMem(tex); + end; +end; + + +procedure oglDrawCursorAt (msX, msY: Integer); +var + sst: TSavedGLState; +begin + //if (curtexid = 0) then createCursorTexture() else glBindTexture(GL_TEXTURE_2D, curtexid); + sst := TSavedGLState.Create(true); + try + oglSetup2D(fuiScrWdt, fuiScrHgt); + glBindTexture(GL_TEXTURE_2D, curtexid); + // blend it + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_TEXTURE_2D); + glDisable(GL_STENCIL_TEST); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_LIGHTING); + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + // color and opacity + glColor4f(1, 1, 1, 1.0); + //Dec(msX, 2); + glBegin(GL_QUADS); + glTexCoord2f(0.0, 0.0); glVertex2i(msX, msY); // top-left + glTexCoord2f(1.0, 0.0); glVertex2i(msX+curTexWidth, msY); // top-right + glTexCoord2f(1.0, 1.0); glVertex2i(msX+curTexWidth, msY+curTexHeight); // bottom-right + glTexCoord2f(0.0, 1.0); glVertex2i(msX, msY+curTexHeight); // bottom-left + glEnd(); + //Inc(msX, 2); + //glDisable(GL_BLEND); + //glDisable(GL_TEXTURE_2D); + //glColor4f(1, 1, 1, 1); + //glBindTexture(GL_TEXTURE_2D, 0); + finally + sst.restore(); + end; +end; diff --git a/src/flexui/fui_gfx_gl_fonts.inc b/src/flexui/fui_gfx_gl_fonts.inc new file mode 100644 index 0000000..c3372e2 --- /dev/null +++ b/src/flexui/fui_gfx_gl_fonts.inc @@ -0,0 +1,311 @@ +(* coded by Ketmar // Invisible Vector + * Understanding is not required. Only obedience. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *) +// ////////////////////////////////////////////////////////////////////////// // +// fonts +const kgiFont6: array[0..256*8-1] of Byte = ( +$00,$00,$00,$00,$00,$00,$00,$00,$3c,$42,$a5,$81,$a5,$99,$42,$3c,$3c,$7e,$db,$ff,$ff,$db,$66,$3c,$6c,$fe, +$fe,$fe,$7c,$38,$10,$00,$10,$38,$7c,$fe,$7c,$38,$10,$00,$10,$38,$54,$fe,$54,$10,$38,$00,$10,$38,$7c,$fe, +$fe,$10,$38,$00,$00,$00,$00,$30,$30,$00,$00,$00,$ff,$ff,$ff,$e7,$e7,$ff,$ff,$ff,$38,$44,$82,$82,$82,$44, +$38,$00,$c7,$bb,$7d,$7d,$7d,$bb,$c7,$ff,$0f,$03,$05,$79,$88,$88,$88,$70,$38,$44,$44,$44,$38,$10,$7c,$10, +$30,$28,$24,$24,$28,$20,$e0,$c0,$3c,$24,$3c,$24,$24,$e4,$dc,$18,$10,$54,$38,$ee,$38,$54,$10,$00,$10,$10, +$10,$7c,$10,$10,$10,$10,$10,$10,$10,$ff,$00,$00,$00,$00,$00,$00,$00,$ff,$10,$10,$10,$10,$10,$10,$10,$f0, +$10,$10,$10,$10,$10,$10,$10,$1f,$10,$10,$10,$10,$10,$10,$10,$ff,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10, +$10,$10,$00,$00,$00,$ff,$00,$00,$00,$00,$00,$00,$00,$1f,$10,$10,$10,$10,$00,$00,$00,$f0,$10,$10,$10,$10, +$10,$10,$10,$1f,$00,$00,$00,$00,$10,$10,$10,$f0,$00,$00,$00,$00,$81,$42,$24,$18,$18,$24,$42,$81,$01,$02, +$04,$08,$10,$20,$40,$80,$80,$40,$20,$10,$08,$04,$02,$01,$00,$10,$10,$ff,$10,$10,$00,$00,$00,$00,$00,$00, +$00,$00,$00,$00,$20,$20,$20,$20,$00,$00,$20,$00,$50,$50,$50,$00,$00,$00,$00,$00,$50,$50,$f8,$50,$f8,$50, +$50,$00,$20,$78,$a0,$70,$28,$f0,$20,$00,$c0,$c8,$10,$20,$40,$98,$18,$00,$40,$a0,$40,$a8,$90,$98,$60,$00, +$10,$20,$40,$00,$00,$00,$00,$00,$10,$20,$40,$40,$40,$20,$10,$00,$40,$20,$10,$10,$10,$20,$40,$00,$88,$50, +$20,$f8,$20,$50,$88,$00,$00,$20,$20,$f8,$20,$20,$00,$00,$00,$00,$00,$00,$00,$20,$20,$40,$00,$00,$00,$78, +$00,$00,$00,$00,$00,$00,$00,$00,$00,$60,$60,$00,$00,$00,$08,$10,$20,$40,$80,$00,$70,$88,$98,$a8,$c8,$88, +$70,$00,$20,$60,$a0,$20,$20,$20,$f8,$00,$70,$88,$08,$10,$60,$80,$f8,$00,$70,$88,$08,$30,$08,$88,$70,$00, +$10,$30,$50,$90,$f8,$10,$10,$00,$f8,$80,$e0,$10,$08,$10,$e0,$00,$30,$40,$80,$f0,$88,$88,$70,$00,$f8,$88, +$10,$20,$20,$20,$20,$00,$70,$88,$88,$70,$88,$88,$70,$00,$70,$88,$88,$78,$08,$10,$60,$00,$00,$00,$20,$00, +$00,$20,$00,$00,$00,$00,$20,$00,$00,$20,$20,$40,$18,$30,$60,$c0,$60,$30,$18,$00,$00,$00,$f8,$00,$f8,$00, +$00,$00,$c0,$60,$30,$18,$30,$60,$c0,$00,$70,$88,$08,$10,$20,$00,$20,$00,$70,$88,$08,$68,$a8,$a8,$70,$00, +$20,$50,$88,$88,$f8,$88,$88,$00,$f0,$48,$48,$70,$48,$48,$f0,$00,$30,$48,$80,$80,$80,$48,$30,$00,$e0,$50, +$48,$48,$48,$50,$e0,$00,$f8,$80,$80,$f0,$80,$80,$f8,$00,$f8,$80,$80,$f0,$80,$80,$80,$00,$70,$88,$80,$b8, +$88,$88,$70,$00,$88,$88,$88,$f8,$88,$88,$88,$00,$70,$20,$20,$20,$20,$20,$70,$00,$38,$10,$10,$10,$90,$90, +$60,$00,$88,$90,$a0,$c0,$a0,$90,$88,$00,$80,$80,$80,$80,$80,$80,$f8,$00,$88,$d8,$a8,$a8,$88,$88,$88,$00, +$88,$c8,$c8,$a8,$98,$98,$88,$00,$70,$88,$88,$88,$88,$88,$70,$00,$f0,$88,$88,$f0,$80,$80,$80,$00,$70,$88, +$88,$88,$a8,$90,$68,$00,$f0,$88,$88,$f0,$a0,$90,$88,$00,$70,$88,$80,$70,$08,$88,$70,$00,$f8,$20,$20,$20, +$20,$20,$20,$00,$88,$88,$88,$88,$88,$88,$70,$00,$88,$88,$88,$88,$50,$50,$20,$00,$88,$88,$88,$a8,$a8,$d8, +$88,$00,$88,$88,$50,$20,$50,$88,$88,$00,$88,$88,$88,$70,$20,$20,$20,$00,$f8,$08,$10,$20,$40,$80,$f8,$00, +$70,$40,$40,$40,$40,$40,$70,$00,$00,$00,$80,$40,$20,$10,$08,$00,$70,$10,$10,$10,$10,$10,$70,$00,$20,$50, +$88,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$f8,$00,$40,$20,$10,$00,$00,$00,$00,$00,$00,$00,$70,$08, +$78,$88,$78,$00,$80,$80,$b0,$c8,$88,$c8,$b0,$00,$00,$00,$70,$88,$80,$88,$70,$00,$08,$08,$68,$98,$88,$98, +$68,$00,$00,$00,$70,$88,$f8,$80,$70,$00,$10,$28,$20,$f8,$20,$20,$20,$00,$00,$00,$68,$98,$98,$68,$08,$70, +$80,$80,$f0,$88,$88,$88,$88,$00,$20,$00,$60,$20,$20,$20,$70,$00,$10,$00,$30,$10,$10,$10,$90,$60,$40,$40, +$48,$50,$60,$50,$48,$00,$60,$20,$20,$20,$20,$20,$70,$00,$00,$00,$d0,$a8,$a8,$a8,$a8,$00,$00,$00,$b0,$c8, +$88,$88,$88,$00,$00,$00,$70,$88,$88,$88,$70,$00,$00,$00,$b0,$c8,$c8,$b0,$80,$80,$00,$00,$68,$98,$98,$68, +$08,$08,$00,$00,$b0,$c8,$80,$80,$80,$00,$00,$00,$78,$80,$f0,$08,$f0,$00,$40,$40,$f0,$40,$40,$48,$30,$00, +$00,$00,$90,$90,$90,$90,$68,$00,$00,$00,$88,$88,$88,$50,$20,$00,$00,$00,$88,$a8,$a8,$a8,$50,$00,$00,$00, +$88,$50,$20,$50,$88,$00,$00,$00,$88,$88,$98,$68,$08,$70,$00,$00,$f8,$10,$20,$40,$f8,$00,$18,$20,$20,$40, +$20,$20,$18,$00,$20,$20,$20,$00,$20,$20,$20,$00,$c0,$20,$20,$10,$20,$20,$c0,$00,$40,$a8,$10,$00,$00,$00, +$00,$00,$00,$00,$20,$50,$f8,$00,$00,$00,$00,$00,$00,$00,$00,$00,$ff,$ff,$f0,$f0,$f0,$f0,$0f,$0f,$0f,$0f, +$00,$00,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3c,$3c,$00,$00,$00,$ff,$ff, +$ff,$ff,$ff,$ff,$00,$00,$c0,$c0,$c0,$c0,$c0,$c0,$c0,$c0,$0f,$0f,$0f,$0f,$f0,$f0,$f0,$f0,$fc,$fc,$fc,$fc, +$fc,$fc,$fc,$fc,$03,$03,$03,$03,$03,$03,$03,$03,$3f,$3f,$3f,$3f,$3f,$3f,$3f,$3f,$11,$22,$44,$88,$11,$22, +$44,$88,$88,$44,$22,$11,$88,$44,$22,$11,$fe,$7c,$38,$10,$00,$00,$00,$00,$00,$00,$00,$00,$10,$38,$7c,$fe, +$80,$c0,$e0,$f0,$e0,$c0,$80,$00,$01,$03,$07,$0f,$07,$03,$01,$00,$ff,$7e,$3c,$18,$18,$3c,$7e,$ff,$81,$c3, +$e7,$ff,$ff,$e7,$c3,$81,$f0,$f0,$f0,$f0,$00,$00,$00,$00,$00,$00,$00,$00,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f, +$00,$00,$00,$00,$00,$00,$00,$00,$f0,$f0,$f0,$f0,$33,$33,$cc,$cc,$33,$33,$cc,$cc,$00,$20,$20,$50,$50,$88, +$f8,$00,$20,$20,$70,$20,$70,$20,$20,$00,$00,$00,$00,$50,$88,$a8,$50,$00,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff, +$00,$00,$00,$00,$ff,$ff,$ff,$ff,$f0,$f0,$f0,$f0,$f0,$f0,$f0,$f0,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$ff,$ff, +$ff,$ff,$00,$00,$00,$00,$00,$00,$68,$90,$90,$90,$68,$00,$30,$48,$48,$70,$48,$48,$70,$c0,$f8,$88,$80,$80, +$80,$80,$80,$00,$00,$50,$70,$88,$f8,$80,$70,$00,$00,$00,$78,$80,$f0,$80,$78,$00,$00,$00,$78,$90,$90,$90, +$60,$00,$20,$00,$60,$20,$20,$20,$70,$00,$50,$00,$70,$20,$20,$20,$70,$00,$f8,$20,$70,$a8,$a8,$70,$20,$f8, +$20,$50,$88,$f8,$88,$50,$20,$00,$70,$88,$88,$88,$50,$50,$d8,$00,$30,$40,$40,$20,$50,$50,$50,$20,$00,$00, +$00,$50,$a8,$a8,$50,$00,$08,$70,$a8,$a8,$a8,$70,$80,$00,$38,$40,$80,$f8,$80,$40,$38,$00,$70,$88,$88,$88, +$88,$88,$88,$00,$00,$f8,$00,$f8,$00,$f8,$00,$00,$20,$20,$f8,$20,$20,$00,$f8,$00,$c0,$30,$08,$30,$c0,$00, +$f8,$00,$50,$f8,$80,$f0,$80,$80,$f8,$00,$78,$80,$80,$f0,$80,$80,$78,$00,$20,$20,$20,$20,$20,$20,$a0,$40, +$70,$20,$20,$20,$20,$20,$70,$00,$50,$70,$20,$20,$20,$20,$70,$00,$00,$18,$24,$24,$18,$00,$00,$00,$00,$30, +$78,$78,$30,$00,$00,$00,$00,$00,$00,$00,$30,$00,$00,$00,$3e,$20,$20,$20,$a0,$60,$20,$00,$a0,$50,$50,$50, +$00,$00,$00,$00,$40,$a0,$20,$40,$e0,$00,$00,$00,$00,$38,$38,$38,$38,$38,$38,$00,$3c,$42,$99,$a1,$a1,$99, +$42,$3c,$00,$00,$90,$a8,$e8,$a8,$90,$00,$00,$00,$60,$10,$70,$90,$68,$00,$00,$00,$f0,$80,$f0,$88,$f0,$00, +$00,$00,$90,$90,$90,$f8,$08,$00,$00,$00,$30,$50,$50,$70,$88,$00,$00,$00,$70,$88,$f8,$80,$70,$00,$00,$20, +$70,$a8,$a8,$70,$20,$00,$00,$00,$78,$48,$40,$40,$40,$00,$00,$00,$88,$50,$20,$50,$88,$00,$00,$00,$88,$98, +$a8,$c8,$88,$00,$00,$50,$20,$00,$98,$a8,$c8,$00,$00,$00,$90,$a0,$c0,$a0,$90,$00,$00,$00,$38,$28,$28,$48, +$88,$00,$00,$00,$88,$d8,$a8,$88,$88,$00,$00,$00,$88,$88,$f8,$88,$88,$00,$00,$00,$70,$88,$88,$88,$70,$00, +$00,$00,$78,$48,$48,$48,$48,$00,$00,$00,$78,$88,$78,$28,$48,$00,$00,$00,$f0,$88,$f0,$80,$80,$00,$00,$00, +$78,$80,$80,$80,$78,$00,$00,$00,$f8,$20,$20,$20,$20,$00,$00,$00,$88,$50,$20,$40,$80,$00,$00,$00,$a8,$70, +$20,$70,$a8,$00,$00,$00,$f0,$48,$70,$48,$f0,$00,$00,$00,$40,$40,$70,$48,$70,$00,$00,$00,$88,$88,$c8,$a8, +$c8,$00,$00,$00,$f0,$08,$70,$08,$f0,$00,$00,$00,$a8,$a8,$a8,$a8,$f8,$00,$00,$00,$70,$88,$38,$88,$70,$00, +$00,$00,$a8,$a8,$a8,$f8,$08,$00,$00,$00,$48,$48,$78,$08,$08,$00,$00,$00,$c0,$40,$70,$48,$70,$00,$90,$a8, +$a8,$e8,$a8,$a8,$90,$00,$20,$50,$88,$88,$f8,$88,$88,$00,$f8,$88,$80,$f0,$88,$88,$f0,$00,$90,$90,$90,$90, +$90,$f8,$08,$00,$38,$28,$28,$48,$48,$f8,$88,$00,$f8,$80,$80,$f0,$80,$80,$f8,$00,$20,$70,$a8,$a8,$a8,$70, +$20,$00,$f8,$88,$88,$80,$80,$80,$80,$00,$88,$88,$50,$20,$50,$88,$88,$00,$88,$88,$98,$a8,$c8,$88,$88,$00, +$50,$20,$88,$98,$a8,$c8,$88,$00,$88,$90,$a0,$c0,$a0,$90,$88,$00,$18,$28,$48,$48,$48,$48,$88,$00,$88,$d8, +$a8,$a8,$88,$88,$88,$00,$88,$88,$88,$f8,$88,$88,$88,$00,$70,$88,$88,$88,$88,$88,$70,$00,$f8,$88,$88,$88, +$88,$88,$88,$00,$78,$88,$88,$78,$28,$48,$88,$00,$f0,$88,$88,$f0,$80,$80,$80,$00,$70,$88,$80,$80,$80,$88, +$70,$00,$f8,$20,$20,$20,$20,$20,$20,$00,$88,$88,$88,$50,$20,$40,$80,$00,$a8,$a8,$70,$20,$70,$a8,$a8,$00, +$f0,$48,$48,$70,$48,$48,$f0,$00,$80,$80,$80,$f0,$88,$88,$f0,$00,$88,$88,$88,$c8,$a8,$a8,$c8,$00,$f0,$08, +$08,$30,$08,$08,$f0,$00,$a8,$a8,$a8,$a8,$a8,$a8,$f8,$00,$70,$88,$08,$78,$08,$88,$70,$00,$a8,$a8,$a8,$a8, +$a8,$f8,$08,$00,$88,$88,$88,$88,$78,$08,$08,$00,$c0,$40,$40,$70,$48,$48,$70,$00 +); + +const kgiFont8: array[0..256*8-1] of Byte = ( +$00,$00,$00,$00,$00,$00,$00,$00,$7e,$81,$a5,$81,$bd,$99,$81,$7e,$7e,$ff,$db,$ff,$c3,$e7,$ff,$7e,$6c,$fe, +$fe,$fe,$7c,$38,$10,$00,$10,$38,$7c,$fe,$7c,$38,$10,$00,$38,$7c,$38,$fe,$fe,$d6,$10,$38,$10,$10,$38,$7c, +$fe,$7c,$10,$38,$00,$00,$18,$3c,$3c,$18,$00,$00,$ff,$ff,$e7,$c3,$c3,$e7,$ff,$ff,$00,$3c,$66,$42,$42,$66, +$3c,$00,$ff,$c3,$99,$bd,$bd,$99,$c3,$ff,$0f,$07,$0f,$7d,$cc,$cc,$cc,$78,$3c,$66,$66,$66,$3c,$18,$7e,$18, +$3f,$33,$3f,$30,$30,$70,$f0,$e0,$7f,$63,$7f,$63,$63,$67,$e6,$c0,$99,$5a,$3c,$e7,$e7,$3c,$5a,$99,$80,$e0, +$f8,$fe,$f8,$e0,$80,$00,$02,$0e,$3e,$fe,$3e,$0e,$02,$00,$18,$3c,$7e,$18,$18,$7e,$3c,$18,$66,$66,$66,$66, +$66,$00,$66,$00,$7f,$db,$db,$7b,$1b,$1b,$1b,$00,$7e,$c3,$78,$cc,$cc,$78,$8c,$f8,$00,$00,$00,$00,$7e,$7e, +$7e,$00,$18,$3c,$7e,$18,$7e,$3c,$18,$ff,$18,$3c,$7e,$18,$18,$18,$18,$00,$18,$18,$18,$18,$7e,$3c,$18,$00, +$00,$18,$0c,$fe,$0c,$18,$00,$00,$00,$30,$60,$fe,$60,$30,$00,$00,$00,$00,$c0,$c0,$c0,$fe,$00,$00,$00,$24, +$66,$ff,$66,$24,$00,$00,$00,$18,$3c,$7e,$ff,$ff,$00,$00,$00,$ff,$ff,$7e,$3c,$18,$00,$00,$00,$00,$00,$00, +$00,$00,$00,$00,$30,$78,$78,$30,$30,$00,$30,$00,$6c,$6c,$6c,$00,$00,$00,$00,$00,$6c,$6c,$fe,$6c,$fe,$6c, +$6c,$00,$30,$7c,$c0,$78,$0c,$f8,$30,$00,$00,$c6,$cc,$18,$30,$66,$c6,$00,$38,$6c,$38,$76,$dc,$cc,$76,$00, +$60,$60,$c0,$00,$00,$00,$00,$00,$18,$30,$60,$60,$60,$30,$18,$00,$60,$30,$18,$18,$18,$30,$60,$00,$00,$66, +$3c,$ff,$3c,$66,$00,$00,$00,$30,$30,$fc,$30,$30,$00,$00,$00,$00,$00,$00,$00,$70,$30,$60,$00,$00,$00,$fc, +$00,$00,$00,$00,$00,$00,$00,$00,$00,$30,$30,$00,$06,$0c,$18,$30,$60,$c0,$80,$00,$78,$cc,$dc,$fc,$ec,$cc, +$78,$00,$30,$f0,$30,$30,$30,$30,$fc,$00,$78,$cc,$0c,$38,$60,$cc,$fc,$00,$78,$cc,$0c,$38,$0c,$cc,$78,$00, +$1c,$3c,$6c,$cc,$fe,$0c,$0c,$00,$fc,$c0,$f8,$0c,$0c,$cc,$78,$00,$38,$60,$c0,$f8,$cc,$cc,$78,$00,$fc,$cc, +$0c,$18,$30,$60,$60,$00,$78,$cc,$cc,$78,$cc,$cc,$78,$00,$78,$cc,$cc,$7c,$0c,$18,$70,$00,$00,$00,$30,$30, +$00,$30,$30,$00,$00,$00,$30,$30,$00,$70,$30,$60,$18,$30,$60,$c0,$60,$30,$18,$00,$00,$00,$fc,$00,$fc,$00, +$00,$00,$60,$30,$18,$0c,$18,$30,$60,$00,$78,$cc,$0c,$18,$30,$00,$30,$00,$7c,$c6,$de,$de,$de,$c0,$78,$00, +$30,$78,$cc,$cc,$fc,$cc,$cc,$00,$fc,$66,$66,$7c,$66,$66,$fc,$00,$3c,$66,$c0,$c0,$c0,$66,$3c,$00,$fc,$6c, +$66,$66,$66,$6c,$fc,$00,$fe,$62,$68,$78,$68,$62,$fe,$00,$fe,$62,$68,$78,$68,$60,$f0,$00,$3c,$66,$c0,$c0, +$ce,$66,$3e,$00,$cc,$cc,$cc,$fc,$cc,$cc,$cc,$00,$78,$30,$30,$30,$30,$30,$78,$00,$1e,$0c,$0c,$0c,$cc,$cc, +$78,$00,$e6,$66,$6c,$78,$6c,$66,$e6,$00,$f0,$60,$60,$60,$62,$66,$fe,$00,$c6,$ee,$fe,$d6,$c6,$c6,$c6,$00, +$c6,$e6,$f6,$de,$ce,$c6,$c6,$00,$38,$6c,$c6,$c6,$c6,$6c,$38,$00,$fc,$66,$66,$7c,$60,$60,$f0,$00,$78,$cc, +$cc,$cc,$dc,$78,$1c,$00,$fc,$66,$66,$7c,$78,$6c,$e6,$00,$78,$cc,$e0,$38,$1c,$cc,$78,$00,$fc,$b4,$30,$30, +$30,$30,$78,$00,$cc,$cc,$cc,$cc,$cc,$cc,$fc,$00,$cc,$cc,$cc,$cc,$cc,$78,$30,$00,$c6,$c6,$c6,$d6,$fe,$ee, +$c6,$00,$c6,$c6,$6c,$38,$6c,$c6,$c6,$00,$cc,$cc,$cc,$78,$30,$30,$78,$00,$fe,$cc,$98,$30,$62,$c6,$fe,$00, +$78,$60,$60,$60,$60,$60,$78,$00,$c0,$60,$30,$18,$0c,$06,$02,$00,$78,$18,$18,$18,$18,$18,$78,$00,$10,$38, +$6c,$c6,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$ff,$30,$30,$18,$00,$00,$00,$00,$00,$00,$00,$78,$0c, +$7c,$cc,$76,$00,$e0,$60,$7c,$66,$66,$66,$bc,$00,$00,$00,$78,$cc,$c0,$cc,$78,$00,$1c,$0c,$0c,$7c,$cc,$cc, +$76,$00,$00,$00,$78,$cc,$fc,$c0,$78,$00,$38,$6c,$60,$f0,$60,$60,$f0,$00,$00,$00,$76,$cc,$cc,$7c,$0c,$f8, +$e0,$60,$6c,$76,$66,$66,$e6,$00,$30,$00,$70,$30,$30,$30,$78,$00,$18,$00,$78,$18,$18,$18,$d8,$70,$e0,$60, +$66,$6c,$78,$6c,$e6,$00,$70,$30,$30,$30,$30,$30,$78,$00,$00,$00,$ec,$fe,$d6,$c6,$c6,$00,$00,$00,$f8,$cc, +$cc,$cc,$cc,$00,$00,$00,$78,$cc,$cc,$cc,$78,$00,$00,$00,$dc,$66,$66,$7c,$60,$f0,$00,$00,$76,$cc,$cc,$7c, +$0c,$1e,$00,$00,$d8,$6c,$6c,$60,$f0,$00,$00,$00,$7c,$c0,$78,$0c,$f8,$00,$10,$30,$7c,$30,$30,$34,$18,$00, +$00,$00,$cc,$cc,$cc,$cc,$76,$00,$00,$00,$cc,$cc,$cc,$78,$30,$00,$00,$00,$c6,$c6,$d6,$fe,$6c,$00,$00,$00, +$c6,$6c,$38,$6c,$c6,$00,$00,$00,$cc,$cc,$cc,$7c,$0c,$f8,$00,$00,$fc,$98,$30,$64,$fc,$00,$1c,$30,$30,$e0, +$30,$30,$1c,$00,$18,$18,$18,$00,$18,$18,$18,$00,$e0,$30,$30,$1c,$30,$30,$e0,$00,$76,$dc,$00,$00,$00,$00, +$00,$00,$10,$38,$6c,$c6,$c6,$c6,$fe,$00,$78,$cc,$c0,$cc,$78,$18,$0c,$78,$00,$cc,$00,$cc,$cc,$cc,$7e,$00, +$1c,$00,$78,$cc,$fc,$c0,$78,$00,$7e,$c3,$3c,$06,$3e,$66,$3f,$00,$cc,$00,$78,$0c,$7c,$cc,$7e,$00,$e0,$00, +$78,$0c,$7c,$cc,$7e,$00,$30,$30,$78,$0c,$7c,$cc,$7e,$00,$00,$00,$7c,$c0,$c0,$7c,$06,$3c,$7e,$c3,$3c,$66, +$7e,$60,$3c,$00,$cc,$00,$78,$cc,$fc,$c0,$78,$00,$e0,$00,$78,$cc,$fc,$c0,$78,$00,$cc,$00,$70,$30,$30,$30, +$78,$00,$7c,$c6,$38,$18,$18,$18,$3c,$00,$e0,$00,$70,$30,$30,$30,$78,$00,$cc,$30,$78,$cc,$cc,$fc,$cc,$00, +$30,$30,$00,$78,$cc,$fc,$cc,$00,$1c,$00,$fc,$60,$78,$60,$fc,$00,$00,$00,$7f,$0c,$7f,$cc,$7f,$00,$3e,$6c, +$cc,$fe,$cc,$cc,$ce,$00,$78,$cc,$00,$78,$cc,$cc,$78,$00,$00,$cc,$00,$78,$cc,$cc,$78,$00,$00,$e0,$00,$78, +$cc,$cc,$78,$00,$78,$cc,$00,$cc,$cc,$cc,$7e,$00,$00,$e0,$00,$cc,$cc,$cc,$7e,$00,$00,$cc,$00,$cc,$cc,$fc, +$0c,$f8,$c6,$38,$7c,$c6,$c6,$7c,$38,$00,$cc,$00,$cc,$cc,$cc,$cc,$78,$00,$18,$18,$7e,$c0,$c0,$7e,$18,$18, +$38,$6c,$64,$f0,$60,$e6,$fc,$00,$cc,$cc,$78,$fc,$30,$fc,$30,$00,$f0,$d8,$d8,$f4,$cc,$de,$cc,$0e,$0e,$1b, +$18,$7e,$18,$18,$d8,$70,$1c,$00,$78,$0c,$7c,$cc,$7e,$00,$38,$00,$70,$30,$30,$30,$78,$00,$00,$1c,$00,$78, +$cc,$cc,$78,$00,$00,$1c,$00,$cc,$cc,$cc,$7e,$00,$00,$f8,$00,$f8,$cc,$cc,$cc,$00,$fc,$00,$cc,$ec,$fc,$dc, +$cc,$00,$3c,$6c,$6c,$3e,$00,$7e,$00,$00,$3c,$66,$66,$3c,$00,$7e,$00,$00,$30,$00,$30,$60,$c0,$cc,$78,$00, +$00,$00,$00,$fc,$c0,$c0,$00,$00,$00,$00,$00,$fc,$0c,$0c,$00,$00,$c6,$cc,$d8,$3e,$63,$ce,$98,$1f,$c6,$cc, +$d8,$f3,$67,$cf,$9f,$03,$00,$18,$00,$18,$18,$3c,$3c,$18,$00,$33,$66,$cc,$66,$33,$00,$00,$00,$cc,$66,$33, +$66,$cc,$00,$00,$22,$88,$22,$88,$22,$88,$22,$88,$55,$aa,$55,$aa,$55,$aa,$55,$aa,$dc,$76,$dc,$76,$dc,$76, +$dc,$76,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$f8,$18,$18,$18,$18,$18,$f8,$18,$f8,$18,$18,$18, +$36,$36,$36,$36,$f6,$36,$36,$36,$00,$00,$00,$00,$fe,$36,$36,$36,$00,$00,$f8,$18,$f8,$18,$18,$18,$36,$36, +$f6,$06,$f6,$36,$36,$36,$36,$36,$36,$36,$36,$36,$36,$36,$00,$00,$fe,$06,$f6,$36,$36,$36,$36,$36,$f6,$06, +$fe,$00,$00,$00,$36,$36,$36,$36,$fe,$00,$00,$00,$18,$18,$f8,$18,$f8,$00,$00,$00,$00,$00,$00,$00,$f8,$18, +$18,$18,$18,$18,$18,$18,$1f,$00,$00,$00,$18,$18,$18,$18,$ff,$00,$00,$00,$00,$00,$00,$00,$ff,$18,$18,$18, +$18,$18,$18,$18,$1f,$18,$18,$18,$00,$00,$00,$00,$ff,$00,$00,$00,$18,$18,$18,$18,$ff,$18,$18,$18,$18,$18, +$1f,$18,$1f,$18,$18,$18,$36,$36,$36,$36,$37,$36,$36,$36,$36,$36,$37,$30,$3f,$00,$00,$00,$00,$00,$3f,$30, +$37,$36,$36,$36,$36,$36,$f7,$00,$ff,$00,$00,$00,$00,$00,$ff,$00,$f7,$36,$36,$36,$36,$36,$37,$30,$37,$36, +$36,$36,$00,$00,$ff,$00,$ff,$00,$00,$00,$36,$36,$f7,$00,$f7,$36,$36,$36,$18,$18,$ff,$00,$ff,$00,$00,$00, +$36,$36,$36,$36,$ff,$00,$00,$00,$00,$00,$ff,$00,$ff,$18,$18,$18,$00,$00,$00,$00,$ff,$36,$36,$36,$36,$36, +$36,$36,$3f,$00,$00,$00,$18,$18,$1f,$18,$1f,$00,$00,$00,$00,$00,$1f,$18,$1f,$18,$18,$18,$00,$00,$00,$00, +$3f,$36,$36,$36,$36,$36,$36,$36,$f7,$36,$36,$36,$18,$18,$ff,$00,$ff,$18,$18,$18,$18,$18,$18,$18,$f8,$00, +$00,$00,$00,$00,$00,$00,$1f,$18,$18,$18,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$00,$00,$00,$00,$ff,$ff,$ff,$ff, +$f0,$f0,$f0,$f0,$f0,$f0,$f0,$f0,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$ff,$ff,$ff,$ff,$00,$00,$00,$00,$00,$00, +$76,$dc,$c8,$dc,$76,$00,$00,$78,$cc,$f8,$cc,$f8,$c0,$c0,$00,$fe,$c6,$c0,$c0,$c0,$c0,$00,$00,$fe,$6c,$6c, +$6c,$6c,$6c,$00,$fe,$66,$30,$18,$30,$66,$fe,$00,$00,$00,$7e,$cc,$cc,$cc,$78,$00,$00,$66,$66,$66,$66,$7c, +$60,$c0,$00,$76,$dc,$18,$18,$18,$18,$00,$fc,$30,$78,$cc,$cc,$78,$30,$fc,$38,$6c,$c6,$fe,$c6,$6c,$38,$00, +$38,$6c,$c6,$c6,$6c,$6c,$ee,$00,$1c,$30,$18,$7c,$cc,$cc,$78,$00,$00,$00,$7e,$db,$db,$7e,$00,$00,$06,$0c, +$7e,$db,$db,$7e,$60,$c0,$3c,$60,$c0,$fc,$c0,$60,$3c,$00,$78,$cc,$cc,$cc,$cc,$cc,$cc,$00,$00,$fc,$00,$fc, +$00,$fc,$00,$00,$30,$30,$fc,$30,$30,$00,$fc,$00,$60,$30,$18,$30,$60,$00,$fc,$00,$18,$30,$60,$30,$18,$00, +$fc,$00,$0e,$1b,$1b,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$d8,$d8,$70,$30,$30,$00,$fc,$00,$30,$30,$00, +$00,$72,$9c,$00,$72,$9c,$00,$00,$38,$6c,$6c,$38,$00,$00,$00,$00,$00,$00,$00,$18,$18,$00,$00,$00,$00,$00, +$00,$00,$18,$00,$00,$00,$0f,$0c,$0c,$0c,$ec,$6c,$3c,$1c,$78,$6c,$6c,$6c,$6c,$00,$00,$00,$78,$0c,$38,$60, +$7c,$00,$00,$00,$00,$00,$3c,$3c,$3c,$3c,$00,$00,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff +); + +const kgiFont6PropWidth: array[0..256-1] of Byte = ( + $08,$08,$08,$07,$07,$07,$07,$04,$08,$07,$08,$08,$06,$06,$06,$07, + $06,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08, + $85,$21,$13,$05,$05,$05,$05,$13,$13,$13,$05,$05,$12,$14,$12,$05, + $05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$21,$12,$05,$05,$05,$05, + $05,$05,$05,$05,$05,$05,$05,$05,$05,$13,$05,$05,$05,$05,$05,$05, + $05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$13,$05,$13,$05,$05, + $13,$05,$05,$05,$05,$05,$05,$05,$05,$13,$04,$14,$13,$05,$05,$05, + $05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$14,$21,$04,$05,$08, + $08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$04, + $44,$08,$08,$08,$08,$08,$08,$08,$05,$04,$05,$08,$08,$08,$08,$08, + $05,$05,$05,$05,$05,$05,$13,$13,$05,$05,$05,$04,$05,$05,$05,$05, + $05,$05,$05,$05,$05,$03,$04,$04,$06,$05,$04,$07,$04,$03,$05,$08, + $05,$05,$05,$05,$05,$05,$05,$14,$05,$05,$05,$04,$05,$05,$05,$05, + $14,$05,$05,$05,$05,$05,$05,$05,$14,$05,$05,$05,$05,$05,$14,$05, + $05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05, + $05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05 +); + +const kgiFont8PropWidth: array[0..256-1] of Byte = ( + $08,$08,$08,$07,$07,$07,$07,$06,$08,$07,$08,$08,$07,$08,$08,$08, + $07,$07,$07,$07,$08,$08,$07,$08,$07,$07,$07,$07,$07,$08,$08,$08, + $85,$14,$15,$07,$06,$07,$07,$03,$14,$14,$08,$06,$13,$06,$22,$07, + $05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$22,$13,$05,$06,$15,$06, + $07,$06,$07,$07,$07,$07,$07,$07,$06,$14,$07,$07,$07,$07,$07,$07, + $07,$06,$07,$06,$06,$06,$06,$07,$07,$06,$07,$14,$07,$14,$07,$08, + $23,$07,$07,$06,$07,$06,$06,$07,$07,$14,$05,$07,$14,$07,$06,$06, + $07,$07,$06,$06,$15,$07,$06,$07,$07,$06,$06,$06,$32,$06,$07,$07, + $06,$07,$06,$08,$07,$07,$07,$07,$08,$06,$06,$06,$07,$05,$06,$06, + $06,$08,$07,$06,$06,$06,$07,$07,$06,$07,$06,$07,$07,$06,$07,$08, + $07,$05,$06,$07,$06,$06,$16,$16,$06,$06,$06,$08,$08,$06,$08,$08, + $08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08, + $38,$08,$08,$38,$08,$08,$38,$28,$28,$28,$08,$08,$28,$08,$08,$08, + $08,$08,$08,$28,$38,$38,$28,$08,$08,$08,$38,$08,$08,$08,$48,$08, + $07,$06,$07,$07,$07,$07,$07,$07,$06,$07,$07,$06,$08,$08,$06,$06, + $06,$06,$06,$06,$35,$05,$06,$07,$15,$32,$32,$08,$15,$15,$24,$08 +); + + +function createFontTexture (const font: PByte; const fontwdt: PByte; prop: Boolean): GLuint; +const + Width = 16*8; + Height = 16*8; +var + tex, tpp: PByte; + b: Byte; + cc: Integer; + x, y, dx, dy: Integer; +begin + GetMem(tex, Width*Height*4); + + for cc := 0 to 255 do + begin + x := (cc mod 16)*8; + y := (cc div 16)*8; + for dy := 0 to 7 do + begin + b := font[cc*8+dy]; + if prop then b := b shl (fontwdt[cc] shr 4); + tpp := tex+((y+dy)*(Width*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; + end; + end; + + glGenTextures(1, @result); + if (result = 0) then raise Exception.Create('can''t create Holmes font texture'); + + glBindTexture(GL_TEXTURE_2D, result); + 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); + + //GLfloat[4] bclr = 0.0; + //glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, bclr.ptr); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Width, Height, 0, GL_RGBA{gltt}, GL_UNSIGNED_BYTE, tex); + glFlush(); + + //FreeMem(tex); +end; + + +{ +var + font6texid: GLuint = 0; + font8texid: GLuint = 0; + prfont6texid: GLuint = 0; + prfont8texid: GLuint = 0; + + +procedure deleteFonts (); +begin + if (font6texid <> 0) then glDeleteTextures(1, @font6texid); + if (font8texid <> 0) then glDeleteTextures(1, @font8texid); + if (prfont6texid <> 0) then glDeleteTextures(1, @prfont6texid); + if (prfont8texid <> 0) then glDeleteTextures(1, @prfont8texid); + font6texid := 0; + font8texid := 0; + prfont6texid := 0; + prfont8texid := 0; +end; + + +procedure createFonts (); +begin + if (font6texid = 0) then font6texid := createFontTexture(kgiFont6, kgiFont6PropWidth, false); + if (font8texid = 0) then font8texid := createFontTexture(kgiFont8, kgiFont8PropWidth, false); + if (prfont6texid = 0) then prfont6texid := createFontTexture(kgiFont6, kgiFont6PropWidth, true); + if (prfont8texid = 0) then prfont8texid := createFontTexture(kgiFont8, kgiFont8PropWidth, true); +end; +} -- 2.29.2