rev |
line source |
nuclear@6
|
1 /*
|
nuclear@6
|
2 GoatKit - a themable/animated widget toolkit for games
|
nuclear@9
|
3 Copyright (C) 2014-2015 John Tsiombikas <nuclear@member.fsf.org>
|
nuclear@6
|
4
|
nuclear@6
|
5 This program is free software: you can redistribute it and/or modify
|
nuclear@6
|
6 it under the terms of the GNU Lesser General Public License as published by
|
nuclear@6
|
7 the Free Software Foundation, either version 3 of the License, or
|
nuclear@6
|
8 (at your option) any later version.
|
nuclear@6
|
9
|
nuclear@6
|
10 This program is distributed in the hope that it will be useful,
|
nuclear@6
|
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nuclear@6
|
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nuclear@6
|
13 GNU Lesser General Public License for more details.
|
nuclear@6
|
14
|
nuclear@6
|
15 You should have received a copy of the GNU Lesser General Public License
|
nuclear@6
|
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
nuclear@6
|
17 */
|
nuclear@6
|
18 #include "config.h"
|
nuclear@6
|
19 #include <stdio.h>
|
nuclear@6
|
20 #include <vector>
|
nuclear@6
|
21 #include <string>
|
nuclear@6
|
22 #include <map>
|
nuclear@6
|
23 #include <algorithm>
|
nuclear@9
|
24 #include <string.h>
|
nuclear@6
|
25 #include "theme.h"
|
nuclear@6
|
26 #include "widget.h"
|
nuclear@6
|
27
|
nuclear@6
|
28 #ifdef WIN32
|
nuclear@6
|
29 #include <windows.h>
|
nuclear@6
|
30
|
nuclear@9
|
31 #define RTLD_DEFAULT ((void*)0)
|
nuclear@9
|
32
|
nuclear@6
|
33 static void *dlopen(const char *name, int flags);
|
nuclear@6
|
34 static void dlclose(void *so);
|
nuclear@6
|
35 static void *dlsym(void *so, const char *symbol);
|
nuclear@6
|
36 #else
|
nuclear@6
|
37 #include <unistd.h>
|
nuclear@6
|
38 #include <dlfcn.h>
|
nuclear@6
|
39 #endif
|
nuclear@6
|
40
|
nuclear@6
|
41 #ifdef HAVE_OPENGL_H
|
nuclear@6
|
42 #include "opengl.h"
|
nuclear@6
|
43
|
nuclear@6
|
44 #else
|
nuclear@6
|
45
|
nuclear@6
|
46 #ifdef __APPLE__
|
nuclear@6
|
47 #include <OpenGL/gl.h>
|
nuclear@6
|
48 #else
|
nuclear@6
|
49 #include <GL/gl.h>
|
nuclear@6
|
50 #endif
|
nuclear@6
|
51
|
nuclear@6
|
52 #endif /* HAVE_OPENGL_H_ */
|
nuclear@6
|
53
|
nuclear@6
|
54 #ifndef PREFIX
|
nuclear@6
|
55 #define PREFIX "/usr/local"
|
nuclear@6
|
56 #endif
|
nuclear@6
|
57
|
nuclear@6
|
58 namespace goatkit {
|
nuclear@6
|
59
|
nuclear@6
|
60 struct ThemeImpl {
|
nuclear@6
|
61 void *so;
|
nuclear@6
|
62 WidgetDrawFunc (*lookup_theme_draw_func)(const char*);
|
nuclear@6
|
63 mutable std::map<std::string, WidgetDrawFunc> func_cache;
|
nuclear@6
|
64 };
|
nuclear@6
|
65
|
nuclear@6
|
66 Theme *theme;
|
nuclear@6
|
67 static std::vector<std::string> search_paths;
|
nuclear@6
|
68 static const char *fallback_paths[] = {
|
nuclear@6
|
69 PREFIX "/share/goatkit",
|
nuclear@6
|
70 0
|
nuclear@6
|
71 };
|
nuclear@6
|
72
|
nuclear@6
|
73 void add_theme_path(const char *path)
|
nuclear@6
|
74 {
|
nuclear@6
|
75 if(!path || !*path) return;
|
nuclear@6
|
76
|
nuclear@6
|
77 std::string s = path;
|
nuclear@6
|
78 int last = s.length() - 1;
|
nuclear@6
|
79 if(s[last] == '/' || s[last] == '\\') {
|
nuclear@6
|
80 s.erase(last);
|
nuclear@6
|
81 }
|
nuclear@6
|
82
|
nuclear@6
|
83 if(std::find(search_paths.begin(), search_paths.end(), s) != search_paths.end()) {
|
nuclear@6
|
84 return;
|
nuclear@6
|
85 }
|
nuclear@6
|
86
|
nuclear@6
|
87 search_paths.push_back(s);
|
nuclear@6
|
88 }
|
nuclear@6
|
89
|
nuclear@6
|
90 Theme::Theme()
|
nuclear@6
|
91 {
|
nuclear@6
|
92 impl = new ThemeImpl;
|
nuclear@6
|
93 impl->so = 0;
|
nuclear@6
|
94 impl->lookup_theme_draw_func = 0;
|
nuclear@6
|
95 }
|
nuclear@6
|
96
|
nuclear@6
|
97 Theme::~Theme()
|
nuclear@6
|
98 {
|
nuclear@6
|
99 unload();
|
nuclear@6
|
100 delete impl;
|
nuclear@6
|
101 }
|
nuclear@6
|
102
|
nuclear@6
|
103 typedef WidgetDrawFunc (*LookupFunc)(const char*);
|
nuclear@6
|
104
|
nuclear@6
|
105 bool Theme::load(const char *name)
|
nuclear@6
|
106 {
|
nuclear@6
|
107 unload();
|
nuclear@6
|
108
|
nuclear@7
|
109 if(strcmp(name, "GOATKIT_THEME_BUILTIN") == 0) {
|
nuclear@7
|
110 impl->so = RTLD_DEFAULT;
|
nuclear@7
|
111 } else {
|
nuclear@7
|
112 std::string fname = std::string(name) + ".gtheme";
|
nuclear@7
|
113 if(!(impl->so = dlopen(fname.c_str(), RTLD_LAZY))) {
|
nuclear@7
|
114 for(size_t i=0; i<search_paths.size(); i++) {
|
nuclear@7
|
115 std::string path = search_paths[i] + "/" + fname;
|
nuclear@6
|
116
|
nuclear@6
|
117 if((impl->so = dlopen(path.c_str(), RTLD_LAZY))) {
|
nuclear@6
|
118 break;
|
nuclear@6
|
119 }
|
nuclear@6
|
120 }
|
nuclear@6
|
121
|
nuclear@7
|
122 // try the fallback paths
|
nuclear@7
|
123 if(!impl->so) {
|
nuclear@7
|
124 for(int i=0; fallback_paths[i]; i++) {
|
nuclear@7
|
125 std::string path = std::string(fallback_paths[i]) + "/" + fname;
|
nuclear@7
|
126
|
nuclear@7
|
127 if((impl->so = dlopen(path.c_str(), RTLD_LAZY))) {
|
nuclear@7
|
128 break;
|
nuclear@7
|
129 }
|
nuclear@7
|
130 }
|
nuclear@7
|
131 }
|
nuclear@7
|
132
|
nuclear@7
|
133 if(!impl->so) {
|
nuclear@7
|
134 fprintf(stderr, "%s: failed to load theme plugin: %s\n", __func__, name);
|
nuclear@7
|
135 return false;
|
nuclear@7
|
136 }
|
nuclear@6
|
137 }
|
nuclear@6
|
138 }
|
nuclear@6
|
139
|
nuclear@6
|
140 // loaded the shared object, now get the lookup function
|
nuclear@6
|
141 impl->lookup_theme_draw_func = (LookupFunc)dlsym(impl->so, "get_widget_func");
|
nuclear@6
|
142 if(!impl->lookup_theme_draw_func) {
|
nuclear@6
|
143 fprintf(stderr, "%s: invalid theme plugin %s\n", __func__, name);
|
nuclear@6
|
144 unload();
|
nuclear@6
|
145 return false;
|
nuclear@6
|
146 }
|
nuclear@6
|
147
|
nuclear@6
|
148 return true;
|
nuclear@6
|
149 }
|
nuclear@6
|
150
|
nuclear@6
|
151 void Theme::unload()
|
nuclear@6
|
152 {
|
nuclear@6
|
153 if(impl->so) {
|
nuclear@7
|
154 if(impl->so != RTLD_DEFAULT) {
|
nuclear@7
|
155 dlclose(impl->so);
|
nuclear@7
|
156 }
|
nuclear@6
|
157 impl->so = 0;
|
nuclear@6
|
158 }
|
nuclear@6
|
159 impl->func_cache.clear();
|
nuclear@6
|
160 }
|
nuclear@6
|
161
|
nuclear@6
|
162 WidgetDrawFunc Theme::get_draw_func(const char *type) const
|
nuclear@6
|
163 {
|
nuclear@6
|
164 std::map<std::string, WidgetDrawFunc>::const_iterator it = impl->func_cache.find(type);
|
nuclear@6
|
165 if(it == impl->func_cache.end()) {
|
nuclear@6
|
166 // don't have it cached, try to look it up
|
nuclear@6
|
167 WidgetDrawFunc func;
|
nuclear@6
|
168 if(impl->lookup_theme_draw_func && (func = impl->lookup_theme_draw_func(type))) {
|
nuclear@6
|
169 impl->func_cache[type] = func;
|
nuclear@6
|
170 return func;
|
nuclear@6
|
171 }
|
nuclear@6
|
172
|
nuclear@6
|
173 // can't look it up, return the default
|
nuclear@6
|
174 return default_draw_func;
|
nuclear@6
|
175 }
|
nuclear@6
|
176 return it->second;
|
nuclear@6
|
177 }
|
nuclear@6
|
178
|
nuclear@6
|
179 #define LERP(a, b, t) ((a) + ((b) - (a)) * t)
|
nuclear@6
|
180 #define DEF_TEX_SZ 32
|
nuclear@6
|
181 void default_draw_func(const Widget *w)
|
nuclear@6
|
182 {
|
nuclear@6
|
183 static unsigned int tex;
|
nuclear@6
|
184
|
nuclear@6
|
185 if(!tex) {
|
nuclear@6
|
186 unsigned char *pixels = new unsigned char[DEF_TEX_SZ * DEF_TEX_SZ * 3];
|
nuclear@6
|
187 unsigned char *ptr = pixels;
|
nuclear@6
|
188 for(int i=0; i<DEF_TEX_SZ; i++) {
|
nuclear@6
|
189 for(int j=0; j<DEF_TEX_SZ; j++) {
|
nuclear@6
|
190 bool stripe = (((j + i) / 8) & 1) == 1;
|
nuclear@6
|
191 ptr[0] = ptr[1] = ptr[2] = stripe ? 255 : 0;
|
nuclear@6
|
192 ptr += 3;
|
nuclear@6
|
193 }
|
nuclear@6
|
194 }
|
nuclear@6
|
195
|
nuclear@6
|
196 glGenTextures(1, &tex);
|
nuclear@6
|
197 glBindTexture(GL_TEXTURE_2D, tex);
|
nuclear@6
|
198 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
nuclear@6
|
199 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
nuclear@6
|
200 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, DEF_TEX_SZ, DEF_TEX_SZ, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
|
nuclear@6
|
201 delete [] pixels;
|
nuclear@6
|
202 }
|
nuclear@6
|
203
|
nuclear@6
|
204 Vec2 pos = w->get_position();
|
nuclear@6
|
205 Vec2 sz = w->get_size();
|
nuclear@6
|
206 float aspect = sz.x / sz.y;
|
nuclear@6
|
207
|
nuclear@6
|
208 #if !defined(GL_ES_VERSION_2_0)
|
nuclear@6
|
209 glPushAttrib(GL_ENABLE_BIT);
|
nuclear@6
|
210 glEnable(GL_TEXTURE_2D);
|
nuclear@6
|
211 #endif
|
nuclear@6
|
212 glBindTexture(GL_TEXTURE_2D, tex);
|
nuclear@6
|
213
|
nuclear@6
|
214 float offs = w->get_pressed() * 0.1 * sz.y;
|
nuclear@6
|
215 glMatrixMode(GL_MODELVIEW);
|
nuclear@6
|
216 glPushMatrix();
|
nuclear@6
|
217 glTranslatef(offs, -offs, 0);
|
nuclear@6
|
218
|
nuclear@6
|
219 float active = w->get_active();
|
nuclear@6
|
220 float hover = w->get_under_mouse();
|
nuclear@6
|
221
|
nuclear@6
|
222 float rg = LERP(0.4, 1.0, hover);
|
nuclear@6
|
223 float b = LERP(rg, 0, active);
|
nuclear@6
|
224 glColor3f(rg, rg, b);
|
nuclear@6
|
225
|
nuclear@6
|
226 glBegin(GL_QUADS);
|
nuclear@6
|
227 glTexCoord2f(0, 1);
|
nuclear@6
|
228 glVertex2f(pos.x, pos.y);
|
nuclear@6
|
229 glTexCoord2f(aspect, 1);
|
nuclear@6
|
230 glVertex2f(pos.x + sz.x, pos.y);
|
nuclear@6
|
231 glTexCoord2f(aspect, 0);
|
nuclear@6
|
232 glVertex2f(pos.x + sz.x, pos.y + sz.y);
|
nuclear@6
|
233 glTexCoord2f(0, 0);
|
nuclear@6
|
234 glVertex2f(pos.x, pos.y + sz.y);
|
nuclear@6
|
235 glEnd();
|
nuclear@6
|
236
|
nuclear@6
|
237 glPopMatrix();
|
nuclear@6
|
238
|
nuclear@6
|
239 #ifndef GL_ES_VERSION_2_0
|
nuclear@6
|
240 glPopAttrib();
|
nuclear@6
|
241 #endif
|
nuclear@6
|
242 }
|
nuclear@6
|
243
|
nuclear@6
|
244 } // namespace goatkit
|
nuclear@6
|
245
|
nuclear@6
|
246 #ifdef WIN32
|
nuclear@6
|
247 // XXX untested
|
nuclear@6
|
248 static void *dlopen(const char *name, int flags)
|
nuclear@6
|
249 {
|
nuclear@6
|
250 return LoadLibrary(name);
|
nuclear@6
|
251 }
|
nuclear@6
|
252
|
nuclear@6
|
253 static void dlclose(void *so)
|
nuclear@6
|
254 {
|
nuclear@6
|
255 FreeLibrary(so);
|
nuclear@6
|
256 }
|
nuclear@6
|
257
|
nuclear@6
|
258 static void *dlsym(void *so, const char *symbol)
|
nuclear@6
|
259 {
|
nuclear@7
|
260 if(so == RTLD_DEFAULT) {
|
nuclear@7
|
261 so = GetModuleHandle(0);
|
nuclear@7
|
262 }
|
nuclear@6
|
263 return (void*)GetProcAddress(so, symbol);
|
nuclear@6
|
264 }
|
nuclear@6
|
265 #endif
|