5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2003 - 2004 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
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.
20 #include "silcincludes.h"
21 #include "silcclient.h"
26 /******* Bitmap Routines *****************************************************/
28 /* Load a bitmap file. The file is the map image that is loaded into
29 the SilcMap context. This is no perfect PPM loader. */
31 bool silc_map_load_ppm(SilcMap map, const char *filename)
35 int ret, retval = TRUE;
37 SILC_LOG_DEBUG(("Load PPM '%s'", filename));
39 fp = fopen(filename, "r");
41 fprintf(stderr, "fopen: %s: %s\n", strerror(errno), filename);
45 /* Read width and height */
46 ret = fscanf(fp, "%s %ld %ld %ld ", type,
47 (unsigned long *)&map->width,
48 (unsigned long *)&map->height,
49 (unsigned long *)&map->maxcolor);
51 fprintf(stderr, "Invalid PPM file");
56 /* Read the picture */
57 map->bitmap_size = map->width * 3 * map->height;
58 map->bitmap = silc_malloc(map->bitmap_size);
59 ret = fread(map->bitmap, map->bitmap_size, 1, fp);
61 fprintf(stderr, "fread: %s\n", strerror(errno));
71 /* Write the map into a bitmap file. */
73 bool silc_map_write_ppm(SilcMap map, const char *filename)
78 SILC_LOG_DEBUG(("Write PPM '%s'", filename));
80 fp = fopen(filename, "w+");
82 fprintf(stderr, "fopen: %s: %s\n", strerror(errno), filename);
86 /* Write the header */
87 fprintf(fp, "P6 %ld %ld %ld\n",
88 (unsigned long)map->width,
89 (unsigned long)map->height,
90 (unsigned long)map->maxcolor);
92 /* Write the bitmap */
93 fwrite(map->bitmap, map->bitmap_size, 1, fp);
99 /* Cut the map into a `width' * `height' size chunk at `x' and `y'. This
100 returns the allocated map bitmap into `ret_bitmap'. The original map
103 bool silc_map_cut(SilcMap map, SilcInt32 x, SilcInt32 y,
104 SilcUInt32 width, SilcUInt32 height,
109 SILC_LOG_DEBUG(("cut"));
112 if (height > map->height - y) {
113 fprintf(stderr, "Requesting too much height: %ld\n",
114 (unsigned long)height);
117 if (width > map->width - x) {
118 fprintf(stderr, "Requesting too much width: %ld\n",
119 (unsigned long)width);
123 /* Compute coordinates in the bitmap */
124 y = (map->width * 3) * y;
127 /* Allocate new SilcMap context */
128 *ret_map = silc_calloc(1, sizeof(**ret_map));
129 (*ret_map)->width = width;
130 (*ret_map)->height = height;
131 (*ret_map)->maxcolor = map->maxcolor;
132 (*ret_map)->bitmap_size = (width * 3) * height;
133 (*ret_map)->bitmap = silc_malloc((*ret_map)->bitmap_size);
135 /* Copy the requested area */
136 for (i = 0; i < height; i++) {
137 memcpy((*ret_map)->bitmap + (i * width * 3),
138 map->bitmap + y + x, width * 3);
141 y += (map->width * 3);
147 /* Draw a bitmap indicated by `bitmap' of size of `width' * 'height'
148 into the SilcMap context into the coordinates `x' and `y' (the upper left
149 corner of the bitmap will be at x and y). The `bitmap' must be RGB
152 bool silc_map_draw(SilcMap map,
153 SilcInt32 x, SilcInt32 y,
154 const unsigned char *bitmap,
155 SilcUInt32 width, SilcUInt32 height)
160 /* Compute coordinates in the bitmap */
161 y = (map->width * 3) * y;
164 /* Draw the bitmap into the map bitmap */
165 for (i = 0; i < height; i++) {
166 for (k = 0; k < width; k++) {
167 val = bitmap[i * (width * 3) + (k * 3)];
168 map->bitmap[y + x + (k * 3) ] = val; /* R */
170 val = bitmap[i * (width * 3) + (k * 3) + 1];
171 map->bitmap[y + x + (k * 3) + 1] = val; /* G */
173 val = bitmap[i * (width * 3) + (k * 3) + 2];
174 map->bitmap[y + x + (k * 3) + 2] = val; /* B */
178 y += (map->width * 3);
184 /* Same as silc_map_draw but the `bitmap' is a grayscale bitmap
185 and the RGB color information is provided as argument to this function. */
187 bool silc_map_draw_raw(SilcMap map,
188 SilcInt32 x, SilcInt32 y,
189 const unsigned char *bitmap,
190 SilcUInt32 width, SilcUInt32 height,
191 SilcInt16 r, SilcInt16 g, SilcInt16 b)
196 /* Compute coordinates in the bitmap */
197 y = (map->width * 3) * y;
200 /* Draw the bitmap into the map bitmap */
201 for (i = 0; i < height; i++) {
202 for (k = 0; k < width; k++) {
203 val = bitmap[i * width + k];
205 map->bitmap[y + x + (k * 3) ] = r; /* R */
206 map->bitmap[y + x + (k * 3) + 1] = g; /* G */
207 map->bitmap[y + x + (k * 3) + 2] = b; /* B */
212 y += (map->width * 3);
218 /* Draw a straight line between points a and b. The coordinates for the
219 points are provided as arguments. The `width' is the line width in
220 pixels. The RGB color for the line can be provided too. Implements
223 bool silc_map_draw_line(SilcMap map, SilcUInt32 width,
224 SilcInt32 a_x, SilcInt32 a_y,
225 SilcInt32 b_x, SilcInt32 b_y,
226 SilcInt16 r, SilcInt16 g, SilcInt16 b)
228 unsigned char p[3] = { r, g, b };
230 double x, y, slox, sloy;
232 SILC_LOG_DEBUG(("draw_line"));
234 /* Compute the difference of points */
237 if (!xdiff && !ydiff)
241 if (abs(xdiff) > abs(ydiff)) {
242 sloy = (double)ydiff / (double)xdiff;
243 y = a_y + 0.5; /* rounding */
245 for (x = a_x; x <= b_x; x++) {
246 for (i = 0; i < width; i++)
247 silc_map_draw(map, x + i, floor(y), p, 1, 1);
251 for (x = a_x; x >= b_x; x--) {
252 for (i = 0; i < width; i++)
253 silc_map_draw(map, x + i, floor(y), p, 1, 1);
258 slox = (double)xdiff / (double)ydiff;
259 x = a_x + 0.5; /* rounding */
261 for (y = a_y; y <= b_y; y++) {
262 for (i = 0; i < width; i++)
263 silc_map_draw(map, floor(x + i), y, p, 1, 1);
267 for (y = a_y; y >= b_y; y--) {
268 for (i = 0; i < width; i++)
269 silc_map_draw(map, floor(x + i), y, p, 1, 1);
278 /* Print the text string `text' on the bitmap at `x' and `y'. The color
279 for the text can be provided as argument. */
281 bool silc_map_draw_text(SilcMap map, const char *text,
282 SilcInt32 x, SilcInt32 y,
283 SilcInt16 r, SilcInt16 g, SilcInt16 b)
288 SILC_LOG_DEBUG(("draw_text"));
290 /* Write the text. */
292 for (k = 0; k < strlen(text); k++) {
294 silc_map_draw_raw(map, x + w, y,
295 map->font.font[c].data,
296 map->font.font[c].width,
297 map->font.height, r, g, b);
298 w += map->font.font[c].width;
304 /* Draw circle on the bitmap map at `x' and `y'. The center of the
305 circle will be at the `x' and `y'. If the `label' is provided the
306 text will appear with the circle at `lposx' and `lposy' in relation
309 bool silc_map_draw_circle(SilcMap map, SilcInt32 x, SilcInt32 y,
310 SilcInt16 r, SilcInt16 g, SilcInt16 b,
311 const char *label, SilcInt32 lposx, SilcInt32 lposy,
312 SilcInt16 lr, SilcInt16 lg, SilcInt16 lb)
316 SILC_LOG_DEBUG(("draw_circle"));
318 y = y - (silc_map_circle.height / 2);
319 x = x - (silc_map_circle.width / 2);
321 ret = silc_map_draw_raw(map, x, y,
322 silc_map_circle.data,
323 silc_map_circle.width, silc_map_circle.height,
329 ret = silc_map_draw_text(map, label, x + lposx, y - lposy, lr, lg, lb);
334 /* Draw rectangle on the bitmap map at `x' and `y'. The center of the
335 rectangle will be at the `x' and `y'. If the `label' is provided the
336 text will appear with the circle at `lposx' and `lposy' in relation
339 bool silc_map_draw_rectangle(SilcMap map, SilcInt32 x, SilcInt32 y,
340 SilcInt16 r, SilcInt16 g, SilcInt16 b,
342 SilcInt32 lposx, SilcInt32 lposy,
343 SilcInt16 lr, SilcInt16 lg, SilcInt16 lb)
347 SILC_LOG_DEBUG(("draw_rectangle"));
349 y = y - (silc_map_rectangle.height / 2);
350 x = x - (silc_map_rectangle.width / 2);
352 ret = silc_map_draw_raw(map, x, y,
353 silc_map_rectangle.data, silc_map_rectangle.width,
354 silc_map_rectangle.height,
360 ret = silc_map_draw_text(map, label, x + lposx, y - lposy, lr, lg, lb);
365 /* Parses the degree position string. For example, longitude 40 23 10,
366 as in 40 degrees, 23 minutes and 10 seconds east. Negative degree is to
367 West. For latitude positive is north and negative south. */
369 double silc_map_parse_pos(char *pos)
371 double d = 0, m = 0, s = 0;
374 ret = sscanf(pos, "%lf %lf %lf", &d, &m, &s);
376 fprintf(stderr, "Malfromed position string '%s'\n", pos);
381 m = (m < 0 ? m : -m);
382 s = (s < 0 ? s : -s);
385 return ((d < 0 ? -1 : d > 0 ? 1 : 0) *
386 abs(d) + (m / 60) + (s / 3600));
389 /* Converts longitude into position in the bitmap */
391 int silc_map_lon2x(SilcMap map, char *longitude)
393 double meridian, aspmul, lon;
395 /* Parse position string */
396 lon = silc_map_parse_pos(longitude);
398 /* Compute "aspect ratio multiplier" to get the position in the map. */
399 meridian = (double)map->width / (double)2.0;
400 aspmul = meridian / 180.0;
402 /* Compute the position in the bitmap map */
403 return (int)(double)(meridian + (lon * aspmul));
406 /* Converts latitude into position in the bitmap */
408 int silc_map_lat2y(SilcMap map, char *latitude)
410 double meridian, aspmul, lat;
412 /* Parse position string */
413 lat = silc_map_parse_pos(latitude);
415 /* Compute "aspect ratio multiplier" to get the position in the map. */
416 meridian = (double)map->height / (double)2.0;
417 aspmul = meridian / 90.0;
419 /* Compute the position in the bitmap map */
420 return (int)(double)(meridian - (lat * aspmul));
423 /* Parses RGB color string. */
425 bool silc_map_parse_color(const char *color,
426 SilcInt16 *r, SilcInt16 *g, SilcInt16 *b)
431 ret = sscanf(color, "%d %d %d", &rr, &gg, &bb);
433 fprintf(stderr, "Invalid color string: %s\n", color);
444 /* Loads a font file. The font file format is the following:
453 If this function is called multiple times the new font replaces the
456 bool silc_map_load_font(SilcMap map, const char *filename)
462 fp = fopen(filename, "r");
464 fprintf(stderr, "fopen: %s: %s\n", strerror(errno), filename);
468 /* Read the font height */
469 i = fscanf(fp, "%d\n", &map->font.height);
473 /* Read the font data */
474 for (i = 0; i < 94; i++) {
475 map->font.font[i].width = fgetc(fp);
477 for (y = 0; y < map->font.height; y++)
478 for (x = 0; x < map->font.font[i].width; x++)
479 map->font.font[i].data[(y * map->font.font[i].width) + x] = fgetc(fp);