5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2003 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 ",
47 type, &map->width, &map->height, &map->maxcolor);
49 fprintf(stderr, "Invalid PPM file");
54 /* Read the picture */
55 map->bitsilc_map_size = map->width * 3 * map->height;
56 map->bitmap = silc_malloc(map->bitsilc_map_size);
57 ret = fread(map->bitmap, map->bitsilc_map_size, 1, fp);
59 fprintf(stderr, "fread: %s\n", strerror(errno));
69 /* Write the map into a bitmap file. */
71 bool silc_map_write_ppm(SilcMap map, const char *filename)
77 SILC_LOG_DEBUG(("Write PPM '%s'", filename));
79 fp = fopen(filename, "w+");
81 fprintf(stderr, "fopen: %s: %s\n", strerror(errno), filename);
85 /* Write the header */
86 fprintf(fp, "P6 %ld %ld %ld\n", map->width, map->height, map->maxcolor);
88 /* Write the bitmap */
89 fwrite(map->bitmap, map->bitsilc_map_size, 1, fp);
95 /* Cut the map into a `width' * `height' size chunk at `x' and `y'. This
96 returns the allocated map bitmap into `ret_bitmap'. The original map
99 bool silc_map_cut(SilcMap map, SilcInt32 x, SilcInt32 y,
100 SilcUInt32 width, SilcUInt32 height,
105 SILC_LOG_DEBUG(("cut"));
108 if (height > map->height - y) {
109 fprintf(stderr, "Requesting too much height: %ld\n", height);
112 if (width > map->width - x) {
113 fprintf(stderr, "Requesting too much width: %ld\n", width);
117 /* Compute coordinates in the bitmap */
118 y = (map->width * 3) * y;
121 /* Allocate new SilcMap context */
122 *ret_map = silc_calloc(1, sizeof(**ret_map));
123 (*ret_map)->width = width;
124 (*ret_map)->height = height;
125 (*ret_map)->maxcolor = map->maxcolor;
126 (*ret_map)->bitsilc_map_size = (width * 3) * height;
127 (*ret_map)->bitmap = silc_malloc((*ret_map)->bitsilc_map_size);
129 /* Copy the requested area */
130 for (i = 0; i < height; i++) {
131 memcpy((*ret_map)->bitmap + (i * width * 3),
132 map->bitmap + y + x, width * 3);
135 y += (map->width * 3);
141 /* Draw a bitmap indicated by `bitmap' of size of `width' * 'height'
142 into the SilcMap context into the coordinates `x' and `y' (the upper left
143 corner of the bitmap will be at x and y). The `bitmap' must be RGB
146 bool silc_map_draw(SilcMap map,
147 SilcInt32 x, SilcInt32 y,
148 const unsigned char *bitmap,
149 SilcUInt32 width, SilcUInt32 height)
154 /* Compute coordinates in the bitmap */
155 y = (map->width * 3) * y;
158 /* Draw the bitmap into the map bitmap */
159 for (i = 0; i < height; i++) {
160 for (k = 0; k < width; k++) {
161 val = bitmap[i * (width * 3) + (k * 3)];
162 map->bitmap[y + x + (k * 3) ] = val; /* R */
164 val = bitmap[i * (width * 3) + (k * 3) + 1];
165 map->bitmap[y + x + (k * 3) + 1] = val; /* G */
167 val = bitmap[i * (width * 3) + (k * 3) + 2];
168 map->bitmap[y + x + (k * 3) + 2] = val; /* B */
172 y += (map->width * 3);
178 /* Same as silc_map_draw but the `bitmap' is a grayscale bitmap
179 and the RGB color information is provided as argument to this function. */
181 bool silc_map_draw_raw(SilcMap map,
182 SilcInt32 x, SilcInt32 y,
183 const unsigned char *bitmap,
184 SilcUInt32 width, SilcUInt32 height,
185 SilcInt16 r, SilcInt16 g, SilcInt16 b)
190 /* Compute coordinates in the bitmap */
191 y = (map->width * 3) * y;
194 /* Draw the bitmap into the map bitmap */
195 for (i = 0; i < height; i++) {
196 for (k = 0; k < width; k++) {
197 val = bitmap[i * width + k];
199 map->bitmap[y + x + (k * 3) ] = r; /* R */
200 map->bitmap[y + x + (k * 3) + 1] = g; /* G */
201 map->bitmap[y + x + (k * 3) + 2] = b; /* B */
206 y += (map->width * 3);
212 /* Draw a straight line between points a and b. The coordinates for the
213 points are provided as arguments. The `width' is the line width in
214 pixels. The RGB color for the line can be provided too. Implements
217 bool silc_map_draw_line(SilcMap map, SilcUInt32 width,
218 SilcInt32 a_x, SilcInt32 a_y,
219 SilcInt32 b_x, SilcInt32 b_y,
220 SilcInt16 r, SilcInt16 g, SilcInt16 b)
222 unsigned char p[3] = { r, g, b };
224 double x, y, slox, sloy;
226 SILC_LOG_DEBUG(("draw_line"));
228 /* Compute the difference of points */
231 if (!xdiff && !ydiff)
235 if (abs(xdiff) > abs(ydiff)) {
236 sloy = (double)ydiff / (double)xdiff;
237 y = a_y + 0.5; /* rounding */
239 for (x = a_x; x <= b_x; x++) {
240 for (i = 0; i < width; i++)
241 silc_map_draw(map, x + i, floor(y), p, 1, 1);
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);
252 slox = (double)xdiff / (double)ydiff;
253 x = a_x + 0.5; /* rounding */
255 for (y = a_y; y <= b_y; y++) {
256 for (i = 0; i < width; i++)
257 silc_map_draw(map, floor(x + i), y, p, 1, 1);
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);
272 /* Print the text string `text' on the bitmap at `x' and `y'. The color
273 for the text can be provided as argument. */
275 bool silc_map_draw_text(SilcMap map, const char *text,
276 SilcInt32 x, SilcInt32 y,
277 SilcInt16 r, SilcInt16 g, SilcInt16 b)
282 SILC_LOG_DEBUG(("draw_text"));
284 /* Write the text. */
286 for (k = 0; k < strlen(text); k++) {
288 silc_map_draw_raw(map, x + w, y,
289 map->font.font[c].data,
290 map->font.font[c].width,
291 map->font.height, r, g, b);
292 w += map->font.font[c].width;
298 /* Draw circle on the bitmap map at `x' and `y'. The center of the
299 circle will be at the `x' and `y'. If the `label' is provided the
300 text will appear with the circle at `lposx' and `lposy' in relation
303 bool silc_map_draw_circle(SilcMap map, SilcInt32 x, SilcInt32 y,
304 SilcInt16 r, SilcInt16 g, SilcInt16 b,
305 const char *label, SilcInt32 lposx, SilcInt32 lposy,
306 SilcInt16 lr, SilcInt16 lg, SilcInt16 lb)
310 SILC_LOG_DEBUG(("draw_circle"));
312 y = y - (silc_map_circle.height / 2);
313 x = x - (silc_map_circle.width / 2);
315 ret = silc_map_draw_raw(map, x, y,
316 silc_map_circle.data,
317 silc_map_circle.width, silc_map_circle.height,
323 ret = silc_map_draw_text(map, label, x + lposx, y - lposy, lr, lg, lb);
328 /* Draw rectangle on the bitmap map at `x' and `y'. The center of the
329 rectangle will be at the `x' and `y'. If the `label' is provided the
330 text will appear with the circle at `lposx' and `lposy' in relation
333 bool silc_map_draw_rectangle(SilcMap map, SilcInt32 x, SilcInt32 y,
334 SilcInt16 r, SilcInt16 g, SilcInt16 b,
336 SilcInt32 lposx, SilcInt32 lposy,
337 SilcInt16 lr, SilcInt16 lg, SilcInt16 lb)
341 SILC_LOG_DEBUG(("draw_rectangle"));
343 y = y - (silc_map_rectangle.height / 2);
344 x = x - (silc_map_rectangle.width / 2);
346 ret = silc_map_draw_raw(map, x, y,
347 silc_map_rectangle.data, silc_map_rectangle.width,
348 silc_map_rectangle.height,
354 ret = silc_map_draw_text(map, label, x + lposx, y - lposy, lr, lg, lb);
359 /* Parses the degree position string. For example, longitude 40 23 10,
360 as in 40 degrees, 23 minutes and 10 seconds east. Negative degree is to
361 West. For latitude positive is north and negative south. */
363 double silc_map_parse_pos(char *pos)
365 double d = 0, m = 0, s = 0;
368 ret = sscanf(pos, "%lf %lf %lf", &d, &m, &s);
370 fprintf(stderr, "Malfromed position string '%s'\n", pos);
375 m = (m < 0 ? m : -m);
376 s = (s < 0 ? s : -s);
379 return ((d < 0 ? -1 : d > 0 ? 1 : 0) *
380 abs(d) + (m / 60) + (s / 3600));
383 /* Converts longitude into position in the bitmap */
385 int silc_map_lon2x(SilcMap map, char *longitude)
387 double meridian, aspmul, lon;
389 /* Parse position string */
390 lon = silc_map_parse_pos(longitude);
392 /* Compute "aspect ratio multiplier" to get the position in the map. */
393 meridian = (double)map->width / (double)2.0;
394 aspmul = meridian / 180.0;
396 /* Compute the position in the bitmap map */
397 return (int)(double)(meridian + (lon * aspmul));
400 /* Converts latitude into position in the bitmap */
402 int silc_map_lat2y(SilcMap map, char *latitude)
404 double meridian, aspmul, lat;
406 /* Parse position string */
407 lat = silc_map_parse_pos(latitude);
409 /* Compute "aspect ratio multiplier" to get the position in the map. */
410 meridian = (double)map->height / (double)2.0;
411 aspmul = meridian / 90.0;
413 /* Compute the position in the bitmap map */
414 return (int)(double)(meridian - (lat * aspmul));
417 /* Parses RGB color string. */
419 bool silc_map_parse_color(const char *color,
420 SilcInt16 *r, SilcInt16 *g, SilcInt16 *b)
425 ret = sscanf(color, "%d %d %d", &rr, &gg, &bb);
427 fprintf(stderr, "Invalid color string: %s\n", color);
438 /* Loads a font file. The font file format is the following:
447 If this function is called multiple times the new font replaces the
450 bool silc_map_load_font(SilcMap map, const char *filename)
456 fp = fopen(filename, "r");
458 fprintf(stderr, "fopen: %s: %s\n", strerror(errno), filename);
462 /* Read the font height */
463 i = fscanf(fp, "%d\n", &map->font.height);
467 /* Read the font data */
468 for (i = 0; i < 94; i++) {
469 map->font.font[i].width = fgetc(fp);
471 for (y = 0; y < map->font.height; y++)
472 for (x = 0; x < map->font.font[i].width; x++)
473 map->font.font[i].data[(y * map->font.font[i].width) + x] = fgetc(fp);