DEADSOFTWARE

b4ab11bf421334107877508b550960915504f160
[d2df-sdl.git] / src / game / renders / opengl / r_fui_gfx_gl.pas
1 (* coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
2 * Understanding is not required. Only obedience.
3 *
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, version 3 of the License ONLY.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *)
16 {$INCLUDE ../shared/a_modes.inc}
17 {$DEFINE FUI_TEXT_ICONS}
18 unit r_fui_gfx_gl;
20 {$IFDEF USE_GLES1}
21 {$FATAL Desktop OpenGL required for current flexui implementation}
22 {$ENDIF}
24 interface
26 uses
27 SysUtils, Classes,
28 fui_gfx,
29 fui_common, fui_events;
32 // ////////////////////////////////////////////////////////////////////////// //
33 type
34 TGxFont = class
35 protected
36 mName: AnsiString;
37 mHeight: Integer;
38 mBaseLine: Integer;
40 public
41 function charWidth (const ch: AnsiChar): Integer; virtual; abstract;
42 function textWidth (const s: AnsiString): Integer; virtual; abstract;
44 public
45 property name: AnsiString read mName;
46 property height: Integer read mHeight;
47 property baseLine: Integer read mBaseLine;
48 end;
50 TGxContext = class (fui_gfx.TGxContext)
51 protected
52 mColor: TGxRGBA;
53 mFont: TGxFont;
54 // for active contexts
55 mScaled: Boolean;
56 mScale: Single;
57 mClipRect: TGxRect;
58 mClipOfs: TGxOfs;
60 protected
61 procedure realizeClip (); // setup scissoring
62 procedure setClipOfs (const aofs: TGxOfs); // !!!
64 public
65 function setOffset (constref aofs: TGxOfs): TGxOfs; // returns previous offset
66 function setClip (constref aclip: TGxRect): TGxRect; // returns previous clip
68 protected
69 function getFont (): AnsiString; override;
70 procedure setFont (const aname: AnsiString); override;
72 procedure onActivate (); override;
73 procedure onDeactivate (); override;
75 function getColor (): TGxRGBA; override;
76 procedure setColor (const clr: TGxRGBA); override;
78 function getClipRect (): TGxRect; override;
79 procedure setClipRect (const aclip: TGxRect); override;
81 public
82 constructor Create ();
83 destructor Destroy (); override;
85 procedure line (x1, y1, x2, y2: Integer); override;
86 procedure hline (x, y, len: Integer); override;
87 procedure vline (x, y, len: Integer); override;
88 procedure rect (x, y, w, h: Integer); override;
89 procedure fillRect (x, y, w, h: Integer); override;
90 procedure darkenRect (x, y, w, h: Integer; a: Integer); override;
92 function charWidth (const ch: AnsiChar): Integer; override;
93 function charHeight (const ch: AnsiChar): Integer; override;
94 function textWidth (const s: AnsiString): Integer; override;
95 function textHeight (const s: AnsiString): Integer; override;
96 function drawChar (x, y: Integer; const ch: AnsiChar): Integer; override; // returns char width
97 function drawText (x, y: Integer; const s: AnsiString): Integer; override; // returns text width
99 function iconMarkWidth (ic: TMarkIcon): Integer; override;
100 function iconMarkHeight (ic: TMarkIcon): Integer; override;
101 procedure drawIconMark (ic: TMarkIcon; x, y: Integer; marked: Boolean); override;
103 function iconWinWidth (ic: TWinIcon): Integer; override;
104 function iconWinHeight (ic: TWinIcon): Integer; override;
105 procedure drawIconWin (ic: TWinIcon; x, y: Integer; pressed: Boolean); override;
107 procedure resetClip (); override;
109 function combineClip (constref aclip: TGxRect): TGxRect; override; // returns previous clip
111 // vertical scrollbar
112 procedure drawVSBar (x, y, wdt, hgt: Integer; cur, min, max: Integer; constref clrfull, clrempty: TGxRGBA); override;
113 // horizontal scrollbar
114 procedure drawHSBar (x, y, wdt, hgt: Integer; cur, min, max: Integer; constref clrfull, clrempty: TGxRGBA); override;
116 public //HACK!
117 procedure glSetScale (ascale: Single);
118 procedure glSetTrans (ax, ay: Single);
119 procedure glSetScaleTrans (ascale, ax, ay: Single);
121 public
122 property color: TGxRGBA read mColor write setColor;
123 property offset: TGxOfs read mClipOfs write setClipOfs;
124 property clip: TGxRect read mClipRect write setClipRect; // clipping is unaffected by offset
125 end;
128 // setup 2D OpenGL mode; will be called automatically in `glInit()`
129 //procedure oglSetup2D (winWidth, winHeight: Integer; upsideDown: Boolean=false);
130 //procedure oglSetup2DState (); // don't modify viewports and matrices
132 //procedure oglDrawCursor ();
133 //procedure oglDrawCursorAt (msX, msY: Integer);
136 //procedure fuiGfxLoadFont (const fontname: AnsiString; const fontFile: AnsiString; proportional: Boolean=false);
137 //procedure fuiGfxLoadFont (const fontname: AnsiString; st: TStream; proportional: Boolean=false);
140 // ////////////////////////////////////////////////////////////////////////// //
141 var
142 gGfxDoClear: Boolean = true;
145 implementation
147 uses
148 {$INCLUDE ../nogl/noGLuses.inc}
149 sdlcarcass,
150 fui_wadread,
151 utils;
154 // ////////////////////////////////////////////////////////////////////////// //
155 // returns `false` if the color is transparent
156 // returns `false` if the color is transparent
157 function setupGLColor (constref clr: TGxRGBA): Boolean;
158 begin
159 if (clr.a < 255) then
160 begin
161 glEnable(GL_BLEND);
162 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
163 end
164 else
165 begin
166 glDisable(GL_BLEND);
167 end;
168 glColor4ub(clr.r, clr.g, clr.b, clr.a);
169 result := (clr.a <> 0);
170 end;
172 function isScaled (): Boolean;
173 var
174 mt: packed array [0..15] of GLfloat;
175 begin
176 glGetFloatv(GL_MODELVIEW_MATRIX, @mt[0]);
177 result := (mt[0] <> 1.0) or (mt[1*4+1] <> 1.0);
178 end;
181 // ////////////////////////////////////////////////////////////////////////// //
182 //TODO: OpenGL framebuffers and shaders state
183 type
184 TSavedGLState = record
185 public
186 glmatmode: GLint;
187 gltextbinding: GLint;
188 //oldprg: GLint;
189 //oldfbr, oldfbw: GLint;
190 glvport: packed array [0..3] of GLint;
191 saved: Boolean;
193 public
194 constructor Create (dosave: Boolean);
195 procedure save ();
196 procedure restore ();
197 end;
199 constructor TSavedGLState.Create (dosave: Boolean);
200 begin
201 FillChar(self, sizeof(self), 0);
202 if (dosave) then save();
203 end;
205 procedure TSavedGLState.save ();
206 begin
207 if (saved) then raise Exception.Create('cannot save into already saved OpenGL state');
208 glGetIntegerv(GL_MATRIX_MODE, @glmatmode);
209 glGetIntegerv(GL_TEXTURE_BINDING_2D, @gltextbinding);
210 glGetIntegerv(GL_VIEWPORT, @glvport[0]);
211 //glGetIntegerv(GL_CURRENT_PROGRAM, &oldprg);
212 //glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &oldfbr);
213 //glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldfbw);
214 glMatrixMode(GL_PROJECTION); glPushMatrix();
215 glMatrixMode(GL_MODELVIEW); glPushMatrix();
216 glMatrixMode(GL_TEXTURE); glPushMatrix();
217 glMatrixMode(GL_COLOR); glPushMatrix();
218 glPushAttrib({GL_ENABLE_BIT|GL_COLOR_BUFFER_BIT|GL_CURRENT_BIT}GL_ALL_ATTRIB_BITS); // let's play safe
219 saved := true;
220 end;
222 procedure TSavedGLState.restore ();
223 begin
224 if (not saved) then raise Exception.Create('cannot restore unsaved OpenGL state');
225 glPopAttrib({GL_ENABLE_BIT});
226 glMatrixMode(GL_PROJECTION); glPopMatrix();
227 glMatrixMode(GL_MODELVIEW); glPopMatrix();
228 glMatrixMode(GL_TEXTURE); glPopMatrix();
229 glMatrixMode(GL_COLOR); glPopMatrix();
230 glMatrixMode(glmatmode);
231 //if (glHasFunc!"glBindFramebufferEXT") glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, oldfbr);
232 //if (glHasFunc!"glBindFramebufferEXT") glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, oldfbw);
233 glBindTexture(GL_TEXTURE_2D, gltextbinding);
234 //if (glHasFunc!"glUseProgram") glUseProgram(oldprg);
235 glViewport(glvport[0], glvport[1], glvport[2], glvport[3]);
236 saved := false;
237 end;
240 var
241 savedGLState: TSavedGLState;
243 procedure gxGLPreSetContextCallback;
244 begin
245 if (savedGLState.saved) then savedGLState.restore();
246 end;
248 function gxGLCreateContextCallback (): fui_gfx.TGxContext;
249 begin
250 result := TGxContext.Create();
251 end;
253 // ////////////////////////////////////////////////////////////////////////// //
254 type
255 TScissorSave = record
256 public
257 wassc: Boolean;
258 scxywh: packed array[0..3] of GLint;
260 public
262 public
263 procedure save (enableScissoring: Boolean);
264 procedure restore ();
266 // set new scissor rect, bounded by the saved scissor rect
267 procedure combineRect (x, y, w, h: Integer);
268 end;
271 procedure TScissorSave.save (enableScissoring: Boolean);
272 begin
273 wassc := (glIsEnabled(GL_SCISSOR_TEST) <> 0);
274 if wassc then glGetIntegerv(GL_SCISSOR_BOX, @scxywh[0]) else glGetIntegerv(GL_VIEWPORT, @scxywh[0]);
275 //conwritefln('(%d,%d)-(%d,%d)', [scxywh[0], scxywh[1], scxywh[2], scxywh[3]]);
276 if enableScissoring and (not wassc) then glEnable(GL_SCISSOR_TEST);
277 end;
279 procedure TScissorSave.restore ();
280 begin
281 glScissor(scxywh[0], scxywh[1], scxywh[2], scxywh[3]);
282 if wassc then glEnable(GL_SCISSOR_TEST) else glDisable(GL_SCISSOR_TEST);
283 end;
285 procedure TScissorSave.combineRect (x, y, w, h: Integer);
286 //var ox, oy, ow, oh: Integer;
287 begin
288 if (w < 1) or (h < 1) then begin glScissor(0, 0, 0, 0); exit; end;
289 y := fuiScrHgt-(y+h);
290 //ox := x; oy := y; ow := w; oh := h;
291 if not intersectRect(x, y, w, h, scxywh[0], scxywh[1], scxywh[2], scxywh[3]) then
292 begin
293 //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, ')');
294 //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, '>');
295 glScissor(0, 0, 0, 0);
296 end
297 else
298 begin
299 glScissor(x, y, w, h);
300 end;
301 end;
304 // ////////////////////////////////////////////////////////////////////////// //
305 type
306 TGxBmpFont = class(TGxFont)
307 private
308 mTexId: GLuint; // OpenGL texture id
309 mWidth: Integer; // <=0: proportional
310 mFontBmp: PByte;
311 mFontWdt: PByte;
312 mFreeFontWdt: Boolean;
313 mFreeFontBmp: Boolean;
315 protected
316 procedure oglCreateTexture ();
317 procedure oglDestroyTexture ();
319 procedure initDrawText ();
320 procedure doneDrawText ();
321 function drawCharInterim (x, y: Integer; const ch: AnsiChar): Integer; // return width (not including last empty pixel)
322 function drawCharInternal (x, y: Integer; const ch: AnsiChar): Integer; // return width (not including last empty pixel)
323 function drawTextInternal (x, y: Integer; const s: AnsiString): Integer; // return width (not including last empty pixel)
325 public
326 constructor Create (const aname: AnsiString; st: TStream; proportional: Boolean);
327 destructor Destroy (); override;
329 function charWidth (const ch: AnsiChar): Integer; override;
330 function textWidth (const s: AnsiString): Integer; override;
331 end;
334 constructor TGxBmpFont.Create (const aname: AnsiString; st: TStream; proportional: Boolean);
335 var
336 sign: packed array [0..7] of AnsiChar;
337 enc: packed array [0..16] of AnsiChar;
338 b: Byte;
339 wdt, hgt, elen: Integer;
340 ch, dy: Integer;
341 fntbwdt: Integer;
342 wrd: Word;
343 begin
344 mFreeFontBmp := true;
345 mFreeFontWdt := true;
346 mName := aname;
347 mTexId := 0;
348 // signature
349 st.ReadBuffer(sign[0], 8);
350 if (sign <> 'FUIFONT0') then raise Exception.Create('FlexUI: invalid font file signature');
351 // encoding length and width
352 st.ReadBuffer(b, 1);
353 wdt := (b and $0f)+1; // 16 is not supported
354 if (wdt = 16) then raise Exception.Create('FlexUI: 16-wdt fonts aren''t supported yet');
355 elen := ((b shr 4) and $0f);
356 if (elen = 0) then raise Exception.CreateFmt('FlexUI: invalid font encoding length: %d', [elen]);
357 // height
358 st.ReadBuffer(b, 1);
359 hgt := b;
360 if (hgt < 2) then raise Exception.CreateFmt('FlexUI: invalid font height: %d', [hgt]);
361 // encoding
362 st.ReadBuffer(enc[0], elen);
363 // check for 'cp1251' here (it can also be 'koi8')
364 if (wdt <= 8) then fntbwdt := 1 else fntbwdt := 2;
365 // shift and width table (hi nibble: left shift for proportional print; lo nibble: shifted character width for proportional print)
366 GetMem(mFontWdt, 256);
367 st.ReadBuffer(mFontWdt^, 256);
368 // font bitmap
369 GetMem(mFontBmp, (hgt*fntbwdt)*256);
370 st.ReadBuffer(mFontBmp^, (hgt*fntbwdt)*256);
371 mWidth := wdt;
372 mHeight := hgt;
373 mBaseLine := hgt-1; //FIXME
374 if (proportional) then
375 begin
376 // shift font
377 for ch := 0 to 255 do
378 begin
379 for dy := 0 to hgt-1 do
380 begin
381 if (fntbwdt = 1) then
382 begin
383 mFontBmp[ch*hgt+dy] := mFontBmp[ch*hgt+dy] shl (mFontWdt[ch] shr 4);
384 end
385 else
386 begin
387 wrd := mFontBmp[ch*(hgt*2)+(dy*2)]+256*mFontBmp[ch*(hgt*2)+(dy*2)+1];
388 wrd := wrd shl (mFontWdt[ch] shr 4);
389 mFontBmp[ch*(hgt*2)+(dy*2)+0] := (wrd and $ff);
390 mFontBmp[ch*(hgt*2)+(dy*2)+1] := ((wrd shr 16) and $ff);
391 end;
392 end;
393 end;
394 end
395 else
396 begin
397 FillChar(mFontWdt^, 256, wdt);
398 end;
399 end;
402 destructor TGxBmpFont.Destroy ();
403 begin
404 if (mFreeFontBmp) and (mFontBmp <> nil) then FreeMem(mFontBmp);
405 if (mFreeFontWdt) and (mFontWdt <> nil) then FreeMem(mFontWdt);
406 mName := '';
407 mWidth := 0;
408 mHeight := 0;
409 mBaseLine := 0;
410 mFontBmp := nil;
411 mFontWdt := nil;
412 mFreeFontWdt := false;
413 mFreeFontBmp := false;
414 mTexId := 0;
415 inherited;
416 end;
419 procedure TGxBmpFont.oglCreateTexture ();
420 const
421 TxWidth = 16*16;
422 TxHeight = 16*16;
423 var
424 tex, tpp: PByte;
425 b: Byte;
426 cc: Integer;
427 x, y, dx, dy: Integer;
428 begin
429 GetMem(tex, TxWidth*TxHeight*4);
430 FillChar(tex^, TxWidth*TxHeight*4, 0);
432 for cc := 0 to 255 do
433 begin
434 x := (cc mod 16)*16;
435 y := (cc div 16)*16;
436 for dy := 0 to mHeight-1 do
437 begin
438 if (mWidth <= 8) then b := mFontBmp[cc*mHeight+dy] else b := mFontBmp[cc*(mHeight*2)+(dy*2)+1];
439 //if prop then b := b shl (fontwdt[cc] shr 4);
440 tpp := tex+((y+dy)*(TxWidth*4))+x*4;
441 for dx := 0 to 7 do
442 begin
443 if ((b and $80) <> 0) then
444 begin
445 tpp^ := 255; Inc(tpp);
446 tpp^ := 255; Inc(tpp);
447 tpp^ := 255; Inc(tpp);
448 tpp^ := 255; Inc(tpp);
449 end
450 else
451 begin
452 tpp^ := 0; Inc(tpp);
453 tpp^ := 0; Inc(tpp);
454 tpp^ := 0; Inc(tpp);
455 tpp^ := 0; Inc(tpp);
456 end;
457 b := (b and $7f) shl 1;
458 end;
459 if (mWidth > 8) then
460 begin
461 b := mFontBmp[cc*(mHeight*2)+(dy*2)+0];
462 for dx := 0 to 7 do
463 begin
464 if ((b and $80) <> 0) then
465 begin
466 tpp^ := 255; Inc(tpp);
467 tpp^ := 255; Inc(tpp);
468 tpp^ := 255; Inc(tpp);
469 tpp^ := 255; Inc(tpp);
470 end
471 else
472 begin
473 tpp^ := 0; Inc(tpp);
474 tpp^ := 0; Inc(tpp);
475 tpp^ := 0; Inc(tpp);
476 tpp^ := 0; Inc(tpp);
477 end;
478 b := (b and $7f) shl 1;
479 end;
480 end;
481 end;
482 end;
484 glGenTextures(1, @mTexId);
485 if (mTexId = 0) then raise Exception.Create('can''t create FlexUI font texture');
487 glBindTexture(GL_TEXTURE_2D, mTexId);
488 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
489 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
490 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
491 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
493 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TxWidth, TxHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex);
494 glFinish();
496 glBindTexture(GL_TEXTURE_2D, 0);
497 FreeMem(tex);
498 end;
501 procedure TGxBmpFont.oglDestroyTexture ();
502 begin
503 if (mTexId <> 0) then
504 begin
505 glDeleteTextures(1, @mTexId);
506 mTexId := 0;
507 end;
508 end;
511 function TGxBmpFont.charWidth (const ch: AnsiChar): Integer;
512 begin
513 result := (mFontWdt[Byte(ch)] and $0f);
514 end;
517 function TGxBmpFont.textWidth (const s: AnsiString): Integer;
518 var
519 ch: AnsiChar;
520 begin
521 if (Length(s) > 0) then
522 begin
523 result := -1;
524 for ch in s do result += (mFontWdt[Byte(ch)] and $0f)+1;
525 end
526 else
527 begin
528 result := 0;
529 end;
530 end;
533 procedure TGxBmpFont.initDrawText ();
534 begin
535 glEnable(GL_ALPHA_TEST);
536 glAlphaFunc(GL_NOTEQUAL, 0.0);
537 glEnable(GL_TEXTURE_2D);
538 glBindTexture(GL_TEXTURE_2D, mTexId);
539 end;
542 procedure TGxBmpFont.doneDrawText ();
543 begin
544 glDisable(GL_ALPHA_TEST);
545 glDisable(GL_TEXTURE_2D);
546 glBindTexture(GL_TEXTURE_2D, 0);
547 end;
550 function TGxBmpFont.drawCharInterim (x, y: Integer; const ch: AnsiChar): Integer;
551 var
552 tx, ty: Integer;
553 begin
554 tx := (Integer(ch) mod 16)*16;
555 ty := (Integer(ch) div 16)*16;
556 glBegin(GL_QUADS);
557 glTexCoord2f((tx+0)/256.0, (ty+0)/256.0); glVertex2i(x+0, y+0); // top-left
558 glTexCoord2f((tx+mWidth)/256.0, (ty+0)/256.0); glVertex2i(x+mWidth, y+0); // top-right
559 glTexCoord2f((tx+mWidth)/256.0, (ty+mHeight)/256.0); glVertex2i(x+mWidth, y+mHeight); // bottom-right
560 glTexCoord2f((tx+0)/256.0, (ty+mHeight)/256.0); glVertex2i(x+0, y+mHeight); // bottom-left
561 glEnd();
562 result := (mFontWdt[Byte(ch)] and $0f);
563 end;
566 function TGxBmpFont.drawCharInternal (x, y: Integer; const ch: AnsiChar): Integer;
567 begin
568 initDrawText();
569 result := drawCharInterim(x, y, ch);
570 doneDrawText();
571 end;
574 function TGxBmpFont.drawTextInternal (x, y: Integer; const s: AnsiString): Integer;
575 var
576 ch: AnsiChar;
577 wdt: Integer;
578 begin
579 if (Length(s) = 0) then begin result := 0; exit; end;
580 result := -1;
581 initDrawText();
582 for ch in s do
583 begin
584 wdt := drawCharInterim(x, y, ch)+1;
585 x += wdt;
586 result += wdt;
587 end;
588 doneDrawText();
589 end;
592 // ////////////////////////////////////////////////////////////////////////// //
593 var
594 fontList: array of TGxBmpFont = nil;
595 defaultFontName: AnsiString = 'win14';
598 function strEquCI (const s0, s1: AnsiString): Boolean;
599 var
600 f: Integer;
601 c0, c1: AnsiChar;
602 begin
603 result := (Length(s0) = Length(s1));
604 if (result) then
605 begin
606 for f := 1 to Length(s0) do
607 begin
608 c0 := s0[f];
609 if (c0 >= 'a') and (c0 <= 'z') then Dec(c0, 32); // poor man's `toupper()`
610 c1 := s1[f];
611 if (c1 >= 'a') and (c1 <= 'z') then Dec(c1, 32); // poor man's `toupper()`
612 if (c0 <> c1) then begin result := false; exit; end;
613 end;
614 end;
615 end;
618 function getFontByName (const aname: AnsiString): TGxBmpFont;
619 var
620 f: Integer;
621 fname: AnsiString;
622 begin
623 if (Length(fontList) = 0) then raise Exception.Create('font subsystem not initialized');
624 if (Length(aname) = 0) or (strEquCI(aname, 'default')) then fname := defaultFontName else fname := aname;
625 for f := 0 to High(fontList) do
626 begin
627 result := fontList[f];
628 if (result = nil) then continue;
629 if (strEquCI(result.name, fname)) then exit;
630 end;
631 if (fontList[0] = nil) then raise Exception.Create('font subsystem not properly initialized');
632 result := fontList[0];
633 end;
637 procedure deleteFonts ();
638 var
639 f: Integer;
640 begin
641 for f := 0 to High(fontList) do freeAndNil(fontList[f]);
642 fontList := nil;
643 end;
647 procedure fuiGfxLoadFont (const fontname: AnsiString; st: TStream; proportional: Boolean=false);
648 var
649 fnt: TGxBmpFont = nil;
650 f: Integer;
651 begin
652 if (Length(fontname) = 0) then raise Exception.Create('FlexUI: cannot load nameless font');
653 fnt := TGxBmpFont.Create(fontname, st, proportional);
654 try
655 for f := 0 to High(fontList) do
656 begin
657 if (strEquCI(fontList[f].name, fontname)) then
658 begin
659 if (fontList[f].mTexId <> 0) then raise Exception.Create('FlexUI: cannot reload generated font named '''+fontname+'''');
660 FreeAndNil(fontList[f]);
661 fontList[f] := fnt;
662 exit;
663 end;
664 end;
665 SetLength(fontList, Length(fontList)+1);
666 fontList[High(fontList)] := fnt;
667 except
668 FreeAndNil(fnt);
669 raise;
670 end;
671 end;
674 procedure fuiGfxLoadFont (const fontname: AnsiString; const fontFile: AnsiString; proportional: Boolean=false);
675 var
676 st: TStream;
677 begin
678 if (Length(fontname) = 0) then raise Exception.Create('FlexUI: cannot load nameless font '''+fontFile+'''');
679 st := fuiOpenFile(fontFile);
680 if (st = nil) then raise Exception.Create('FlexUI: cannot load font '''+fontFile+'''');
681 try
682 fuiGfxLoadFont(fontname, st, proportional);
683 except on e: Exception do
684 begin
685 writeln('FlexUI font loadin error: ', e.message);
686 FreeAndNil(st);
687 raise Exception.Create('FlexUI: cannot load font '''+fontFile+'''');
688 end;
689 else
690 raise;
691 end;
692 FreeAndNil(st);
693 end;
696 procedure oglInitFonts ();
697 var
698 f: Integer;
699 begin
700 for f := 0 to High(fontList) do if (fontList[f] <> nil) then fontList[f].oglCreateTexture();
701 end;
704 procedure oglDeinitFonts ();
705 var
706 f: Integer;
707 begin
708 for f := 0 to High(fontList) do if (fontList[f] <> nil) then fontList[f].oglDestroyTexture();
709 end;
712 // ////////////////////////////////////////////////////////////////////////// //
713 procedure oglSetup2DState ();
714 begin
715 glDisable(GL_BLEND);
716 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
717 glDisable(GL_LINE_SMOOTH);
718 glDisable(GL_POLYGON_SMOOTH);
719 glDisable(GL_POINT_SMOOTH);
720 glDisable(GL_DEPTH_TEST);
721 glDisable(GL_TEXTURE_2D);
722 glDisable(GL_LIGHTING);
723 glDisable(GL_DITHER);
724 glDisable(GL_STENCIL_TEST);
725 glDisable(GL_SCISSOR_TEST);
726 glDisable(GL_CULL_FACE);
727 glDisable(GL_ALPHA_TEST);
729 glClearColor(0, 0, 0, 0);
730 glColor4f(1, 1, 1, 1);
731 end;
734 procedure oglSetup2D (winWidth, winHeight: Integer; upsideDown: Boolean=false);
735 begin
736 glViewport(0, 0, winWidth, winHeight);
738 oglSetup2DState();
740 glMatrixMode(GL_TEXTURE);
741 glLoadIdentity();
743 glMatrixMode(GL_COLOR);
744 glLoadIdentity();
746 glMatrixMode(GL_PROJECTION);
747 glLoadIdentity();
748 if (upsideDown) then
749 begin
750 glOrtho(0, winWidth, 0, winHeight, -1, 1); // set origin to bottom left
751 end
752 else
753 begin
754 glOrtho(0, winWidth, winHeight, 0, -1, 1); // set origin to top left
755 end;
757 glMatrixMode(GL_MODELVIEW);
758 glLoadIdentity();
759 end;
762 // ////////////////////////////////////////////////////////////////////////// //
763 {$INCLUDE r_fui_gfx_gl_cursor.inc}
765 procedure oglDrawCursor (); begin oglDrawCursorAt(fuiMouseX, fuiMouseY); end;
768 // ////////////////////////////////////////////////////////////////////////// //
769 constructor TGxContext.Create ();
770 begin
771 inherited;
772 mColor := TGxRGBA.Create(255, 255, 255);
773 mFont := getFontByName('default');
774 mScaled := false;
775 mScale := 1.0;
776 mClipRect := TGxRect.Create(0, 0, 8192, 8192);
777 mClipOfs := TGxOfs.Create(0, 0);
778 end;
781 destructor TGxContext.Destroy ();
782 begin
783 if self.active then gxSetContext(nil);
784 inherited;
785 end;
788 function TGxContext.getFont (): AnsiString;
789 begin
790 result := mFont.name;
791 end;
793 procedure TGxContext.setFont (const aname: AnsiString);
794 begin
795 mFont := getFontByName(aname);
796 end;
799 procedure TGxContext.onActivate ();
800 //ascale: Single; domatrix: Boolean;
801 var
802 mt: packed array [0..15] of GLfloat;
803 begin
804 savedGLState.save();
805 // if (domatrix) then
806 // begin
807 // oglSetup2D(fuiScrWdt, fuiScrHgt);
808 // glScalef(ascale, ascale, 1.0);
809 // self.mScaled := (ascale <> 1.0);
810 // self.mScale := ascale;
811 // end
812 // else
813 begin
814 // assume uniform scale
815 glGetFloatv(GL_MODELVIEW_MATRIX, @mt[0]);
816 self.mScaled := (mt[0] <> 1.0) or (mt[1*4+1] <> 1.0);
817 self.mScale := mt[0];
818 oglSetup2DState();
819 end;
820 setupGLColor(mColor);
821 realizeClip();
822 end;
824 procedure TGxContext.onDeactivate ();
825 begin
826 end;
829 function TGxContext.getColor (): TGxRGBA;
830 begin
831 result := mColor;
832 end;
834 procedure TGxContext.setColor (const clr: TGxRGBA);
835 begin
836 mColor := clr;
837 if self.active then setupGLColor(mColor);
838 end;
841 procedure TGxContext.realizeClip ();
842 var
843 sx, sy, sw, sh: Integer;
844 begin
845 if not self.active then exit; // just in case
846 if (mClipRect.w <= 0) or (mClipRect.h <= 0) then
847 begin
848 glEnable(GL_SCISSOR_TEST);
849 glScissor(0, 0, 0, 0);
850 end
851 else
852 begin
853 if (mScaled) then
854 begin
855 sx := trunc(mClipRect.x*mScale);
856 sy := trunc(mClipRect.y*mScale);
857 sw := trunc(mClipRect.w*mScale);
858 sh := trunc(mClipRect.h*mScale);
859 end
860 else
861 begin
862 sx := mClipRect.x;
863 sy := mClipRect.y;
864 sw := mClipRect.w;
865 sh := mClipRect.h;
866 end;
867 if (not intersectRect(sx, sy, sw, sh, 0, 0, fuiScrWdt, fuiScrHgt)) then
868 begin
869 glEnable(GL_SCISSOR_TEST);
870 glScissor(0, 0, 0, 0);
871 end
872 else if (sx = 0) and (sy = 0) and (sw = fuiScrWdt) and (sh = fuiScrHgt) then
873 begin
874 glDisable(GL_SCISSOR_TEST);
875 end
876 else
877 begin
878 glEnable(GL_SCISSOR_TEST);
879 sy := fuiScrHgt-(sy+sh);
880 glScissor(sx, sy, sw, sh);
881 end;
882 end;
883 end;
886 procedure TGxContext.resetClip ();
887 begin
888 mClipRect := TGxRect.Create(0, 0, 8192, 8192);
889 if self.active then realizeClip();
890 end;
893 procedure TGxContext.setClipOfs (const aofs: TGxOfs);
894 begin
895 mClipOfs := aofs;
896 end;
899 function TGxContext.getClipRect (): TGxRect;
900 begin
901 result := mClipRect;
902 end;
904 procedure TGxContext.setClipRect (const aclip: TGxRect);
905 begin
906 mClipRect := aclip;
907 if self.active then realizeClip();
908 end;
911 function TGxContext.setOffset (constref aofs: TGxOfs): TGxOfs;
912 begin
913 result := mClipOfs;
914 mClipOfs := aofs;
915 end;
918 function TGxContext.setClip (constref aclip: TGxRect): TGxRect;
919 begin
920 result := mClipRect;
921 mClipRect := aclip;
922 if self.active then realizeClip();
923 end;
926 function TGxContext.combineClip (constref aclip: TGxRect): TGxRect;
927 begin
928 result := mClipRect;
929 mClipRect.intersect(aclip);
930 if self.active then realizeClip();
931 end;
934 procedure TGxContext.line (x1, y1, x2, y2: Integer);
935 begin
936 if (not self.active) or (mClipRect.w < 1) or (mClipRect.h < 1) or (mColor.a = 0) then exit;
938 if (not mScaled) then
939 begin
940 glLineWidth(1);
941 glBegin(GL_LINES);
942 glVertex2f(x1+0.375, y1+0.375);
943 glVertex2f(x2+0.375, y2+0.375);
944 glEnd();
946 if (x1 <> x2) or (y1 <> y2) then
947 begin
948 glPointSize(1);
949 glBegin(GL_POINTS);
950 glVertex2f(x2+0.375, y2+0.375);
951 glEnd();
952 end;
953 end
954 else
955 begin
956 glLineWidth(1);
957 glBegin(GL_LINES);
958 glVertex2i(x1, y1);
959 glVertex2i(x2, y2);
960 // draw last point
961 glVertex2i(x2, y2);
962 glVertex2i(x2+1, y2+1);
963 glEnd();
964 end;
965 end;
968 procedure TGxContext.hline (x, y, len: Integer);
969 begin
970 if (not self.active) or (mClipRect.w < 1) or (mClipRect.h < 1) or (mColor.a = 0) then exit;
971 if (len < 1) then exit;
972 if (not mScaled) then
973 begin
974 glLineWidth(1);
975 glBegin(GL_LINES);
976 glVertex2f(x+0.375, y+0.375);
977 glVertex2f(x+len+0.375, y+0.375);
978 glEnd();
979 end
980 else if (mScale > 1.0) then
981 begin
982 glBegin(GL_QUADS);
983 glVertex2i(x, y);
984 glVertex2i(x+len, y);
985 glVertex2i(x+len, y+1);
986 glVertex2i(x, y+1);
987 glEnd();
988 end
989 else
990 begin
991 glPointSize(1);
992 glBegin(GL_POINTS);
993 while (len > 0) do begin glVertex2i(x, y); Inc(x); Dec(len); end;
994 glEnd();
995 end;
996 end;
999 procedure TGxContext.vline (x, y, len: Integer);
1000 begin
1001 if (not self.active) or (mClipRect.w < 1) or (mClipRect.h < 1) or (mColor.a = 0) then exit;
1002 if (len < 1) then exit;
1003 if (not mScaled) then
1004 begin
1005 glLineWidth(1);
1006 glBegin(GL_LINES);
1007 glVertex2f(x+0.375, y+0.375);
1008 glVertex2f(x+0.375, y+len+0.375);
1009 glEnd();
1010 end
1011 else if (mScale > 1.0) then
1012 begin
1013 glBegin(GL_QUADS);
1014 glVertex2i(x, y);
1015 glVertex2i(x, y+len);
1016 glVertex2i(x+1, y+len);
1017 glVertex2i(x+1, y);
1018 glEnd();
1019 end
1020 else
1021 begin
1022 glPointSize(1);
1023 glBegin(GL_POINTS);
1024 while (len > 0) do begin glVertex2i(x, y); Inc(y); Dec(len); end;
1025 glEnd();
1026 end;
1027 end;
1030 procedure TGxContext.rect (x, y, w, h: Integer);
1031 begin
1032 if (not self.active) or (mClipRect.w < 1) or (mClipRect.h < 1) or (mColor.a = 0) then exit;
1033 if (w < 0) or (h < 0) then exit;
1034 if (w = 1) and (h = 1) then
1035 begin
1036 glPointSize(1);
1037 glBegin(GL_POINTS);
1038 if mScaled then glVertex2i(x, y) else glVertex2f(x+0.375, y+0.375);
1039 glEnd();
1040 end
1041 else
1042 begin
1043 if (not mScaled) then
1044 begin
1045 glLineWidth(1);
1046 glBegin(GL_LINES);
1047 glVertex2i(x, y); glVertex2i(x+w, y); // top
1048 glVertex2i(x, y+h-1); glVertex2i(x+w, y+h-1); // bottom
1049 glVertex2f(x+0.375, y+1); glVertex2f(x+0.375, y+h-1); // left
1050 glVertex2f(x+w-1+0.375, y+1); glVertex2f(x+w-1+0.375, y+h-1); // right
1051 glEnd();
1052 end
1053 else
1054 begin
1055 hline(x, y, w);
1056 hline(x, y+h-1, w);
1057 vline(x, y+1, h-2);
1058 vline(x+w-1, y+1, h-2);
1059 end;
1060 end;
1061 end;
1064 procedure TGxContext.fillRect (x, y, w, h: Integer);
1065 begin
1066 if (not self.active) or (mClipRect.w < 1) or (mClipRect.h < 1) or (mColor.a = 0) then exit;
1067 if (w < 0) or (h < 0) then exit;
1068 glBegin(GL_QUADS);
1069 glVertex2f(x, y);
1070 glVertex2f(x+w, y);
1071 glVertex2f(x+w, y+h);
1072 glVertex2f(x, y+h);
1073 glEnd();
1074 end;
1077 procedure TGxContext.darkenRect (x, y, w, h: Integer; a: Integer);
1078 begin
1079 if (not self.active) or (mClipRect.w < 1) or (mClipRect.h < 1) or (a >= 255) then exit;
1080 if (w < 0) or (h < 0) then exit;
1081 if (a < 0) then a := 0;
1082 glEnable(GL_BLEND);
1083 glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
1084 glColor4f(0.0, 0.0, 0.0, a/255.0);
1085 glBegin(GL_QUADS);
1086 glVertex2i(x, y);
1087 glVertex2i(x+w, y);
1088 glVertex2i(x+w, y+h);
1089 glVertex2i(x, y+h);
1090 glEnd();
1091 setupGLColor(mColor);
1092 end;
1095 function TGxContext.charWidth (const ch: AnsiChar): Integer;
1096 begin
1097 result := mFont.charWidth(ch);
1098 end;
1100 function TGxContext.charHeight (const ch: AnsiChar): Integer;
1101 begin
1102 result := mFont.height;
1103 end;
1106 function TGxContext.textWidth (const s: AnsiString): Integer;
1107 begin
1108 result := mFont.textWidth(s);
1109 end;
1111 function TGxContext.textHeight (const s: AnsiString): Integer;
1112 begin
1113 result := mFont.height;
1114 end;
1117 function TGxContext.drawChar (x, y: Integer; const ch: AnsiChar): Integer; // returns char width
1118 begin
1119 result := mFont.charWidth(ch);
1120 if (not self.active) or (mClipRect.w < 1) or (mClipRect.h < 1) or (mColor.a = 0) then exit;
1121 TGxBmpFont(mFont).drawCharInternal(x, y, ch);
1122 end;
1124 function TGxContext.drawText (x, y: Integer; const s: AnsiString): Integer; // returns text width
1125 begin
1126 result := mFont.textWidth(s);
1127 if (not self.active) or (mClipRect.w < 1) or (mClipRect.h < 1) or (mColor.a = 0) or (Length(s) = 0) then exit;
1128 TGxBmpFont(mFont).drawTextInternal(x, y, s);
1129 end;
1132 function TGxContext.iconMarkWidth (ic: TMarkIcon): Integer;
1133 begin
1134 {$IFDEF FUI_TEXT_ICONS}
1135 case ic of
1136 TMarkIcon.Checkbox: result := textWidth('[x]');
1137 TMarkIcon.Radiobox: result := textWidth('(*)');
1138 else result := textWidth('[x]');
1139 end;
1140 {$ELSE}
1141 result := 11;
1142 {$ENDIF}
1143 end;
1145 function TGxContext.iconMarkHeight (ic: TMarkIcon): Integer;
1146 begin
1147 {$IFDEF FUI_TEXT_ICONS}
1148 case ic of
1149 TMarkIcon.Checkbox: result := textHeight('[x]');
1150 TMarkIcon.Radiobox: result := textHeight('(*)');
1151 else result := textHeight('[x]');
1152 end;
1153 {$ELSE}
1154 result := 8;
1155 {$ENDIF}
1156 end;
1158 procedure TGxContext.drawIconMark (ic: TMarkIcon; x, y: Integer; marked: Boolean);
1159 var
1160 {$IFDEF FUI_TEXT_ICONS}
1161 xstr: AnsiString;
1162 {$ELSE}
1163 f: Integer;
1164 {$ENDIF}
1165 begin
1166 if (not self.active) or (mClipRect.w < 1) or (mClipRect.h < 1) or (mColor.a = 0) then exit;
1167 {$IFDEF FUI_TEXT_ICONS}
1168 case ic of
1169 TMarkIcon.Checkbox: xstr := '[x]';
1170 TMarkIcon.Radiobox: xstr := '(*)';
1171 else exit;
1172 end;
1173 if (marked) then
1174 begin
1175 drawText(x, y, xstr);
1176 end
1177 else
1178 begin
1179 drawChar(x, y, xstr[1]);
1180 drawChar(x+textWidth(xstr)-charWidth(xstr[3]), y, xstr[3]);
1181 end;
1182 {$ELSE}
1183 if (ic = TMarkIcon.Checkbox) then
1184 begin
1185 vline(x, y, 7);
1186 vline(x+10, y, 7);
1187 hline(x+1, y, 1);
1188 hline(x+1, y+6, 1);
1189 hline(x+9, y, 1);
1190 hline(x+9, y+6, 1);
1191 end
1192 else
1193 begin
1194 vline(x, y+1, 5);
1195 vline(x+10, y+1, 5);
1196 hline(x+1, y, 1);
1197 hline(x+1, y+6, 1);
1198 hline(x+9, y, 1);
1199 hline(x+9, y+6, 1);
1200 end;
1201 if (not marked) then exit;
1202 case ic of
1203 TMarkIcon.Checkbox:
1204 begin
1205 for f := 0 to 4 do
1206 begin
1207 vline(x+3+f, y+1+f, 1);
1208 vline(x+7-f, y+1+f, 1);
1209 end;
1210 end;
1211 TMarkIcon.Radiobox:
1212 begin
1213 hline(x+4, y+1, 3);
1214 hline(x+3, y+2, 5);
1215 hline(x+3, y+3, 5);
1216 hline(x+3, y+4, 5);
1217 hline(x+4, y+5, 3);
1218 end;
1219 end;
1220 {$ENDIF}
1221 end;
1224 function TGxContext.iconWinWidth (ic: TWinIcon): Integer;
1225 begin
1226 {$IFDEF FUI_TEXT_ICONS}
1227 case ic of
1228 TWinIcon.Close: result := nmax(textWidth('[x]'), textWidth('[#]'));
1229 else result := nmax(textWidth('[x]'), textWidth('[#]'));
1230 end;
1231 {$ELSE}
1232 result := 9;
1233 {$ENDIF}
1234 end;
1236 function TGxContext.iconWinHeight (ic: TWinIcon): Integer;
1237 begin
1238 {$IFDEF FUI_TEXT_ICONS}
1239 case ic of
1240 TWinIcon.Close: result := nmax(textHeight('[x]'), textHeight('[#]'));
1241 else result := nmax(textHeight('[x]'), textHeight('[#]'));
1242 end;
1243 {$ELSE}
1244 result := 8;
1245 {$ENDIF}
1246 end;
1248 procedure TGxContext.drawIconWin (ic: TWinIcon; x, y: Integer; pressed: Boolean);
1249 var
1250 {$IFDEF FUI_TEXT_ICONS}
1251 xstr: AnsiString;
1252 wdt: Integer;
1253 {$ELSE}
1254 f: Integer;
1255 {$ENDIF}
1256 begin
1257 if (not self.active) or (mClipRect.w < 1) or (mClipRect.h < 1) or (mColor.a = 0) then exit;
1258 {$IFDEF FUI_TEXT_ICONS}
1259 case ic of
1260 TWinIcon.Close: if (pressed) then xstr := '[#]' else xstr := '[x]';
1261 else exit;
1262 end;
1263 wdt := nmax(textWidth('[x]'), textWidth('[#]'));
1264 drawChar(x, y, xstr[1]);
1265 drawChar(x+wdt-charWidth(xstr[3]), y, xstr[3]);
1266 drawChar(x+((wdt-charWidth(xstr[2])) div 2), y, xstr[2]);
1267 {$ELSE}
1268 if pressed then rect(x, y, 9, 8);
1269 for f := 1 to 5 do
1270 begin
1271 vline(x+1+f, y+f, 1);
1272 vline(x+1+6-f, y+f, 1);
1273 end;
1274 {$ENDIF}
1275 end;
1278 procedure TGxContext.glSetScale (ascale: Single);
1279 begin
1280 if (ascale < 0.01) then ascale := 0.01;
1281 glLoadIdentity();
1282 glScalef(ascale, ascale, 1.0);
1283 mScale := ascale;
1284 mScaled := (ascale <> 1.0);
1285 end;
1287 procedure TGxContext.glSetTrans (ax, ay: Single);
1288 begin
1289 glLoadIdentity();
1290 glScalef(mScale, mScale, 1.0);
1291 glTranslatef(ax, ay, 0);
1292 end;
1295 procedure TGxContext.glSetScaleTrans (ascale, ax, ay: Single);
1296 begin
1297 glSetScale(ascale);
1298 glTranslatef(ax, ay, 0);
1299 end;
1302 // vertical scroll bar
1303 procedure TGxContext.drawVSBar (x, y, wdt, hgt: Integer; cur, min, max: Integer; constref clrfull, clrempty: TGxRGBA);
1304 var
1305 filled: Integer;
1306 begin
1307 if (wdt < 1) or (hgt < 1) then exit;
1308 filled := sbarFilled(hgt, cur, min, max);
1309 color := clrfull;
1310 fillRect(x, y, wdt, filled);
1311 color := clrempty;
1312 fillRect(x, y+filled, wdt, hgt-filled);
1313 end;
1316 // horizontal scrollbar
1317 procedure TGxContext.drawHSBar (x, y, wdt, hgt: Integer; cur, min, max: Integer; constref clrfull, clrempty: TGxRGBA);
1318 var
1319 filled: Integer;
1320 begin
1321 if (wdt < 1) or (hgt < 1) then exit;
1322 filled := sbarFilled(wdt, cur, min, max);
1323 color := clrfull;
1324 fillRect(x, y, filled, hgt);
1325 color := clrempty;
1326 fillRect(x+filled, y, wdt-filled, hgt);
1327 end;
1330 // ////////////////////////////////////////////////////////////////////////// //
1331 (*
1332 procedure oglRestoreMode (doClear: Boolean);
1333 begin
1334 oglSetup2D(fuiScrWdt, fuiScrHgt);
1335 glScissor(0, 0, fuiScrWdt, fuiScrHgt);
1337 glBindTexture(GL_TEXTURE_2D, 0);
1338 glDisable(GL_BLEND);
1339 glDisable(GL_TEXTURE_2D);
1340 glDisable(GL_STENCIL_TEST);
1341 glDisable(GL_SCISSOR_TEST);
1342 glDisable(GL_LIGHTING);
1343 glDisable(GL_DEPTH_TEST);
1344 glDisable(GL_CULL_FACE);
1345 glDisable(GL_LINE_SMOOTH);
1346 glDisable(GL_POINT_SMOOTH);
1347 glLineWidth(1);
1348 glPointSize(1);
1349 glColor4f(1, 1, 1, 1);
1351 if doClear then
1352 begin
1353 glClearColor(0, 0, 0, 0);
1354 glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT or GL_ACCUM_BUFFER_BIT or GL_STENCIL_BUFFER_BIT);
1355 end;
1357 // scale everything
1358 glMatrixMode(GL_MODELVIEW);
1359 glLoadIdentity();
1360 //glScalef(4, 4, 1);
1361 end;
1362 *)
1365 //procedure onWinFocus (); begin uiFocus(); end;
1366 //procedure onWinBlur (); begin fuiResetKMState(true); uiBlur(); end;
1368 //procedure onPreRender (); begin oglRestoreMode(gGfxDoClear); end;
1369 procedure onPostRender (); begin oglDrawCursor(); end;
1371 procedure onInit ();
1372 begin
1373 //oglSetup2D(fuiScrWdt, fuiScrHgt);
1374 createCursorTexture();
1375 oglInitFonts();
1376 end;
1378 procedure onDeinit ();
1379 begin
1380 fuiResetKMState(false);
1381 if (curtexid <> 0) then glDeleteTextures(1, @curtexid);
1382 curtexid := 0;
1383 oglDeinitFonts();
1384 fuiSetButState(0);
1385 fuiSetModState(0);
1386 fuiSetMouseX(0);
1387 fuiSetMouseY(0);
1388 end;
1391 // ////////////////////////////////////////////////////////////////////////// //
1392 initialization
1393 savedGLState := TSavedGLState.Create(false);
1394 //createFonts();
1395 //winFocusCB := onWinFocus;
1396 //winBlurCB := onWinBlur;
1397 //prerenderFrameCB := onPreRender;
1398 postrenderFrameCB := onPostRender;
1399 oglInitCB := onInit;
1400 oglDeinitCB := onDeinit;
1402 gxPreSetContextCallback := gxGLPreSetContextCallback;
1403 gxCreateContextCallback := gxGLCreateContextCallback;
1404 gxFuiGfxLoadFontCallback := fuiGfxLoadFont;
1405 end.