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 unsigned char header[80];
36 int ret, retval = TRUE, i;
38 SILC_LOG_DEBUG(("Load PPM '%s'", filename));
40 fd = open(filename, O_RDONLY, 0600);
42 fprintf(stderr, "open: %s: %s\n", strerror(errno), filename);
46 /* Read file header */
47 memset(header, 0, sizeof(header));
48 ret = read(fd, (void *)header, sizeof(header) - 1);
50 fprintf(stderr, "read: %s: %s\n", strerror(errno), filename);
54 /* Read width and height */
55 ret = sscanf(header, "%s %ld %ld %ld\n", type,
56 (unsigned long *)&map->width,
57 (unsigned long *)&map->height,
58 (unsigned long *)&map->maxcolor);
60 fprintf(stderr, "Invalid PPM file");
65 for (i = sizeof(header) - 1; i >= 0; i--)
66 if (header[i] == '\n' || header[i] == ' ')
68 lseek(fd, i + 1, SEEK_SET);
70 /* Read the picture */
71 map->bitmap_size = map->width * 3 * map->height;
72 map->bitmap = silc_malloc(map->bitmap_size);
73 ret = read(fd, map->bitmap, map->bitmap_size);
75 fprintf(stderr, "read: %s\n", strerror(errno));
85 /* Write the map into a bitmap file. */
87 bool silc_map_write_ppm(SilcMap map, const char *filename)
93 SILC_LOG_DEBUG(("Write PPM '%s'", filename));
95 fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0600);
97 fprintf(stderr, "open: %s: %s\n", strerror(errno), filename);
101 /* Write the header */
102 memset(header, 0, sizeof(header));
103 snprintf(header, sizeof(header) - 1, "P6 %ld %ld %ld\n",
104 (unsigned long)map->width,
105 (unsigned long)map->height,
106 (unsigned long)map->maxcolor);
107 write(fd, header, strlen(header));
109 /* Write the bitmap */
110 write(fd, map->bitmap, map->bitmap_size);
116 /* Cut the map into a `width' * `height' size chunk at `x' and `y'. This
117 returns the allocated map bitmap into `ret_bitmap'. The original map
120 bool silc_map_cut(SilcMap map, SilcInt32 x, SilcInt32 y,
121 SilcUInt32 width, SilcUInt32 height,
126 SILC_LOG_DEBUG(("cut"));
129 if (height > map->height - y) {
130 fprintf(stderr, "Requesting too much height: %ld\n",
131 (unsigned long)height);
134 if (width > map->width - x) {
135 fprintf(stderr, "Requesting too much width: %ld\n",
136 (unsigned long)width);
140 /* Compute coordinates in the bitmap */
141 y = (map->width * 3) * y;
144 /* Allocate new SilcMap context */
145 *ret_map = silc_calloc(1, sizeof(**ret_map));
146 (*ret_map)->width = width;
147 (*ret_map)->height = height;
148 (*ret_map)->maxcolor = map->maxcolor;
149 (*ret_map)->bitmap_size = (width * 3) * height;
150 (*ret_map)->bitmap = silc_malloc((*ret_map)->bitmap_size);
152 /* Copy the requested area */
153 for (i = 0; i < height; i++) {
154 memcpy((*ret_map)->bitmap + (i * width * 3),
155 map->bitmap + y + x, width * 3);
158 y += (map->width * 3);
164 /* Draw a bitmap indicated by `bitmap' of size of `width' * 'height'
165 into the SilcMap context into the coordinates `x' and `y' (the upper left
166 corner of the bitmap will be at x and y). The `bitmap' must be RGB
169 bool silc_map_draw(SilcMap map,
170 SilcInt32 x, SilcInt32 y,
171 const unsigned char *bitmap,
172 SilcUInt32 width, SilcUInt32 height)
177 /* Compute coordinates in the bitmap */
178 y = (map->width * 3) * y;
181 /* Draw the bitmap into the map bitmap */
182 for (i = 0; i < height; i++) {
183 for (k = 0; k < width; k++) {
184 val = bitmap[i * (width * 3) + (k * 3)];
185 map->bitmap[y + x + (k * 3) ] = val; /* R */
187 val = bitmap[i * (width * 3) + (k * 3) + 1];
188 map->bitmap[y + x + (k * 3) + 1] = val; /* G */
190 val = bitmap[i * (width * 3) + (k * 3) + 2];
191 map->bitmap[y + x + (k * 3) + 2] = val; /* B */
195 y += (map->width * 3);
201 /* Same as silc_map_draw but the `bitmap' is a grayscale bitmap
202 and the RGB color information is provided as argument to this function. */
204 bool silc_map_draw_raw(SilcMap map,
205 SilcInt32 x, SilcInt32 y,
206 const unsigned char *bitmap,
207 SilcUInt32 width, SilcUInt32 height,
208 SilcInt16 r, SilcInt16 g, SilcInt16 b)
213 /* Compute coordinates in the bitmap */
214 y = (map->width * 3) * y;
217 /* Draw the bitmap into the map bitmap */
218 for (i = 0; i < height; i++) {
219 for (k = 0; k < width; k++) {
220 val = bitmap[i * width + k];
222 map->bitmap[y + x + (k * 3) ] = r; /* R */
223 map->bitmap[y + x + (k * 3) + 1] = g; /* G */
224 map->bitmap[y + x + (k * 3) + 2] = b; /* B */
229 y += (map->width * 3);
235 /* Draw a straight line between points a and b. The coordinates for the
236 points are provided as arguments. The `width' is the line width in
237 pixels. The RGB color for the line can be provided too. Implements
240 bool silc_map_draw_line(SilcMap map, SilcUInt32 width,
241 SilcInt32 a_x, SilcInt32 a_y,
242 SilcInt32 b_x, SilcInt32 b_y,
243 SilcInt16 r, SilcInt16 g, SilcInt16 b)
245 unsigned char p[3] = { r, g, b };
247 double x, y, slox, sloy;
249 SILC_LOG_DEBUG(("draw_line"));
251 /* Compute the difference of points */
254 if (!xdiff && !ydiff)
258 if (abs(xdiff) > abs(ydiff)) {
259 sloy = (double)ydiff / (double)xdiff;
260 y = a_y + 0.5; /* rounding */
262 for (x = a_x; x <= b_x; x++) {
263 for (i = 0; i < width; i++)
264 silc_map_draw(map, x + i, floor(y), p, 1, 1);
268 for (x = a_x; x >= b_x; x--) {
269 for (i = 0; i < width; i++)
270 silc_map_draw(map, x + i, floor(y), p, 1, 1);
275 slox = (double)xdiff / (double)ydiff;
276 x = a_x + 0.5; /* rounding */
278 for (y = a_y; y <= b_y; y++) {
279 for (i = 0; i < width; i++)
280 silc_map_draw(map, floor(x + i), y, p, 1, 1);
284 for (y = a_y; y >= b_y; y--) {
285 for (i = 0; i < width; i++)
286 silc_map_draw(map, floor(x + i), y, p, 1, 1);
295 /* Print the text string `text' on the bitmap at `x' and `y'. The color
296 for the text can be provided as argument. */
298 bool silc_map_draw_text(SilcMap map, const char *text,
299 SilcInt32 x, SilcInt32 y,
300 SilcInt16 r, SilcInt16 g, SilcInt16 b)
305 SILC_LOG_DEBUG(("draw_text"));
307 /* Write the text. */
309 for (k = 0; k < strlen(text); k++) {
311 silc_map_draw_raw(map, x + w, y,
312 map->font.font[c].data,
313 map->font.font[c].width,
314 map->font.height, r, g, b);
315 w += map->font.font[c].width;
321 /* Draw circle on the bitmap map at `x' and `y'. The center of the
322 circle will be at the `x' and `y'. If the `label' is provided the
323 text will appear with the circle at `lposx' and `lposy' in relation
326 bool silc_map_draw_circle(SilcMap map, SilcInt32 x, SilcInt32 y,
327 SilcInt16 r, SilcInt16 g, SilcInt16 b,
328 const char *label, SilcInt32 lposx, SilcInt32 lposy,
329 SilcInt16 lr, SilcInt16 lg, SilcInt16 lb)
333 SILC_LOG_DEBUG(("draw_circle"));
335 y = y - (silc_map_circle.height / 2);
336 x = x - (silc_map_circle.width / 2);
338 ret = silc_map_draw_raw(map, x, y,
339 silc_map_circle.data,
340 silc_map_circle.width, silc_map_circle.height,
346 ret = silc_map_draw_text(map, label, x + lposx, y - lposy, lr, lg, lb);
351 /* Draw rectangle on the bitmap map at `x' and `y'. The center of the
352 rectangle will be at the `x' and `y'. If the `label' is provided the
353 text will appear with the circle at `lposx' and `lposy' in relation
356 bool silc_map_draw_rectangle(SilcMap map, SilcInt32 x, SilcInt32 y,
357 SilcInt16 r, SilcInt16 g, SilcInt16 b,
359 SilcInt32 lposx, SilcInt32 lposy,
360 SilcInt16 lr, SilcInt16 lg, SilcInt16 lb)
364 SILC_LOG_DEBUG(("draw_rectangle"));
366 y = y - (silc_map_rectangle.height / 2);
367 x = x - (silc_map_rectangle.width / 2);
369 ret = silc_map_draw_raw(map, x, y,
370 silc_map_rectangle.data, silc_map_rectangle.width,
371 silc_map_rectangle.height,
377 ret = silc_map_draw_text(map, label, x + lposx, y - lposy, lr, lg, lb);
382 /* Parses the degree position string. For example, longitude 40 23 10,
383 as in 40 degrees, 23 minutes and 10 seconds east. Negative degree is to
384 West. For latitude positive is north and negative south. */
386 double silc_map_parse_pos(char *pos)
388 double d = 0, m = 0, s = 0;
391 ret = sscanf(pos, "%lf %lf %lf", &d, &m, &s);
393 fprintf(stderr, "Malfromed position string '%s'\n", pos);
398 m = (m < 0 ? m : -m);
399 s = (s < 0 ? s : -s);
402 return ((d < 0 ? -1 : d > 0 ? 1 : 0) *
403 abs(d) + (m / 60) + (s / 3600));
406 /* Converts longitude into position in the bitmap */
408 int silc_map_lon2x(SilcMap map, char *longitude)
410 double meridian, aspmul, lon;
412 /* Parse position string */
413 lon = silc_map_parse_pos(longitude);
415 /* Compute "aspect ratio multiplier" to get the position in the map. */
416 meridian = (double)map->width / (double)2.0;
417 aspmul = meridian / 180.0;
419 /* Compute the position in the bitmap map */
420 return (int)(double)(meridian + (lon * aspmul));
423 /* Converts latitude into position in the bitmap */
425 int silc_map_lat2y(SilcMap map, char *latitude)
427 double meridian, aspmul, lat;
429 /* Parse position string */
430 lat = silc_map_parse_pos(latitude);
432 /* Compute "aspect ratio multiplier" to get the position in the map. */
433 meridian = (double)map->height / (double)2.0;
434 aspmul = meridian / 90.0;
436 /* Compute the position in the bitmap map */
437 return (int)(double)(meridian - (lat * aspmul));
440 /* Parses RGB color string. */
442 bool silc_map_parse_color(const char *color,
443 SilcInt16 *r, SilcInt16 *g, SilcInt16 *b)
448 ret = sscanf(color, "%d %d %d", &rr, &gg, &bb);
450 fprintf(stderr, "Invalid color string: %s\n", color);
461 /* Loads a font file. The font file format is the following:
470 If this function is called multiple times the new font replaces the
473 bool silc_map_load_font(SilcMap map, const char *filename)
479 fp = fopen(filename, "r");
481 fprintf(stderr, "fopen: %s: %s\n", strerror(errno), filename);
485 /* Read the font height */
486 i = fscanf(fp, "%d\n", &map->font.height);
490 /* Read the font data */
491 for (i = 0; i < 94; i++) {
492 map->font.font[i].width = fgetc(fp);
494 for (y = 0; y < map->font.height; y++)
495 for (x = 0; x < map->font.font[i].width; x++)
496 map->font.font[i].data[(y * map->font.font[i].width) + x] = fgetc(fp);