Include and link physfs properly.
[tuxanci.git] / src / client / image.c
blobcdd7c9bccd9f7f2ea250e290e8371c87eb443ffc
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <assert.h>
5 #include "main.h"
6 #include "list.h"
7 #include "storage.h"
9 #include "interface.h"
10 #include "image.h"
12 static list_t *listStorage;
14 static bool_t isImageDataInit = FALSE;
16 bool_t image_is_inicialized()
18 return isImageDataInit;
22 * Initialization of global list of images
24 void image_init()
26 assert(interface_is_inicialized() == TRUE);
28 debug("Initializing image database");
30 listStorage = storage_new();
31 isImageDataInit = TRUE;
34 static SDL_Surface *loadImage(const char *filename, int alpha)
36 SDL_Surface *tmp;
37 SDL_Surface *ret;
39 char str[STR_PATH_SIZE];
41 if (isFillPath(filename)) {
42 strcpy(str, filename);
43 } else {
44 sprintf(str, PATH_IMAGE "%s", filename);
47 accessExistFile(str);
49 if ((tmp = IMG_Load(str)) == NULL) {
50 error("SDL: %s", SDL_GetError());
51 return NULL;
54 if ((ret = (alpha) ? SDL_DisplayFormatAlpha(tmp) : SDL_DisplayFormat(tmp)) == NULL) {
55 error("SDL: %s", SDL_GetError());
56 SDL_FreeSurface(tmp);
57 return NULL;
60 SDL_FreeSurface(tmp);
61 return ret;
65 image_t *image_new_sdl(SDL_Surface *surface)
67 image_t *new;
69 assert(surface != NULL);
71 new = malloc(sizeof(image_t));
72 new->image = surface;
73 new->w = surface->w;
74 new->h = surface->h;
76 return new;
79 #ifdef SUPPORT_OPENGL
81 * returns closest bigger power of 2 to i
83 unsigned int closestpoweroftwo(unsigned int i)
85 int p;
86 p=0;
87 while (i) {
88 i = i >> 1;
89 p++;
91 return 1 << (p - 0);
94 /* convert from SDL_Surface to image_t
95 * WARNING: image_new is indestructive to surface, caller is responsible for freeing surface
96 * surface is not needed for image_t after execution of image_new
99 image_t *image_new_opengl(SDL_Surface *surface)
101 image_t *new;
102 Uint32 rmask, gmask, bmask, amask;
103 SDL_Surface *sdl_rgba_surface;
104 unsigned int bpp;
106 /* it is unoptimal to blit to buffer surface before actual loading to opengl texture but it is safer and simpler to implement */
107 /* it is unoptimal to always use RGBA texture */
109 /* we set properties of our buffer sdl_rgba_surface */
110 rmask = 0x000000ff;
111 gmask = 0x0000ff00;
112 bmask = 0x00ff0000;
113 amask = 0xff000000;
114 bpp = 32; /* bits per pixel */
116 assert(surface != NULL);
118 new = malloc(sizeof(image_t));
119 new->w = surface->w;
120 new->h = surface->h;
122 /* because some older hw is really slow when using textures with width and height which is not a power of two */
123 new->tw = closestpoweroftwo(new->w);
124 new->th = closestpoweroftwo(new->h);
126 sdl_rgba_surface = SDL_CreateRGBSurface(SDL_SWSURFACE, new->tw, new->th, bpp, rmask, gmask, bmask, amask);
128 SDL_SetAlpha(surface, 0, SDL_ALPHA_OPAQUE); /* we unset SDL_SRCALPHA to preserve alpha channel of original image */
129 SDL_BlitSurface(surface, 0, sdl_rgba_surface, 0);
131 SDL_LockSurface(sdl_rgba_surface); /* we ensure that we can read pixels from sdl_rgba_surface */
133 GLuint tid;
134 glGenTextures(1, &tid); /* we ask for free texture id */
135 glBindTexture(GL_TEXTURE_2D, tid);
136 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); /* scale linearly when image bigger than texture */
137 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); /* scale linearly when image smalled than texture */
138 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, new->tw, new->th, 0, GL_RGBA, GL_UNSIGNED_BYTE, sdl_rgba_surface->pixels);
139 SDL_UnlockSurface(sdl_rgba_surface);
140 SDL_FreeSurface(sdl_rgba_surface);
142 new->tex_id = tid;
144 SDL_FreeSurface(surface);
146 return new;
148 #endif /* SUPPORT_OPENGL */
150 image_t *image_new(SDL_Surface *surface)
152 #ifdef SUPPORT_OPENGL
153 if (interface_is_use_open_gl()) {
154 return image_new_opengl(surface);
155 } else {
156 return image_new_sdl(surface);
158 #else /* SUPPORT_OPENGL */
159 return image_new_sdl(surface);
160 #endif /* SUPPORT_OPENGL */
163 void image_destroy(image_t *p)
165 assert(p != NULL);
167 #ifndef SUPPORT_OPENGL
168 SDL_FreeSurface((SDL_Surface *) p->image);
169 #else /* SUPPORT_OPENGL */
170 if (interface_is_use_open_gl()) {
171 glDeleteTextures(1, &p->tex_id);
172 } else {
173 SDL_FreeSurface((SDL_Surface *) p->image);
175 #endif /* SUPPORT_OPENGL */
177 free(p);
181 * Adds an image to the global image list
182 * *file - name of the image file
183 * *name - name of the image (is used for searching in the list)
184 * alpha - [0] without alpha channel; [1] with alpha channel
186 image_t *image_add(char *file, int alpha, char *name, char *group)
188 SDL_Surface *surface;
189 image_t *new;
191 assert(file != NULL);
192 assert(name != NULL);
193 assert(group != NULL);
195 surface = loadImage(file, alpha);
196 new = image_new(surface);
198 storage_add(listStorage, group, name, new);
200 debug("Loading image [%s]", file);
202 return new;
206 * Returns pointer to image with name *name in the global image list
208 image_t *image_get(char *group, char *name)
210 assert(group != NULL);
211 assert(name != NULL);
213 return storage_get(listStorage, group, name);
216 void image_del(char *group, char *name)
218 assert(group != NULL);
219 assert(name != NULL);
221 storage_del(listStorage, group, name, image_destroy);
224 void image_del_all_image_in_group(char *group)
226 assert(group != NULL);
228 storage_del_all(listStorage, group, image_destroy);
231 void image_draw_sdl(image_t *p, int x, int y, int px, int py, int w, int h)
233 static SDL_Surface *screen = NULL;
234 SDL_Rect dst_rect, src_rect;
236 if (screen == NULL) {
237 screen = interface_get_screen();
240 dst_rect.x = x;
241 dst_rect.y = y;
243 src_rect.x = px;
244 src_rect.y = py;
245 src_rect.w = w;
246 src_rect.h = h;
248 SDL_BlitSurface(p->image, &src_rect, screen, &dst_rect);
251 #ifdef SUPPORT_OPENGL
253 * Draws image on screen at [x,y], with width w and height h, top-left corner on image is at [px,py]
255 void image_draw_opengl(image_t *image, int x,int y, int px, int py, int w, int h)
257 /* x - coordinate of left border; xx - coordinate of right border
258 * y - coordinate of top border; yy - coordinate of bottom border
259 * t - texture space; d - screen space
261 float t_x, t_y, t_xx, t_yy;
262 float d_x, d_y, d_xx, d_yy;
264 /* screen space */
265 d_x = x;
266 d_y = y;
267 d_xx = x+w;
268 d_yy = y+h;
270 /* texture space (remember that texture space is from 0.0 to 1.0) */
271 t_x = px / (float) image->tw;
272 t_y = py / (float) image->th;
273 t_xx = (px+w) / (float) image->tw;
274 t_yy = (py+h) / (float) image->th;
276 glBindTexture(GL_TEXTURE_2D, image->tex_id);
279 * 2--4
280 * |\ |
281 * | \|
282 * 1--3
284 glBegin(GL_TRIANGLE_STRIP);
285 /* 1 */
286 glTexCoord2f(t_x,t_yy);
287 glVertex2f(d_x, d_yy);
288 /* 2 */
289 glTexCoord2f(t_x, t_y);
290 glVertex2f(d_x, d_y);
291 /* 3 */
292 glTexCoord2f(t_xx, t_yy);
293 glVertex2f(d_xx, d_yy);
294 /* 4 */
295 glTexCoord2f(t_xx,t_y);
296 glVertex2f(d_xx, d_y);
297 glEnd();
299 #endif /* SUPPORT_OPENGL */
301 void image_draw(image_t *image, int x,int y, int px, int py, int w, int h)
303 #ifdef SUPPORT_OPENGL
304 if (interface_is_use_open_gl()) {
305 image_draw_opengl(image, x, y, px, py, w, h);
306 } else {
307 image_draw_sdl(image, x, y, px, py, w, h);
309 #else /* SUPPORT_OPENGL */
310 image_draw_sdl(image, x, y, px, py, w, h);
311 #endif /* SUPPORT_OPENGL */
315 * Frees global image list
317 void image_quit()
319 debug("Shutting down image database");
321 storage_destroy(listStorage, image_destroy);
322 isImageDataInit = FALSE;