1 /*
2  * Copyright (C) 2014 Neverball authors
3  *
4  * NEVERBALL is  free software; you can redistribute  it and/or modify
5  * it under the  terms of the GNU General  Public License as published
6  * by the Free  Software Foundation; either version 2  of the License,
7  * or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT  ANY  WARRANTY;  without   even  the  implied  warranty  of
11  * MERCHANTABILITY or  FITNESS FOR A PARTICULAR PURPOSE.   See the GNU
12  * General Public License for more details.
13  */
14 
15 #include "theme.h"
16 #include "config.h"
17 #include "image.h"
18 #include "video.h"
19 
20 /*---------------------------------------------------------------------------*/
21 
22 static const char theme_images[THEME_IMAGES_MAX][PATHMAX] = {
23     "back-plain.png",       /* off and inactive    */
24     "back-plain-focus.png", /* off and   active    */
25     "back-hilite.png",      /* on  and inactive    */
26     "back-hilite-focus.png" /* on  and   active    */
27 };
28 
theme_image(const char * path)29 static GLuint theme_image(const char *path)
30 {
31     const int W = video.device_w;
32     const int H = video.device_h;
33 
34     int W2, H2;
35 
36     int w, h, b;
37     void *p;
38 
39     GLuint o = 0;
40 
41     /*
42      * Disable mipmapping and do a manual downscale.  Heuristic for
43      * downscaling the texture: assume target size to be roughly 1/16
44      * of a full screen texture, smallest size being 32x32.
45      */
46 
47     image_near2(&W2, &H2, W, H);
48 
49     W2 = MAX(W2 / 16, 32);
50     H2 = MAX(H2 / 16, 32);
51 
52     if ((p = image_load(path, &w, &h, &b)))
53     {
54         void *q;
55 
56         /* Prefer a small scale factor. */
57 
58         int s = MAX(w, h) / MAX(W2, H2);
59 
60         if (s > 1 && (q = image_scale(p, w, h, b, &w, &h, s)))
61         {
62             free(p);
63             p = q;
64         }
65 
66         o = make_texture(p, w, h, b, 0);
67 
68         free(p);
69         p = NULL;
70     }
71 
72     return o;
73 }
74 
theme_path(const char * name,const char * file)75 static const char *theme_path(const char *name, const char *file)
76 {
77     static char path[MAXSTR];
78 
79     if ((name && *name) && (file && *file))
80     {
81         SAFECPY(path, "gui/");
82         SAFECAT(path, name);
83         SAFECAT(path, "/");
84         SAFECAT(path, file);
85         return path;
86     }
87     return "";
88 }
89 
theme_load(struct theme * theme,const char * name)90 int theme_load(struct theme *theme, const char *name)
91 {
92     char buff[MAXSTR];
93     fs_file fp;
94 
95     float s[4] = { 0.25f, 0.25f, 0.25f, 0.25f };
96 
97     int i;
98 
99     if (theme && name && *name)
100     {
101         memset(theme, 0, sizeof (*theme));
102 
103         /* Load description. */
104 
105         if ((fp = fs_open(theme_path(name, "theme.txt"), "r")))
106         {
107             while ((fs_gets(buff, sizeof (buff), fp)))
108             {
109                 strip_newline(buff);
110 
111                 if (strncmp(buff, "slice ", 6) == 0)
112                     sscanf(buff + 6, "%f %f %f %f", &s[0], &s[1], &s[2], &s[3]);
113             }
114 
115             fs_close(fp);
116         }
117         else
118         {
119             log_printf("Failure to open \"%s\" theme file\n", name);
120         }
121 
122         theme->s[0] =  0.0f;
123         theme->s[1] =  s[0];
124         theme->s[2] = (1.0f - s[1]);
125         theme->s[3] =  1.0f;
126 
127         theme->t[0] =  1.0f;
128         theme->t[1] = (1.0f - s[2]);
129         theme->t[2] =  s[3];
130         theme->t[3] =  0.0f;
131 
132         /* Load textures. */
133 
134         for (i = 0; i < ARRAYSIZE(theme_images); i++)
135             theme->tex[i] = theme_image(theme_path(name, theme_images[i]));
136 
137         return 1;
138     }
139     return 0;
140 }
141 
theme_free(struct theme * theme)142 void theme_free(struct theme *theme)
143 {
144     int i;
145 
146     if (theme)
147     {
148         glDeleteTextures(THEME_IMAGES_MAX, theme->tex);
149 
150         for (i = 0; i < THEME_IMAGES_MAX; i++)
151             theme->tex[i] = 0;
152     }
153 }
154 
155 /*---------------------------------------------------------------------------*/
156