Atrinik Client  4.0
texture.c
Go to the documentation of this file.
1 /*************************************************************************
2  * Atrinik, a Multiplayer Online Role Playing Game *
3  * *
4  * Copyright (C) 2009-2014 Alex Tokar and Atrinik Development Team *
5  * *
6  * Fork from Crossfire (Multiplayer game for X-windows). *
7  * *
8  * This program is free software; you can redistribute it and/or modify *
9  * it under the terms of the GNU General Public License as published by *
10  * the Free Software Foundation; either version 2 of the License, or *
11  * (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this program; if not, write to the Free Software *
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
21  * *
22  * The author can be reached at admin@atrinik.org *
23  ************************************************************************/
24 
32 #include <global.h>
33 #include <toolkit/string.h>
34 
38 static texture_struct *textures[TEXTURE_TYPE_NUM];
39 
46 {
47  if (tmp->surface) {
48  SDL_FreeSurface(tmp->surface);
49  tmp->surface = NULL;
50  }
51 }
52 
61 {
62  if (tmp->type == TEXTURE_TYPE_SOFTWARE) {
63  SDL_Surface *surface;
64 
65  if (strcmp(tmp->name, TEXTURE_FALLBACK_NAME) == 0) {
66  SDL_Rect box;
67 
68  surface = SDL_CreateRGBSurface(get_video_flags(), 20, 20, video_get_bpp(), 0, 0, 0, 0);
69  lineRGBA(surface, 0, 0, surface->w, surface->h, 255, 0, 0, 255);
70  lineRGBA(surface, surface->w, 0, 0, surface->h, 255, 0, 0, 255);
71  box.x = 0;
72  box.y = 0;
73  box.w = surface->w;
74  box.h = surface->h;
75  border_create_color(surface, &box, 1, "950000");
76  } else if (strncmp(tmp->name, "rectangle:", 10) == 0) {
77  int w, h, alpha;
78 
79  alpha = 255;
80 
81  if (sscanf(tmp->name + 10, "%d,%d,%d", &w, &h, &alpha) >= 2) {
82  char *cp;
83 
84  surface = SDL_CreateRGBSurface(get_video_flags(), w, h, video_get_bpp(), 0, 0, 0, 0);
85 
86  if (alpha != 255) {
87  SDL_SetAlpha(surface, SDL_SRCALPHA, alpha);
88  }
89 
90  cp = strchr(tmp->name + 10, ';');
91 
92  if (cp) {
93  SDL_Rect box;
94 
95  box.w = w;
96  box.h = h;
97  text_show(surface, FONT_ARIAL11, cp + 1, 0, 0, COLOR_WHITE, TEXT_MARKUP, &box);
98  }
99  } else {
100  LOG(BUG, "Invalid parameters for rectangle texture: %s", tmp->name);
101  return 0;
102  }
103  } else {
104  LOG(BUG, "Invalid name for software texture: %s", tmp->name);
105  return 0;
106  }
107 
108  texture_data_free(tmp);
109  tmp->surface = SDL_DisplayFormatAlpha(surface);
110  SDL_FreeSurface(surface);
111  } else if (tmp->type == TEXTURE_TYPE_CLIENT) {
112  char path[HUGE_BUF];
113  SDL_Surface *surface;
114 
115  snprintf(path, sizeof(path), "textures/%s.png", tmp->name);
116  surface = IMG_Load_wrapper(path);
117 
118  if (!surface) {
119  LOG(BUG, "Could not load texture %s: %s", path,
120  IMG_GetError());
121  return 0;
122  }
123 
124  SDL_SetColorKey(surface, SDL_SRCCOLORKEY, surface->format->colorkey);
125  texture_data_free(tmp);
126  tmp->surface = SDL_DisplayFormatAlpha(surface);
127  SDL_FreeSurface(surface);
128  }
129 
130  return 1;
131 }
132 
138 static void texture_free(texture_struct *tmp)
139 {
140  efree(tmp->name);
141  texture_data_free(tmp);
142  efree(tmp);
143 }
144 
154 static texture_struct *texture_new(texture_type_t type, const char *name)
155 {
156  texture_struct *tmp;
157 
158  tmp = ecalloc(1, sizeof(*tmp));
159  tmp->name = estrdup(name);
160  tmp->type = type;
161  tmp->last_used = time(NULL);
162 
163  if (!texture_data_new(tmp)) {
164  texture_free(tmp);
165  return NULL;
166  }
167 
168  HASH_ADD_KEYPTR(hh, textures[type], tmp->name, strlen(tmp->name), tmp);
169 
170  return tmp;
171 }
172 
176 void texture_init(void)
177 {
178  texture_type_t type;
179 
180  for (type = 0; type < TEXTURE_TYPE_NUM; type++) {
181  textures[type] = NULL;
182  }
183 
184  texture_new(TEXTURE_TYPE_SOFTWARE, TEXTURE_FALLBACK_NAME);
185 }
186 
190 void texture_deinit(void)
191 {
192  texture_type_t type;
193  texture_struct *curr, *tmp;
194 
195  for (type = 0; type < TEXTURE_TYPE_NUM; type++) {
196 
197  HASH_ITER(hh, textures[type], curr, tmp)
198  {
199  HASH_DEL(textures[type], curr);
200  texture_free(curr);
201  }
202  }
203 }
204 
209 {
210  if (texture == NULL) {
211  return;
212  }
213 
214  HASH_DEL(textures[texture->type], texture);
215  texture_free(texture);
216 }
217 
221 void texture_reload(void)
222 {
223  texture_type_t type;
224  texture_struct *curr, *tmp;
225 
226  for (type = 0; type < TEXTURE_TYPE_NUM; type++) {
227 
228  HASH_ITER(hh, textures[type], curr, tmp)
229  {
230  texture_data_new(curr);
231  }
232  }
233 }
234 
238 void texture_gc(void)
239 {
240  time_t now;
241  struct timeval tv1, tv2;
242  int done;
243  texture_type_t type;
244  texture_struct *curr, *tmp;
245 
246  if (!rndm_chance(TEXTURE_GC_CHANCE)) {
247  return;
248  }
249 
250  now = time(NULL);
251  gettimeofday(&tv1, NULL);
252  done = 0;
253 
254  for (type = 0; type < TEXTURE_TYPE_NUM && !done; type++) {
255 
256  HASH_ITER(hh, textures[type], curr, tmp)
257  {
258  if (curr->surface && now - curr->last_used >= TEXTURE_GC_FREE_TIME) {
259  texture_data_free(curr);
260  }
261 
262  if (gettimeofday(&tv2, NULL) == 0 && tv2.tv_usec - tv1.tv_usec >= TEXTURE_GC_MAX_TIME) {
263  done = 1;
264  break;
265  }
266  }
267  }
268 }
269 
279 texture_struct *texture_get(texture_type_t type, const char *name)
280 {
281  texture_struct *tmp;
282 
283  HASH_FIND_STR(textures[type], name, tmp);
284 
285  if (!tmp) {
286  tmp = texture_new(type, name);
287 
288  if (!tmp) {
289  tmp = texture_get(TEXTURE_TYPE_SOFTWARE, TEXTURE_FALLBACK_NAME);
290  }
291  }
292 
293  return tmp;
294 }
295 
303 SDL_Surface *texture_surface(texture_struct *texture)
304 {
305  texture->last_used = time(NULL);
306 
307  /* No surface, which means that the texture's surface was freed by
308  * the garbage collector, so re-create it. */
309  if (!texture->surface) {
310  /* If we could not load up the texture's surface for some reason,
311  * use the fallback texture surface. */
312  if (!texture_data_new(texture)) {
313  return texture_get(TEXTURE_TYPE_SOFTWARE, TEXTURE_FALLBACK_NAME)->surface;
314  }
315  }
316 
317  return texture->surface;
318 }
SDL_Surface * texture_surface(texture_struct *texture)
Definition: texture.c:303
uint32_t get_video_flags(void)
Definition: video.c:365
void text_show(SDL_Surface *surface, font_struct *font, const char *text, int x, int y, const char *color_notation, uint64_t flags, SDL_Rect *box)
Definition: text.c:1983
texture_type_t
Definition: texture.h:36
static void texture_free(texture_struct *tmp)
Definition: texture.c:138
static texture_struct * textures[TEXTURE_TYPE_NUM]
Definition: texture.c:38
texture_struct * texture_get(texture_type_t type, const char *name)
Definition: texture.c:279
#define TEXT_MARKUP
Definition: text.h:224
void texture_init(void)
Definition: texture.c:176
int video_get_bpp(void)
Definition: video.c:334
static int texture_data_new(texture_struct *tmp)
Definition: texture.c:60
SDL_Surface * IMG_Load_wrapper(const char *file)
Definition: wrapper.c:524
static texture_struct * texture_new(texture_type_t type, const char *name)
Definition: texture.c:154
void texture_delete(texture_struct *texture)
Definition: texture.c:208
void texture_reload(void)
Definition: texture.c:221
static void texture_data_free(texture_struct *tmp)
Definition: texture.c:45
void border_create_color(SDL_Surface *surface, SDL_Rect *coords, int thickness, const char *color_notation)
Definition: sprite.c:1359
void texture_deinit(void)
Definition: texture.c:190
void texture_gc(void)
Definition: texture.c:238
#define COLOR_WHITE
Definition: text.h:289