Browse code

ui: experimental font cache implementation

Dario Rodriguez authored on 11/11/2020 21:39:04
Showing 2 changed files
... ...
@@ -20,6 +20,8 @@
20 20
 #define DEFAULTTITLEPREFIX "re - "
21 21
 #define DEFAULTWINDOWWIDTH 80
22 22
 #define DEFAULTWINDOWHEIGHT 66
23
+#define FONTCACHEXSIZE 512
24
+#define FONTCACHEYSIZE 512
23 25
 
24 26
 #define RECTFILL(r,rx,ry,rw,rh) (r).x=(rx),(r).y=(ry),(r).w=(rw),(r).h=(rh)
25 27
 
... ...
@@ -46,7 +48,7 @@
46 48
 
47 49
 static int reui_fillrounded(SDL_Surface *dst, int xo, int yo, int w, int h, int r, const char *rgba);
48 50
 static int reui_triangle(SDL_Surface *dst, int x, int y, int w, int h, char direction, const char *rgba);
49
-
51
+static int reui_fontcachereset(reui_t *ui);
50 52
 
51 53
 reui_t *
52 54
 reui_init(int fontheight)
... ...
@@ -79,7 +81,7 @@ reui_init(int fontheight)
79 81
         ui->screenw=screenrect.w;
80 82
         ui->screenh=screenrect.h;
81 83
         /* font */
82
-        ui->fontheight=fontheight;
84
+        ui->fontheight=fontheight; /* placeholder, will fill later with real value */
83 85
         ui->fontdata=SDL_RWFromConstMem(hack_regular,SIZE_HACK_REGULAR);
84 86
         SDL_RWseek(ui->fontdata,0,RW_SEEK_SET);
85 87
         if(ui->fontdata==NULL
... ...
@@ -99,6 +101,17 @@ reui_init(int fontheight)
99 101
                 ui->fontwidth=s->w;
100 102
                 SDL_FreeSurface(s),s=NULL;
101 103
         }
104
+        /* font height */
105
+        {
106
+                SDL_Surface *s;
107
+                SDL_Color c={0,0,0,0};
108
+                if((s=TTF_RenderUTF8_Blended(ui->font,"gjpqy_",c))==NULL) {
109
+                        reui_free(ui),ui=NULL;
110
+                        return(NULL);
111
+                }
112
+                ui->fontheight=s->h;
113
+                SDL_FreeSurface(s),s=NULL;
114
+        }
102 115
         /* main window */
103 116
         ui->w=ui->fontwidth*DEFAULTWINDOWWIDTH;
104 117
         ui->w=(ui->w>ui->screenw)?ui->screenw:ui->w;
... ...
@@ -113,10 +126,15 @@ reui_init(int fontheight)
113 126
           || (ui->scr=SDL_CreateTexture(ui->renderer,SDL_PIXELFORMAT_ARGB8888,
114 127
               SDL_TEXTUREACCESS_STREAMING,ui->w,ui->h))==NULL
115 128
           || (ui->onepx=SDL_CreateTexture(ui->renderer,SDL_PIXELFORMAT_ARGB8888,
116
-              SDL_TEXTUREACCESS_STATIC,1,1))==NULL) {
129
+              SDL_TEXTUREACCESS_STATIC,1,1))==NULL
130
+          || (ui->fontcache=SDL_CreateTexture(ui->renderer,SDL_PIXELFORMAT_ARGB8888,
131
+              SDL_TEXTUREACCESS_STATIC,FONTCACHEXSIZE,FONTCACHEYSIZE))==NULL) {
117 132
                 reui_free(ui),ui=NULL;
118 133
                 return(NULL);
119 134
         }
135
+        /* font cache */
136
+        SDL_SetTextureBlendMode(ui->fontcache, SDL_BLENDMODE_BLEND);
137
+        reui_fontcachereset(ui);
120 138
         /* finished */
121 139
         ui->scrdirty=1;
122 140
         ui->rendererdirty=1;
... ...
@@ -129,6 +147,8 @@ reui_free(reui_t *ui)
129 147
 {
130 148
         if(ui==NULL)
131 149
                 return;
150
+        if(ui->fontcache!=NULL)
151
+                SDL_DestroyTexture(ui->fontcache),ui->fontcache=NULL;
132 152
         if(ui->onepx!=NULL)
133 153
                 SDL_DestroyTexture(ui->onepx),ui->onepx=NULL;
134 154
         if(ui->font!=NULL)
... ...
@@ -143,7 +163,6 @@ reui_free(reui_t *ui)
143 163
                 SDL_DestroyRenderer(ui->renderer),ui->renderer=NULL;
144 164
         if(ui->win!=NULL)
145 165
                 SDL_DestroyWindow(ui->win),ui->win=NULL;
146
-
147 166
         SDL_Quit();
148 167
         free(ui),ui=NULL;
149 168
 }
... ...
@@ -183,23 +202,29 @@ int
183 202
 reui_setfontheight(reui_t *ui, int fontheight)
184 203
 {
185 204
         TTF_Font *newfont;
186
-        SDL_Surface *s;
205
+        SDL_Surface *s,*s2;
187 206
         SDL_Color c={0,0,0,0};
188 207
         if(ui==NULL || fontheight<=0)
189 208
                 return(-1); /* sanity check failed */
190 209
         SDL_RWseek(ui->fontdata,0,RW_SEEK_SET);
191 210
         if((newfont=TTF_OpenFontRW(ui->fontdata,0,fontheight))==NULL)
192 211
                 return(-1); /* couln't setup new font */
193
-        if((s=TTF_RenderUTF8_Blended(newfont,"m",c))==NULL) {
212
+        if((s=TTF_RenderUTF8_Blended(newfont,"m",c))==NULL
213
+          || (s2=TTF_RenderUTF8_Blended(newfont,"gjpqy_",c))==NULL) {
214
+                if(s!=NULL)
215
+                        SDL_FreeSurface(s),s=NULL;
194 216
                 TTF_CloseFont(newfont),newfont=NULL;
195 217
                 return(-1); /* couldn't use new font */
196 218
         }
197 219
         if(ui->font!=NULL)
198 220
                 TTF_CloseFont(ui->font),ui->font=NULL;
199 221
         ui->font=newfont;
200
-        ui->fontheight=fontheight;
222
+        ui->fontheight=s2->h;
201 223
         ui->fontwidth=s->w;
202 224
         SDL_FreeSurface(s),s=NULL;
225
+        SDL_FreeSurface(s2),s2=NULL;
226
+        /* font cache */
227
+        reui_fontcachereset(ui);
203 228
         return(0);
204 229
 }
205 230
 
... ...
@@ -247,6 +272,7 @@ reui_present(reui_t *ui)
247 272
 int
248 273
 reui_write(reui_t *ui, int x, int y, const char *rgba, const char *str, int nchar)
249 274
 {
275
+#if 0
250 276
         char buf[1024];
251 277
         SDL_Surface *fgsurface;
252 278
         SDL_Texture *fg;
... ...
@@ -274,6 +300,84 @@ reui_write(reui_t *ui, int x, int y, const char *rgba, const char *str, int ncha
274 300
         SDL_FreeSurface(fgsurface),fgsurface=NULL;
275 301
         SDL_DestroyTexture(fg),fg=NULL;
276 302
         return(0);
303
+#else
304
+        int curcol;
305
+        char smallbuf[2];
306
+        int maxcached;
307
+        int cachelines,cachecols;
308
+        Uint32 *pixels;
309
+        char buf[1024];
310
+        SDL_Surface *fgsurface;
311
+        SDL_Texture *fg;
312
+        SDL_Color c={((unsigned char *)rgba)[0],
313
+                     ((unsigned char *)rgba)[1],
314
+                     ((unsigned char *)rgba)[2],
315
+                     ((unsigned char *)rgba)[3]};
316
+        SDL_Color whitec={255,255,255,255};
317
+        SDL_Rect srcrect,dstrect;
318
+        int i,n;
319
+        int has_uncached;
320
+        if(nchar<sizeof(buf)) {
321
+                memcpy(buf,str,nchar);
322
+                buf[nchar]='\0';
323
+        } else {
324
+                memcpy(buf,str,sizeof(buf)-1);
325
+                buf[sizeof(buf)-1]='\0';
326
+        }
327
+        SDL_SetTextureColorMod(ui->fontcache, c.r, c.g, c.b);
328
+        cachelines=(ui->fontheight>0)?(FONTCACHEYSIZE/ui->fontheight):0;
329
+        cachecols=(ui->fontwidth>0)?(FONTCACHEXSIZE/ui->fontwidth):0;
330
+        maxcached=cachelines*cachecols;
331
+        /* write cached characters (or fill cache) */
332
+        has_uncached=0;
333
+        for(i=0,curcol=-1;buf[i]!='\0';i++) {
334
+                curcol+=(((buf[i]&0xc0)!=0x80)?1:0); /* this detects an utf-8 start byte, and advances one pos if true */
335
+                if(!(buf[i]>=FONTCACHESTART && buf[i]<=FONTCACHEEND) || maxcached==0) {
336
+                        has_uncached=1;
337
+                        continue;
338
+                }
339
+                /* fill cache if possible */
340
+                if(ui->usedfontcache<maxcached && ui->fontcachewhere[buf[i]-FONTCACHESTART]==0) {
341
+                        smallbuf[0]=buf[i],smallbuf[1]='\0';
342
+                        if((fgsurface=TTF_RenderUTF8_Blended(ui->font,smallbuf,whitec))==NULL)
343
+                                return(-1); /* cannot create text */
344
+                        SDL_LockSurface(fgsurface);
345
+                        pixels=(Uint32*)(fgsurface->pixels);
346
+                        RECTFILL(dstrect,(ui->usedfontcache%cachecols)*ui->fontwidth,(ui->usedfontcache/cachecols)*ui->fontheight,ui->fontwidth,ui->fontheight);
347
+                        SDL_UpdateTexture(ui->fontcache,&dstrect,pixels,sizeof(Uint32)*fgsurface->w);
348
+                        SDL_UnlockSurface(fgsurface);
349
+                        if(fgsurface!=NULL)
350
+                                SDL_FreeSurface(fgsurface),fgsurface=NULL;
351
+                        ui->usedfontcache++;
352
+                        ui->fontcachewhere[buf[i]-FONTCACHESTART]=ui->usedfontcache; /* one more than real pos, as 0 is not init */
353
+                }
354
+                /* if cached, write from there and change the letter to space */
355
+                if(ui->fontcachewhere[buf[i]-FONTCACHESTART]!=0) {
356
+                        n=ui->fontcachewhere[buf[i]-FONTCACHESTART]-1;
357
+                        RECTFILL(srcrect,((n%cachecols)*ui->fontwidth),((n/cachecols)*ui->fontheight),ui->fontwidth,ui->fontheight);
358
+                        RECTFILL(dstrect,(x+ui->fontwidth*curcol),y,ui->fontwidth,ui->fontheight);
359
+                        SDL_RenderCopy(ui->renderer,ui->fontcache,&srcrect,&dstrect);
360
+                        buf[i]=' ';
361
+                } else {
362
+                        has_uncached=1;
363
+                }
364
+        }
365
+        /* write uncached characters */
366
+        if(has_uncached) {
367
+                if((fgsurface=TTF_RenderUTF8_Blended(ui->font,buf,c))==NULL
368
+                  || (fg=SDL_CreateTextureFromSurface(ui->renderer,fgsurface))==NULL) {
369
+                        if(fgsurface!=NULL)
370
+                                SDL_FreeSurface(fgsurface),fgsurface=NULL;
371
+                        return(-1);
372
+                }
373
+                RECTFILL(dstrect,x,y,fgsurface->w,fgsurface->h);
374
+                SDL_RenderCopy(ui->renderer,fg,NULL,&dstrect);
375
+                SDL_FreeSurface(fgsurface),fgsurface=NULL;
376
+                SDL_DestroyTexture(fg),fg=NULL;
377
+        }
378
+        ui->rendererdirty=1;
379
+        return(0);
380
+#endif
277 381
 }
278 382
 
279 383
 
... ...
@@ -523,3 +627,12 @@ reui_triangle(SDL_Surface *dst, int x, int y, int w, int h, char direction, cons
523 627
         return(0);
524 628
 }
525 629
 
630
+static int
631
+reui_fontcachereset(reui_t *ui)
632
+{
633
+        if(ui==NULL || ui->fontcache==NULL)
634
+                return(-1); /* sanity check failed */
635
+        ui->usedfontcache=0;
636
+        memset(ui->fontcachewhere,0,sizeof(ui->fontcachewhere));
637
+        return(0);
638
+}
... ...
@@ -17,6 +17,8 @@
17 17
 #include "SDL_ttf.h"
18 18
 
19 19
 
20
+#define FONTCACHESTART ' '
21
+#define FONTCACHEEND '~'
20 22
 
21 23
 typedef struct reui_t {
22 24
         int screenw,screenh;
... ...
@@ -28,6 +30,9 @@ typedef struct reui_t {
28 30
         SDL_RWops *fontdata;
29 31
         TTF_Font *font;
30 32
         SDL_Texture *onepx;
33
+        int usedfontcache;
34
+        SDL_Texture *fontcache;
35
+        int fontcachewhere[FONTCACHEEND-FONTCACHESTART];
31 36
         int fontheight;
32 37
         int fontwidth;
33 38
         int scrdirty;