1 /*
2 * XPilotNG/SDL, an SDL/OpenGL XPilot client.
3 *
4 * Copyright (C) 2003-2004 Juha Lindstr�m <juhal@users.sourceforge.net>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include "xpclient_sdl.h"
22
23 #include "images.h"
24 #include "sdlpaint.h"
25
26 static image_t *images = NULL;
27 static int num_images = 0, max_images = 0;
28 static int first_texture = 0;
29
pow2_ceil(int t)30 static int pow2_ceil(int t)
31 {
32 int r = 1;
33 while (r < t) r <<= 1;
34 return r;
35 }
36
Image_init(image_t * img)37 static int Image_init(image_t *img)
38 {
39 int i, x, y;
40 xp_picture_t pic;
41 RGB_COLOR c;
42
43 if (img->state != IMG_STATE_UNINITIALIZED)
44 return -1;
45
46 if (Picture_init(&pic,
47 img->filename,
48 img->num_frames * (img->rotate ? 1 : -1)) == -1) {
49 img->state = IMG_STATE_ERROR;
50 return -1;
51 }
52 img->name = 0;
53 img->width = pic.width * img->num_frames;
54 img->height = pic.height;
55 img->frame_width = img->width / img->num_frames;
56 img->data_width = pow2_ceil(img->width);
57 img->data_height = pow2_ceil(img->height);
58
59 warn("Loaded image %s: w=%d, h=%d, fw=%d, dw=%d, dh=%d",
60 img->filename, img->width, img->height, img->frame_width,
61 img->data_width, img->data_height);
62
63 img->data = XCALLOC(unsigned int, img->data_width * img->data_height);
64 if (img->data == NULL) {
65 error("Failed to allocate memory for: %s size %dx%d",
66 img->filename, img->data_width, img->data_height);
67 img->state = IMG_STATE_ERROR;
68 return -1;
69 }
70
71 for (i = 0; i < img->num_frames; i++) {
72 for (y = 0; y < img->height; y++) {
73 for (x = 0; x < img->frame_width; x++) {
74 /* the pixels needs to be mirrored over x-axis because
75 * of the used OpenGL projection */
76 c = Picture_get_pixel(&pic, i, x, img->height - y - 1);
77 if (c)
78 c |= 0xff000000; /* alpha */
79 img->data[(x + img->frame_width * i) + (y * img->data_width)]
80 = c;
81 }
82 }
83 }
84
85 glGenTextures(1, &img->name);
86 glBindTexture(GL_TEXTURE_2D, img->name);
87 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img->data_width, img->data_height,
88 0, GL_RGBA, GL_UNSIGNED_BYTE, img->data);
89 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
90 GL_NEAREST);
91 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
92 GL_NEAREST);
93
94 img->state = IMG_STATE_READY;
95 return 0;
96 }
97
Image_free(image_t * img)98 static void Image_free(image_t *img)
99 {
100 XFREE(img->filename);
101 if (img->state == IMG_STATE_READY) {
102 glDeleteTextures(1, &img->name);
103 /* this causes a Segmentation Fault for some reason
104 free(img->data);
105 */
106 }
107 img->state = IMG_STATE_UNINITIALIZED;
108 }
109
Image_get(int ind)110 image_t *Image_get(int ind) {
111
112 image_t *img;
113
114 if (ind >= num_images)
115 return NULL;
116 img = &images[ind];
117 if (img == NULL)
118 return NULL;
119 if (img->state == IMG_STATE_UNINITIALIZED)
120 Image_init(img);
121 if (img->state != IMG_STATE_READY)
122 return NULL;
123 return img;
124 }
125
Image_get_texture(int ind)126 image_t *Image_get_texture(int ind)
127 {
128 return Image_get(first_texture + ind);
129 }
130
Image_use_texture(int ind)131 void Image_use_texture(int ind)
132 {
133 image_t *img = Image_get_texture(ind);
134
135 glEnable(GL_TEXTURE_2D);
136 glEnable(GL_BLEND);
137
138 if (img == NULL) {
139 warn("Texture %d is undefined.\n", ind);
140 return;
141 }
142
143 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
144 glBindTexture(GL_TEXTURE_2D, img->name);
145 glColor4ub(255, 255, 255, 255);
146 }
147
Image_no_texture(void)148 void Image_no_texture(void)
149 {
150 /*glDisable(GL_BLEND);*/
151 glDisable(GL_TEXTURE_2D);
152 }
153
Image_paint(int ind,int x,int y,int frame,int c)154 void Image_paint(int ind, int x, int y, int frame, int c)
155 {
156 Image_paint_area(ind, x, y, frame, NULL, c);
157 }
158
Image_paint_area(int ind,int x,int y,int frame,irec_t * r,int c)159 void Image_paint_area(int ind, int x, int y, int frame, irec_t *r, int c)
160 {
161 image_t *img;
162 irec_t whole;
163 float tx1, ty1, tx2, ty2;
164
165 img = Image_get(ind);
166 if (img == NULL)
167 return;
168
169 if (r == NULL) {
170 whole.x = 0;
171 whole.y = 0;
172 whole.w = img->frame_width;
173 whole.h = img->height;
174 r = &whole;
175 }
176
177 tx1 = ((float)frame * img->frame_width + r->x) / img->data_width;
178 ty1 = ((float)r->y) / img->data_height;
179 tx2 = ((float)frame * img->frame_width + r->x + r->w) / img->data_width;
180 ty2 = ((float)r->y + r->h) / (img->data_height);
181
182 glBindTexture(GL_TEXTURE_2D, img->name);
183 glEnable(GL_TEXTURE_2D);
184 glEnable(GL_BLEND);
185 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
186 set_alphacolor(c);
187
188 glBegin(GL_QUADS);
189 glTexCoord2f(tx1, ty1); glVertex2i(x , y );
190 glTexCoord2f(tx2, ty1); glVertex2i(x + r->w , y );
191 glTexCoord2f(tx2, ty2); glVertex2i(x + r->w , y + r->h );
192 glTexCoord2f(tx1, ty2); glVertex2i(x , y + r->h );
193 glEnd();
194
195 glDisable(GL_BLEND);
196 glDisable(GL_TEXTURE_2D);
197 }
198
Image_paint_rotated(int ind,int x,int y,int dir,int color)199 void Image_paint_rotated(int ind, int x, int y, int dir, int color)
200 {
201 image_t *img;
202 irec_t whole;
203 float tx1, ty1, tx2, ty2;
204
205 img = Image_get(ind);
206 if (img == NULL)
207 return;
208
209 whole.x = 0;
210 whole.y = 0;
211 whole.w = img->frame_width;
212 whole.h = img->height;
213
214 tx1 = 0.0;
215 ty1 = 0.0;
216 tx2 = img->frame_width / (double)img->data_width;
217 ty2 = img->height / (double)img->data_height;
218
219 glPushMatrix();
220 glTranslatef((GLfloat)(x), (GLfloat)(y), 0.0);
221 glRotatef(360.0 * dir / (double)TABLE_SIZE, 0.0, 0.0, 1.0);
222
223 glBindTexture(GL_TEXTURE_2D, img->name);
224 glEnable(GL_TEXTURE_2D);
225 glEnable(GL_BLEND);
226 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
227 /* Linear Filtering */
228 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
229 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
230 set_alphacolor(color);
231
232 glBegin(GL_QUADS);
233 glTexCoord2f(tx1, ty1); glVertex2f( -whole.w / 2.0 , -whole.h / 2.0 );
234 glTexCoord2f(tx2, ty1); glVertex2f( whole.w / 2.0 , -whole.h / 2.0 );
235 glTexCoord2f(tx2, ty2); glVertex2f( whole.w / 2.0 , whole.h / 2.0 );
236 glTexCoord2f(tx1, ty2); glVertex2f( -whole.w / 2.0 , whole.h / 2.0 );
237 glEnd();
238
239 glDisable(GL_BLEND);
240 glDisable(GL_TEXTURE_2D);
241
242 glPopMatrix();
243 }
244
245
Images_init(void)246 int Images_init(void)
247 {
248 #define DEF_IMG(name, count) Bitmap_add(name, count, false);
249
250 DEF_IMG("holder1.ppm", 1);
251 DEF_IMG("holder2.ppm", 1);
252 DEF_IMG("ball_gray.ppm", 1);
253 DEF_IMG("ship_friend.ppm", 1); /* 128 fails in some OpenGL drivers */
254 DEF_IMG("ship_friend.ppm", 1); /* I guess texture gets too wide (4096) */
255 DEF_IMG("ship_enemy.ppm", 1);
256 DEF_IMG("bullet.ppm", -16);
257 DEF_IMG("bullet_blue.ppm", -16);
258 DEF_IMG("base_down.ppm", 1);
259 DEF_IMG("base_left.ppm", 1);
260 DEF_IMG("base_up.ppm", 1);
261 DEF_IMG("base_right.ppm", 1);
262 DEF_IMG("fuelcell.ppm", 1);
263 DEF_IMG("fuel2.ppm", -16);
264 DEF_IMG("allitems.ppm", -30);
265 DEF_IMG("cannon_down.ppm", 1);
266 DEF_IMG("cannon_left.ppm", 1);
267 DEF_IMG("cannon_up.ppm", 1);
268 DEF_IMG("cannon_right.ppm", 1);
269 DEF_IMG("sparks.ppm", -8);
270 DEF_IMG("paused.ppm", -2);
271 DEF_IMG("refuel.ppm", -4);
272 DEF_IMG("wormhole.ppm", 1);
273 DEF_IMG("mine_team.ppm", 1);
274 DEF_IMG("mine_other.ppm", 1);
275 DEF_IMG("concentrator.ppm", 1);
276 DEF_IMG("plus.ppm", 1);
277 DEF_IMG("minus.ppm", 1);
278 DEF_IMG("checkpoint.ppm", -2);
279 DEF_IMG("meter.ppm", -2);
280 DEF_IMG("asteroidconcentrator.ppm", 1);
281 DEF_IMG("shield.ppm", 1);
282 DEF_IMG("acwise_grav.ppm", -6);
283 DEF_IMG("cwise_grav.ppm", -6);
284 DEF_IMG("missile.ppm", 1);
285 DEF_IMG("asteroid.ppm", 1);
286 DEF_IMG("target.ppm", 1);
287 DEF_IMG("huditems.ppm", -30);
288
289 first_texture = num_images;
290
291 #undef DEF_IMG
292 return 0;
293 }
294
295
Images_cleanup(void)296 void Images_cleanup(void)
297 {
298 int i;
299
300 if (images == NULL)
301 return;
302
303 for (i = 0; i < num_images; i++)
304 Image_free(images + i);
305
306 XFREE(images);
307 }
308
309
Bitmap_add(const char * filename,int count,bool scalable)310 int Bitmap_add(const char *filename, int count, bool scalable)
311 {
312 image_t img;
313
314 img.filename = xp_strdup(filename);
315 img.num_frames = ABS(count);
316 img.rotate = count > 1;
317 img.state = IMG_STATE_UNINITIALIZED;
318 STORE(image_t, images, num_images, max_images, img);
319
320 return num_images - 1;
321 }
322
323
324