1 (* coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
2 * Understanding is not required. Only obedience.
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 {$INCLUDE ../shared/a_modes.inc}
18 {$DEFINE FUI_TEXT_ICONS}
27 fui_common
, fui_events
;
30 // ////////////////////////////////////////////////////////////////////////// //
39 function charWidth (const ch
: AnsiChar): Integer; virtual; abstract;
40 function textWidth (const s
: AnsiString): Integer; virtual; abstract;
43 property name
: AnsiString read mName
;
44 property height
: Integer read mHeight
;
45 property baseLine
: Integer read mBaseLine
;
65 // for active contexts
72 function getFont (): AnsiString;
73 procedure setFont (const aname
: AnsiString);
75 procedure onActivate ();
76 procedure onDeactivate ();
78 procedure setColor (const clr
: TGxRGBA
);
80 procedure realizeClip (); // setup scissoring
82 procedure setClipOfs (const aofs
: TGxOfs
);
83 procedure setClipRect (const aclip
: TGxRect
);
86 constructor Create ();
87 destructor Destroy (); override;
89 procedure line (x1
, y1
, x2
, y2
: Integer);
90 procedure hline (x
, y
, len
: Integer);
91 procedure vline (x
, y
, len
: Integer);
92 procedure rect (x
, y
, w
, h
: Integer);
93 procedure fillRect (x
, y
, w
, h
: Integer);
94 procedure darkenRect (x
, y
, w
, h
: Integer; a
: Integer);
96 function charWidth (const ch
: AnsiChar): Integer;
97 function charHeight (const ch
: AnsiChar): Integer;
98 function textWidth (const s
: AnsiString): Integer;
99 function textHeight (const s
: AnsiString): Integer;
100 function drawChar (x
, y
: Integer; const ch
: AnsiChar): Integer; // returns char width
101 function drawText (x
, y
: Integer; const s
: AnsiString): Integer; // returns text width
103 function iconMarkWidth (ic
: TMarkIcon
): Integer;
104 function iconMarkHeight (ic
: TMarkIcon
): Integer;
105 procedure drawIconMark (ic
: TMarkIcon
; x
, y
: Integer; marked
: Boolean);
107 function iconWinWidth (ic
: TWinIcon
): Integer;
108 function iconWinHeight (ic
: TWinIcon
): Integer;
109 procedure drawIconWin (ic
: TWinIcon
; x
, y
: Integer; pressed
: Boolean);
111 procedure resetClip ();
113 function setOffset (constref aofs
: TGxOfs
): TGxOfs
; // returns previous offset
114 function setClip (constref aclip
: TGxRect
): TGxRect
; // returns previous clip
116 function combineClip (constref aclip
: TGxRect
): TGxRect
; // returns previous clip
119 procedure glSetScale (ascale
: Single);
120 procedure glSetTrans (ax
, ay
: Single);
121 procedure glSetScaleTrans (ascale
, ax
, ay
: Single);
124 property active
: Boolean read mActive
;
125 property color
: TGxRGBA read mColor write setColor
;
126 property font
: AnsiString read getFont write setFont
;
127 property offset
: TGxOfs read mClipOfs write setClipOfs
;
128 property clip
: TGxRect read mClipRect write setClipRect
; // clipping is unaffected by offset
132 // set active context; `ctx` can be `nil`
133 procedure gxSetContext (ctx
: TGxContext
; ascale
: Single=1.0);
134 procedure gxSetContextNoMatrix (ctx
: TGxContext
);
137 // setup 2D OpenGL mode; will be called automatically in `glInit()`
138 procedure oglSetup2D (winWidth
, winHeight
: Integer; upsideDown
: Boolean=false);
139 procedure oglSetup2DState (); // don't modify viewports and matrices
141 procedure oglDrawCursor ();
142 procedure oglDrawCursorAt (msX
, msY
: Integer);
146 // ////////////////////////////////////////////////////////////////////////// //
148 gGfxDoClear
: Boolean = true;
157 // ////////////////////////////////////////////////////////////////////////// //
158 // returns `false` if the color is transparent
159 // returns `false` if the color is transparent
160 function setupGLColor (constref clr
: TGxRGBA
): Boolean;
162 if (clr
.a
< 255) then
165 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
171 glColor4ub(clr
.r
, clr
.g
, clr
.b
, clr
.a
);
172 result
:= (clr
.a
<> 0);
175 function isScaled (): Boolean;
177 mt
: packed array [0..15] of Double;
179 glGetDoublev(GL_MODELVIEW_MATRIX
, @mt
[0]);
180 result
:= (mt
[0] <> 1.0) or (mt
[1*4+1] <> 1.0);
184 // ////////////////////////////////////////////////////////////////////////// //
185 //TODO: OpenGL framebuffers and shaders state
187 TSavedGLState
= record
190 gltextbinding
: GLint
;
192 //oldfbr, oldfbw: GLint;
193 glvport
: packed array [0..3] of GLint
;
197 constructor Create (dosave
: Boolean);
199 procedure restore ();
202 constructor TSavedGLState
.Create (dosave
: Boolean);
204 FillChar(self
, sizeof(self
), 0);
205 if (dosave
) then save();
208 procedure TSavedGLState
.save ();
210 if (saved
) then raise Exception
.Create('cannot save into already saved OpenGL state');
211 glGetIntegerv(GL_MATRIX_MODE
, @glmatmode
);
212 glGetIntegerv(GL_TEXTURE_BINDING_2D
, @gltextbinding
);
213 glGetIntegerv(GL_VIEWPORT
, @glvport
[0]);
214 //glGetIntegerv(GL_CURRENT_PROGRAM, &oldprg);
215 //glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &oldfbr);
216 //glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldfbw);
217 glMatrixMode(GL_PROJECTION
); glPushMatrix();
218 glMatrixMode(GL_MODELVIEW
); glPushMatrix();
219 glMatrixMode(GL_TEXTURE
); glPushMatrix();
220 glMatrixMode(GL_COLOR
); glPushMatrix();
221 glPushAttrib({GL_ENABLE_BIT|GL_COLOR_BUFFER_BIT|GL_CURRENT_BIT}GL_ALL_ATTRIB_BITS
); // let's play safe
225 procedure TSavedGLState
.restore ();
227 if (not saved
) then raise Exception
.Create('cannot restore unsaved OpenGL state');
228 glPopAttrib({GL_ENABLE_BIT});
229 glMatrixMode(GL_PROJECTION
); glPopMatrix();
230 glMatrixMode(GL_MODELVIEW
); glPopMatrix();
231 glMatrixMode(GL_TEXTURE
); glPopMatrix();
232 glMatrixMode(GL_COLOR
); glPopMatrix();
233 glMatrixMode(glmatmode
);
234 //if (glHasFunc!"glBindFramebufferEXT") glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, oldfbr);
235 //if (glHasFunc!"glBindFramebufferEXT") glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, oldfbw);
236 glBindTexture(GL_TEXTURE_2D
, gltextbinding
);
237 //if (glHasFunc!"glUseProgram") glUseProgram(oldprg);
238 glViewport(glvport
[0], glvport
[1], glvport
[2], glvport
[3]);
244 curCtx
: TGxContext
= nil;
245 savedGLState
: TSavedGLState
;
248 // ////////////////////////////////////////////////////////////////////////// //
249 // set active context; `ctx` can be `nil`
250 procedure gxSetContextInternal (ctx
: TGxContext
; ascale
: Single; domatrix
: Boolean);
252 mt
: packed array [0..15] of Double;
254 if (savedGLState
.saved
) then savedGLState
.restore();
256 if (curCtx
<> nil) then
258 curCtx
.onDeactivate();
259 curCtx
.mActive
:= false;
269 oglSetup2D(fuiScrWdt
, fuiScrHgt
);
270 glScalef(ascale
, ascale
, 1.0);
271 ctx
.mScaled
:= (ascale
<> 1.0);
272 ctx
.mScale
:= ascale
;
276 // assume uniform scale
277 glGetDoublev(GL_MODELVIEW_MATRIX
, @mt
[0]);
278 ctx
.mScaled
:= (mt
[0] <> 1.0) or (mt
[1*4+1] <> 1.0);
287 procedure gxSetContext (ctx
: TGxContext
; ascale
: Single=1.0); begin gxSetContextInternal(ctx
, ascale
, true); end;
288 procedure gxSetContextNoMatrix (ctx
: TGxContext
); begin gxSetContextInternal(ctx
, 1, false); end;
291 // ////////////////////////////////////////////////////////////////////////// //
293 TScissorSave
= record
296 scxywh
: packed array[0..3] of GLint
;
301 procedure save (enableScissoring
: Boolean);
302 procedure restore ();
304 // set new scissor rect, bounded by the saved scissor rect
305 procedure combineRect (x
, y
, w
, h
: Integer);
309 procedure TScissorSave
.save (enableScissoring
: Boolean);
311 wassc
:= (glIsEnabled(GL_SCISSOR_TEST
) <> 0);
312 if wassc
then glGetIntegerv(GL_SCISSOR_BOX
, @scxywh
[0]) else glGetIntegerv(GL_VIEWPORT
, @scxywh
[0]);
313 //conwritefln('(%d,%d)-(%d,%d)', [scxywh[0], scxywh[1], scxywh[2], scxywh[3]]);
314 if enableScissoring
and (not wassc
) then glEnable(GL_SCISSOR_TEST
);
317 procedure TScissorSave
.restore ();
319 glScissor(scxywh
[0], scxywh
[1], scxywh
[2], scxywh
[3]);
320 if wassc
then glEnable(GL_SCISSOR_TEST
) else glDisable(GL_SCISSOR_TEST
);
323 procedure TScissorSave
.combineRect (x
, y
, w
, h
: Integer);
324 //var ox, oy, ow, oh: Integer;
326 if (w
< 1) or (h
< 1) then begin glScissor(0, 0, 0, 0); exit
; end;
327 y
:= fuiScrHgt
-(y
+h
);
328 //ox := x; oy := y; ow := w; oh := h;
329 if not intersectRect(x
, y
, w
, h
, scxywh
[0], scxywh
[1], scxywh
[2], scxywh
[3]) then
331 //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, ')');
332 //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, '>');
333 glScissor(0, 0, 0, 0);
337 glScissor(x
, y
, w
, h
);
342 // ////////////////////////////////////////////////////////////////////////// //
343 {$INCLUDE fui_gfx_gl_fonts.inc}
346 TGxBmpFont
= class(TGxFont
)
348 mTexId
: GLuint
; // OpenGL texture id
349 mWidth
: Integer; // <=0: proportional
352 mFreeFontWdt
: Boolean;
355 procedure oglCreateTexture ();
356 procedure oglDestroyTexture ();
358 procedure initDrawText ();
359 procedure doneDrawText ();
360 function drawCharInterim (x
, y
: Integer; const ch
: AnsiChar): Integer; // return width (not including last empty pixel)
361 function drawCharInternal (x
, y
: Integer; const ch
: AnsiChar): Integer; // return width (not including last empty pixel)
362 function drawTextInternal (x
, y
: Integer; const s
: AnsiString): Integer; // return width (not including last empty pixel)
365 constructor Create (const aname
: AnsiString; awdt
, ahgt
: Integer; const afont
: PByte; const awdtable
: PByte=nil);
366 destructor Destroy (); override;
368 function charWidth (const ch
: AnsiChar): Integer; override;
369 function textWidth (const s
: AnsiString): Integer; override;
373 constructor TGxBmpFont
.Create (const aname
: AnsiString; awdt
, ahgt
: Integer; const afont
: PByte; const awdtable
: PByte=nil);
377 if (afont
= nil) then raise Exception
.Create('internal error in font creation');
378 if (ahgt
< 1) then raise Exception
.Create('internal error in font creation');
381 //if (awdtable <> nil) then raise Exception.Create('internal error in font creation');
382 mFreeFontWdt
:= true;
383 // create width table
384 GetMem(mFontWdt
, 256);
385 for c
:= 0 to 255 do mFontWdt
[c
] := awdt
-1;
389 if (awdtable
= nil) then raise Exception
.Create('internal error in font creation');
391 mFontWdt
:= awdtable
;
396 mBaseLine
:= ahgt
-1; //FIXME
402 destructor TGxBmpFont
.Destroy ();
404 if (mFreeFontWdt
) and (mFontWdt
<> nil) then FreeMem(mFontWdt
);
411 mFreeFontWdt
:= false;
417 procedure TGxBmpFont
.oglCreateTexture ();
419 mTexId
:= createFontTexture(mFontBmp
, mFontWdt
, mHeight
, (mWidth
<= 0));
423 procedure TGxBmpFont
.oglDestroyTexture ();
425 if (mTexId
<> 0) then
427 glDeleteTextures(1, @mTexId
);
433 function TGxBmpFont
.charWidth (const ch
: AnsiChar): Integer;
435 result
:= (mFontWdt
[Byte(ch
)] and $0f);
439 function TGxBmpFont
.textWidth (const s
: AnsiString): Integer;
443 if (Length(s
) > 0) then
446 for ch
in s
do result
+= (mFontWdt
[Byte(ch
)] and $0f)+1;
455 procedure TGxBmpFont
.initDrawText ();
457 glEnable(GL_ALPHA_TEST
);
458 glAlphaFunc(GL_NOTEQUAL
, 0.0);
459 glEnable(GL_TEXTURE_2D
);
460 glBindTexture(GL_TEXTURE_2D
, mTexId
);
464 procedure TGxBmpFont
.doneDrawText ();
466 glDisable(GL_ALPHA_TEST
);
467 glDisable(GL_TEXTURE_2D
);
468 glBindTexture(GL_TEXTURE_2D
, 0);
472 function TGxBmpFont
.drawCharInterim (x
, y
: Integer; const ch
: AnsiChar): Integer;
476 tx
:= (Integer(ch
) mod 16)*8;
477 ty
:= (Integer(ch
) div 16)*16;
479 glTexCoord2f((tx
+0)/128.0, (ty
+0)/256.0); glVertex2i(x
+0, y
+0); // top-left
480 glTexCoord2f((tx
+8)/128.0, (ty
+0)/256.0); glVertex2i(x
+8, y
+0); // top-right
481 glTexCoord2f((tx
+8)/128.0, (ty
+mHeight
)/256.0); glVertex2i(x
+8, y
+mHeight
); // bottom-right
482 glTexCoord2f((tx
+0)/128.0, (ty
+mHeight
)/256.0); glVertex2i(x
+0, y
+mHeight
); // bottom-left
484 result
:= (mFontWdt
[Byte(ch
)] and $0f);
488 function TGxBmpFont
.drawCharInternal (x
, y
: Integer; const ch
: AnsiChar): Integer;
491 result
:= drawCharInterim(x
, y
, ch
);
496 function TGxBmpFont
.drawTextInternal (x
, y
: Integer; const s
: AnsiString): Integer;
501 if (Length(s
) = 0) then begin result
:= 0; exit
; end;
506 wdt
:= drawCharInterim(x
, y
, ch
)+1;
514 // ////////////////////////////////////////////////////////////////////////// //
516 fontList
: array of TGxBmpFont
= nil;
517 defaultFontName
: AnsiString = 'dos';
520 function strEquCI (const s0
, s1
: AnsiString): Boolean;
525 result
:= (Length(s0
) = Length(s1
));
528 for f
:= 1 to Length(s0
) do
531 if (c0
>= 'a') and (c0
<= 'z') then Dec(c0
, 32); // poor man's `toupper()`
533 if (c1
>= 'a') and (c1
<= 'z') then Dec(c1
, 32); // poor man's `toupper()`
534 if (c0
<> c1
) then begin result
:= false; exit
; end;
540 function getFontByName (const aname
: AnsiString): TGxBmpFont
;
545 if (Length(fontList
) = 0) then raise Exception
.Create('font subsystem not initialized');
546 if (Length(aname
) = 0) or (strEquCI(aname
, 'default')) then fname
:= defaultFontName
else fname
:= aname
;
547 for f
:= 0 to High(fontList
) do
549 result
:= fontList
[f
];
550 if (result
= nil) then continue
;
551 if (strEquCI(result
.name
, fname
)) then exit
;
553 if (fontList
[0] = nil) then raise Exception
.Create('font subsystem not properly initialized');
554 result
:= fontList
[0];
558 procedure deleteFonts ();
562 for f
:= 0 to High(fontList
) do freeAndNil(fontList
[f
]);
567 procedure createFonts ();
570 SetLength(fontList
, 10);
571 fontList
[0] := TGxBmpFont
.Create('dos', 8, 8, @kgiFont8
[0], @kgiFont8PropWidth
[0]);
572 fontList
[1] := TGxBmpFont
.Create('dos-prop', 0, 8, @kgiFont8
[0], @kgiFont8PropWidth
[0]);
573 fontList
[2] := TGxBmpFont
.Create('msx', 6, 8, @kgiFont6
[0], @kgiFont6PropWidth
[0]);
574 fontList
[3] := TGxBmpFont
.Create('msx-prop', 0, 8, @kgiFont6
[0], @kgiFont6PropWidth
[0]);
575 fontList
[4] := TGxBmpFont
.Create('win8', 8, 8, @kgiWFont8
[0], @kgiWFont8Wdt
[0]);
576 fontList
[5] := TGxBmpFont
.Create('win8-prop', 0, 8, @kgiWFont8
[0], @kgiWFont8Wdt
[0]);
577 fontList
[6] := TGxBmpFont
.Create('win14', 8, 14, @kgiFont14
[0], @kgiFont14Wdt
[0]);
578 fontList
[7] := TGxBmpFont
.Create('win14-prop', 0, 14, @kgiFont14
[0], @kgiFont14Wdt
[0]);
579 fontList
[8] := TGxBmpFont
.Create('win16', 8, 16, @kgiFont16
[0], @kgiFont16Wdt
[0]);
580 fontList
[9] := TGxBmpFont
.Create('win16-prop', 0, 16, @kgiFont16
[0], @kgiFont16Wdt
[0]);
584 procedure oglInitFonts ();
588 for f
:= 0 to High(fontList
) do if (fontList
[f
] <> nil) then fontList
[f
].oglCreateTexture();
592 procedure oglDeinitFonts ();
596 for f
:= 0 to High(fontList
) do if (fontList
[f
] <> nil) then fontList
[f
].oglDestroyTexture();
600 // ////////////////////////////////////////////////////////////////////////// //
601 procedure oglSetup2DState ();
604 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
605 glDisable(GL_LINE_SMOOTH
);
606 glDisable(GL_POLYGON_SMOOTH
);
607 glDisable(GL_POINT_SMOOTH
);
608 glDisable(GL_DEPTH_TEST
);
609 glDisable(GL_TEXTURE_2D
);
610 glDisable(GL_LIGHTING
);
611 glDisable(GL_DITHER
);
612 glDisable(GL_STENCIL_TEST
);
613 glDisable(GL_SCISSOR_TEST
);
614 glDisable(GL_CULL_FACE
);
615 glDisable(GL_ALPHA_TEST
);
617 glClearColor(0, 0, 0, 0);
618 glColor4f(1, 1, 1, 1);
622 procedure oglSetup2D (winWidth
, winHeight
: Integer; upsideDown
: Boolean=false);
624 glViewport(0, 0, winWidth
, winHeight
);
628 glMatrixMode(GL_TEXTURE
);
631 glMatrixMode(GL_COLOR
);
634 glMatrixMode(GL_PROJECTION
);
638 glOrtho(0, winWidth
, 0, winHeight
, -1, 1); // set origin to bottom left
642 glOrtho(0, winWidth
, winHeight
, 0, -1, 1); // set origin to top left
645 glMatrixMode(GL_MODELVIEW
);
650 // ////////////////////////////////////////////////////////////////////////// //
651 {$INCLUDE fui_gfx_gl_cursor.inc}
653 procedure oglDrawCursor (); begin oglDrawCursorAt(fuiMouseX
, fuiMouseY
); end;
656 // ////////////////////////////////////////////////////////////////////////// //
657 constructor TGxContext
.Create ();
660 mColor
:= TGxRGBA
.Create(255, 255, 255);
661 mFont
:= getFontByName('default');
664 mClipRect
:= TGxRect
.Create(0, 0, 8192, 8192);
665 mClipOfs
:= TGxOfs
.Create(0, 0);
669 destructor TGxContext
.Destroy ();
671 if (mActive
) then gxSetContext(nil);
676 function TGxContext
.getFont (): AnsiString;
678 result
:= mFont
.name
;
681 procedure TGxContext
.setFont (const aname
: AnsiString);
683 mFont
:= getFontByName(aname
);
687 procedure TGxContext
.onActivate ();
689 setupGLColor(mColor
);
693 procedure TGxContext
.onDeactivate ();
698 procedure TGxContext
.setColor (const clr
: TGxRGBA
);
701 if (mActive
) then setupGLColor(mColor
);
705 procedure TGxContext
.realizeClip ();
707 sx
, sy
, sw
, sh
: Integer;
709 if (not mActive
) then exit
; // just in case
710 if (mClipRect
.w
<= 0) or (mClipRect
.h
<= 0) then
712 glEnable(GL_SCISSOR_TEST
);
713 glScissor(0, 0, 0, 0);
719 sx
:= trunc(mClipRect
.x
*mScale
);
720 sy
:= trunc(mClipRect
.y
*mScale
);
721 sw
:= trunc(mClipRect
.w
*mScale
);
722 sh
:= trunc(mClipRect
.h
*mScale
);
731 if (not intersectRect(sx
, sy
, sw
, sh
, 0, 0, fuiScrWdt
, fuiScrHgt
)) then
733 glEnable(GL_SCISSOR_TEST
);
734 glScissor(0, 0, 0, 0);
736 else if (sx
= 0) and (sy
= 0) and (sw
= fuiScrWdt
) and (sh
= fuiScrHgt
) then
738 glDisable(GL_SCISSOR_TEST
);
742 glEnable(GL_SCISSOR_TEST
);
743 sy
:= fuiScrHgt
-(sy
+sh
);
744 glScissor(sx
, sy
, sw
, sh
);
750 procedure TGxContext
.resetClip ();
752 mClipRect
:= TGxRect
.Create(0, 0, 8192, 8192);
753 if (mActive
) then realizeClip();
757 procedure TGxContext
.setClipOfs (const aofs
: TGxOfs
);
763 procedure TGxContext
.setClipRect (const aclip
: TGxRect
);
766 if (mActive
) then realizeClip();
770 function TGxContext
.setOffset (constref aofs
: TGxOfs
): TGxOfs
;
777 function TGxContext
.setClip (constref aclip
: TGxRect
): TGxRect
;
781 if (mActive
) then realizeClip();
785 function TGxContext
.combineClip (constref aclip
: TGxRect
): TGxRect
;
788 mClipRect
.intersect(aclip
);
789 if (mActive
) then realizeClip();
793 procedure TGxContext
.line (x1
, y1
, x2
, y2
: Integer);
795 if (not mActive
) or (mClipRect
.w
< 1) or (mClipRect
.h
< 1) or (mColor
.a
= 0) then exit
;
797 if (not mScaled
) then
801 glVertex2f(x1
+0.375, y1
+0.375);
802 glVertex2f(x2
+0.375, y2
+0.375);
805 if (x1
<> x2
) or (y1
<> y2
) then
809 glVertex2f(x2
+0.375, y2
+0.375);
821 glVertex2i(x2
+1, y2
+1);
827 procedure TGxContext
.hline (x
, y
, len
: Integer);
829 if (not mActive
) or (mClipRect
.w
< 1) or (mClipRect
.h
< 1) or (mColor
.a
= 0) then exit
;
830 if (len
< 1) then exit
;
831 if (not mScaled
) then
835 glVertex2f(x
+0.375, y
+0.375);
836 glVertex2f(x
+len
+0.375, y
+0.375);
839 else if (mScale
> 1.0) then
843 glVertex2i(x
+len
, y
);
844 glVertex2i(x
+len
, y
+1);
852 while (len
> 0) do begin glVertex2i(x
, y
); Inc(x
); Dec(len
); end;
858 procedure TGxContext
.vline (x
, y
, len
: Integer);
860 if (not mActive
) or (mClipRect
.w
< 1) or (mClipRect
.h
< 1) or (mColor
.a
= 0) then exit
;
861 if (len
< 1) then exit
;
862 if (not mScaled
) then
866 glVertex2f(x
+0.375, y
+0.375);
867 glVertex2f(x
+0.375, y
+len
+0.375);
870 else if (mScale
> 1.0) then
874 glVertex2i(x
, y
+len
);
875 glVertex2i(x
+1, y
+len
);
883 while (len
> 0) do begin glVertex2i(x
, y
); Inc(y
); Dec(len
); end;
889 procedure TGxContext
.rect (x
, y
, w
, h
: Integer);
891 if (not mActive
) or (mClipRect
.w
< 1) or (mClipRect
.h
< 1) or (mColor
.a
= 0) then exit
;
892 if (w
< 0) or (h
< 0) then exit
;
893 if (w
= 1) and (h
= 1) then
897 if mScaled
then glVertex2i(x
, y
) else glVertex2f(x
+0.375, y
+0.375);
902 if (not mScaled
) then
906 glVertex2i(x
, y
); glVertex2i(x
+w
, y
); // top
907 glVertex2i(x
, y
+h
-1); glVertex2i(x
+w
, y
+h
-1); // bottom
908 glVertex2f(x
+0.375, y
+1); glVertex2f(x
+0.375, y
+h
-1); // left
909 glVertex2f(x
+w
-1+0.375, y
+1); glVertex2f(x
+w
-1+0.375, y
+h
-1); // right
917 vline(x
+w
-1, y
+1, h
-2);
923 procedure TGxContext
.fillRect (x
, y
, w
, h
: Integer);
925 if (not mActive
) or (mClipRect
.w
< 1) or (mClipRect
.h
< 1) or (mColor
.a
= 0) then exit
;
926 if (w
< 0) or (h
< 0) then exit
;
930 glVertex2f(x
+w
, y
+h
);
936 procedure TGxContext
.darkenRect (x
, y
, w
, h
: Integer; a
: Integer);
938 if (not mActive
) or (mClipRect
.w
< 1) or (mClipRect
.h
< 1) or (a
>= 255) then exit
;
939 if (w
< 0) or (h
< 0) then exit
;
940 if (a
< 0) then a
:= 0;
942 glBlendFunc(GL_ZERO
, GL_SRC_ALPHA
);
943 glColor4f(0.0, 0.0, 0.0, a
/255.0);
947 glVertex2i(x
+w
, y
+h
);
950 setupGLColor(mColor
);
954 function TGxContext
.charWidth (const ch
: AnsiChar): Integer;
956 result
:= mFont
.charWidth(ch
);
959 function TGxContext
.charHeight (const ch
: AnsiChar): Integer;
961 result
:= mFont
.height
;
965 function TGxContext
.textWidth (const s
: AnsiString): Integer;
967 result
:= mFont
.textWidth(s
);
970 function TGxContext
.textHeight (const s
: AnsiString): Integer;
972 result
:= mFont
.height
;
976 function TGxContext
.drawChar (x
, y
: Integer; const ch
: AnsiChar): Integer; // returns char width
978 result
:= mFont
.charWidth(ch
);
979 if (not mActive
) or (mClipRect
.w
< 1) or (mClipRect
.h
< 1) or (mColor
.a
= 0) then exit
;
980 TGxBmpFont(mFont
).drawCharInternal(x
, y
, ch
);
983 function TGxContext
.drawText (x
, y
: Integer; const s
: AnsiString): Integer; // returns text width
985 result
:= mFont
.textWidth(s
);
986 if (not mActive
) or (mClipRect
.w
< 1) or (mClipRect
.h
< 1) or (mColor
.a
= 0) or (Length(s
) = 0) then exit
;
987 TGxBmpFont(mFont
).drawTextInternal(x
, y
, s
);
991 function TGxContext
.iconMarkWidth (ic
: TMarkIcon
): Integer;
993 {$IFDEF FUI_TEXT_ICONS}
995 TMarkIcon
.Checkbox
: result
:= textWidth('[x]');
996 TMarkIcon
.Radiobox
: result
:= textWidth('(*)');
997 else result
:= textWidth('[x]');
1004 function TGxContext
.iconMarkHeight (ic
: TMarkIcon
): Integer;
1006 {$IFDEF FUI_TEXT_ICONS}
1008 TMarkIcon
.Checkbox
: result
:= textHeight('[x]');
1009 TMarkIcon
.Radiobox
: result
:= textHeight('(*)');
1010 else result
:= textHeight('[x]');
1017 procedure TGxContext
.drawIconMark (ic
: TMarkIcon
; x
, y
: Integer; marked
: Boolean);
1019 {$IFDEF FUI_TEXT_ICONS}
1025 if (not mActive
) or (mClipRect
.w
< 1) or (mClipRect
.h
< 1) or (mColor
.a
= 0) then exit
;
1026 {$IFDEF FUI_TEXT_ICONS}
1028 TMarkIcon
.Checkbox
: xstr
:= '[x]';
1029 TMarkIcon
.Radiobox
: xstr
:= '(*)';
1034 drawText(x
, y
, xstr
);
1038 drawChar(x
, y
, xstr
[1]);
1039 drawChar(x
+textWidth(xstr
)-charWidth(xstr
[3]), y
, xstr
[3]);
1042 if (ic
= TMarkIcon
.Checkbox
) then
1054 vline(x
+10, y
+1, 5);
1060 if (not marked
) then exit
;
1066 vline(x
+3+f
, y
+1+f
, 1);
1067 vline(x
+7-f
, y
+1+f
, 1);
1083 function TGxContext
.iconWinWidth (ic
: TWinIcon
): Integer;
1085 {$IFDEF FUI_TEXT_ICONS}
1087 TWinIcon
.Close
: result
:= nmax(textWidth('[x]'), textWidth('[#]'));
1088 else result
:= nmax(textWidth('[x]'), textWidth('[#]'));
1095 function TGxContext
.iconWinHeight (ic
: TWinIcon
): Integer;
1097 {$IFDEF FUI_TEXT_ICONS}
1099 TWinIcon
.Close
: result
:= nmax(textHeight('[x]'), textHeight('[#]'));
1100 else result
:= nmax(textHeight('[x]'), textHeight('[#]'));
1107 procedure TGxContext
.drawIconWin (ic
: TWinIcon
; x
, y
: Integer; pressed
: Boolean);
1109 {$IFDEF FUI_TEXT_ICONS}
1116 if (not mActive
) or (mClipRect
.w
< 1) or (mClipRect
.h
< 1) or (mColor
.a
= 0) then exit
;
1117 {$IFDEF FUI_TEXT_ICONS}
1119 TWinIcon
.Close
: if (pressed
) then xstr
:= '[#]' else xstr
:= '[x]';
1122 wdt
:= nmax(textWidth('[x]'), textWidth('[#]'));
1123 drawChar(x
, y
, xstr
[1]);
1124 drawChar(x
+wdt
-charWidth(xstr
[3]), y
, xstr
[3]);
1125 drawChar(x
+((wdt
-charWidth(xstr
[2])) div 2), y
, xstr
[2]);
1127 if pressed
then rect(x
, y
, 9, 8);
1130 vline(x
+1+f
, y
+f
, 1);
1131 vline(x
+1+6-f
, y
+f
, 1);
1137 procedure TGxContext
.glSetScale (ascale
: Single);
1139 if (ascale
< 0.01) then ascale
:= 0.01;
1141 glScalef(ascale
, ascale
, 1.0);
1143 mScaled
:= (ascale
<> 1.0);
1146 procedure TGxContext
.glSetTrans (ax
, ay
: Single);
1149 glScalef(mScale
, mScale
, 1.0);
1150 glTranslatef(ax
, ay
, 0);
1154 procedure TGxContext
.glSetScaleTrans (ascale
, ax
, ay
: Single);
1157 glTranslatef(ax
, ay
, 0);
1161 // ////////////////////////////////////////////////////////////////////////// //
1163 procedure oglRestoreMode (doClear: Boolean);
1165 oglSetup2D(fuiScrWdt, fuiScrHgt);
1166 glScissor(0, 0, fuiScrWdt, fuiScrHgt);
1168 glBindTexture(GL_TEXTURE_2D, 0);
1169 glDisable(GL_BLEND);
1170 glDisable(GL_TEXTURE_2D);
1171 glDisable(GL_STENCIL_TEST);
1172 glDisable(GL_SCISSOR_TEST);
1173 glDisable(GL_LIGHTING);
1174 glDisable(GL_DEPTH_TEST);
1175 glDisable(GL_CULL_FACE);
1176 glDisable(GL_LINE_SMOOTH);
1177 glDisable(GL_POINT_SMOOTH);
1180 glColor4f(1, 1, 1, 1);
1184 glClearColor(0, 0, 0, 0);
1185 glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT or GL_ACCUM_BUFFER_BIT or GL_STENCIL_BUFFER_BIT);
1189 glMatrixMode(GL_MODELVIEW);
1191 //glScalef(4, 4, 1);
1196 //procedure onWinFocus (); begin end;
1197 //procedure onWinBlur (); begin fuiResetKMState(true); end;
1199 //procedure onPreRender (); begin oglRestoreMode(gGfxDoClear); end;
1200 procedure onPostRender (); begin oglDrawCursor(); end;
1202 procedure onInit ();
1204 //oglSetup2D(fuiScrWdt, fuiScrHgt);
1205 createCursorTexture();
1209 procedure onDeinit ();
1211 fuiResetKMState(false);
1212 if (curtexid
<> 0) then glDeleteTextures(1, @curtexid
);
1222 // ////////////////////////////////////////////////////////////////////////// //
1224 savedGLState
:= TSavedGLState
.Create(false);
1226 //winFocusCB := onWinFocus;
1227 //winBlurCB := onWinBlur;
1228 //prerenderFrameCB := onPreRender;
1229 postrenderFrameCB
:= onPostRender
;
1230 oglInitCB
:= onInit
;
1231 oglDeinitCB
:= onDeinit
;