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, "fscanf: %s\n", strerror(errno));
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, "fscanf: %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 for (i = 0; i < map->height; i++)
90 for (k = 0; k < map->width; k++) {
91 putc(map->bitmap[i * (map->width * 3) + (k * 3) ], fp); /* R */
92 putc(map->bitmap[i * (map->width * 3) + (k * 3) + 1], fp); /* G */
93 putc(map->bitmap[i * (map->width * 3) + (k * 3) + 2], fp); /* B */
100 /* Cut the map into a `width' * `height' size chunk at `x' and `y'. This
101 returns the allocated map bitmap into `ret_bitmap'. The original map
104 bool silc_map_cut(SilcMap map, SilcInt32 x, SilcInt32 y,
105 SilcUInt32 width, SilcUInt32 height,
110 SILC_LOG_DEBUG(("cut"));
113 if (height > map->height - y) {
114 fprintf(stderr, "Requesting too much height: %ld\n", height);
117 if (width > map->width - x) {
118 fprintf(stderr, "Requesting too much width: %ld\n", width);
122 /* Compute coordinates in the bitmap */
123 y = (map->width * 3) * y;
126 /* Allocate new SilcMap context */
127 *ret_map = silc_calloc(1, sizeof(**ret_map));
128 (*ret_map)->width = width;
129 (*ret_map)->height = height;
130 (*ret_map)->maxcolor = map->maxcolor;
131 (*ret_map)->bitsilc_map_size = (width * 3) * height;
132 (*ret_map)->bitmap = silc_malloc((*ret_map)->bitsilc_map_size);
134 /* Copy the requested area */
135 for (i = 0; i < height; i++) {
136 memcpy((*ret_map)->bitmap + (i * width * 3),
137 map->bitmap + y + x, width * 3);
140 y += (map->width * 3);
146 /* Draw a bitmap indicated by `bitmap' of size of `width' * 'height'
147 into the SilcMap context into the coordinates `x' and `y' (the upper left
148 corner of the bitmap will be at x and y). The `bitmap' must be RGB
151 bool silc_map_draw(SilcMap map,
152 SilcInt32 x, SilcInt32 y,
153 const unsigned char *bitmap,
154 SilcUInt32 width, SilcUInt32 height)
159 /* Compute coordinates in the bitmap */
160 y = (map->width * 3) * y;
163 /* Draw the bitmap into the map bitmap */
164 for (i = 0; i < height; i++) {
165 for (k = 0; k < width; k++) {
166 val = bitmap[i * (width * 3) + (k * 3)];
167 map->bitmap[y + x + (k * 3) ] = val; /* R */
169 val = bitmap[i * (width * 3) + (k * 3) + 1];
170 map->bitmap[y + x + (k * 3) + 1] = val; /* G */
172 val = bitmap[i * (width * 3) + (k * 3) + 2];
173 map->bitmap[y + x + (k * 3) + 2] = val; /* B */
177 y += (map->width * 3);
183 /* Same as silc_map_draw but the `bitmap' is a grayscale bitmap
184 and the RGB color information is provided as argument to this function. */
186 bool silc_map_draw_raw(SilcMap map,
187 SilcInt32 x, SilcInt32 y,
188 const unsigned char *bitmap,
189 SilcUInt32 width, SilcUInt32 height,
190 SilcInt16 r, SilcInt16 g, SilcInt16 b)
195 /* Compute coordinates in the bitmap */
196 y = (map->width * 3) * y;
199 /* Draw the bitmap into the map bitmap */
200 for (i = 0; i < height; i++) {
201 for (k = 0; k < width; k++) {
202 val = bitmap[i * width + k];
204 map->bitmap[y + x + (k * 3) ] = r; /* R */
205 map->bitmap[y + x + (k * 3) + 1] = g; /* G */
206 map->bitmap[y + x + (k * 3) + 2] = b; /* B */
211 y += (map->width * 3);
217 /* Draw a straight line between points a and b. The coordinates for the
218 points are provided as arguments. The `width' is the line width in
219 pixels. The RGB color for the line can be provided too. Implements
222 bool silc_map_draw_line(SilcMap map, SilcUInt32 width,
223 SilcInt32 a_x, SilcInt32 a_y,
224 SilcInt32 b_x, SilcInt32 b_y,
225 SilcInt16 r, SilcInt16 g, SilcInt16 b)
227 unsigned char p[3] = { r, g, b };
229 double x, y, slox, sloy;
231 SILC_LOG_DEBUG(("draw_line"));
233 /* Compute the difference of points */
236 if (!xdiff && !ydiff)
240 if (abs(xdiff) > abs(ydiff)) {
241 sloy = (double)ydiff / (double)xdiff;
242 y = a_y + 0.5; /* rounding */
244 for (x = a_x; x <= b_x; x++) {
245 for (i = 0; i < width; i++)
246 silc_map_draw(map, x + i, floor(y), p, 1, 1);
250 for (x = a_x; x >= b_x; x--) {
251 for (i = 0; i < width; i++)
252 silc_map_draw(map, x + i, floor(y), p, 1, 1);
257 slox = (double)xdiff / (double)ydiff;
258 x = a_x + 0.5; /* rounding */
260 for (y = a_y; y <= b_y; y++) {
261 for (i = 0; i < width; i++)
262 silc_map_draw(map, floor(x + i), y, p, 1, 1);
266 for (y = a_y; y >= b_y; y--) {
267 for (i = 0; i < width; i++)
268 silc_map_draw(map, floor(x + i), y, p, 1, 1);
277 /* Print the text string `text' on the bitmap at `x' and `y'. The color
278 for the text can be provided as argument. */
280 bool silc_map_draw_text(SilcMap map, const char *text,
281 SilcInt32 x, SilcInt32 y,
282 SilcInt16 r, SilcInt16 g, SilcInt16 b)
287 SILC_LOG_DEBUG(("draw_text"));
289 /* Write the text. */
291 for (k = 0; k < strlen(text); k++) {
293 silc_map_draw_raw(map, x + w, y,
294 map->font.font[c].data,
295 map->font.font[c].width,
296 map->font.height, r, g, b);
297 w += map->font.font[c].width;
303 /* Draw circle on the bitmap map at `x' and `y'. The center of the
304 circle will be at the `x' and `y'. If the `label' is provided the
305 text will appear with the circle at `lposx' and `lposy' in relation
308 bool silc_map_draw_circle(SilcMap map, SilcInt32 x, SilcInt32 y,
309 SilcInt16 r, SilcInt16 g, SilcInt16 b,
310 const char *label, SilcInt32 lposx, SilcInt32 lposy,
311 SilcInt16 lr, SilcInt16 lg, SilcInt16 lb)
315 SILC_LOG_DEBUG(("draw_circle"));
317 y = y - (silc_map_circle.height / 2);
318 x = x - (silc_map_circle.width / 2);
320 ret = silc_map_draw_raw(map, x, y,
321 silc_map_circle.data,
322 silc_map_circle.width, silc_map_circle.height,
328 ret = silc_map_draw_text(map, label, x + lposx, y - lposy, lr, lg, lb);
333 /* Draw rectangle on the bitmap map at `x' and `y'. The center of the
334 rectangle will be at the `x' and `y'. If the `label' is provided the
335 text will appear with the circle at `lposx' and `lposy' in relation
338 bool silc_map_draw_rectangle(SilcMap map, SilcInt32 x, SilcInt32 y,
339 SilcInt16 r, SilcInt16 g, SilcInt16 b,
341 SilcInt32 lposx, SilcInt32 lposy,
342 SilcInt16 lr, SilcInt16 lg, SilcInt16 lb)
346 SILC_LOG_DEBUG(("draw_rectangle"));
348 y = y - (silc_map_rectangle.height / 2);
349 x = x - (silc_map_rectangle.width / 2);
351 ret = silc_map_draw_raw(map, x, y,
352 silc_map_rectangle.data, silc_map_rectangle.width,
353 silc_map_rectangle.height,
359 ret = silc_map_draw_text(map, label, x + lposx, y - lposy, lr, lg, lb);
364 /* Parses the degree position string. For example, longitude 40 23 10,
365 as in 40 degrees, 23 minutes and 10 seconds east. Negative degree is to
366 West. For latitude positive is north and negative south. */
368 double silc_map_parse_pos(char *pos)
370 double d = 0, m = 0, s = 0;
373 ret = sscanf(pos, "%lf %lf %lf", &d, &m, &s);
375 fprintf(stderr, "Malfromed position string '%s'\n", pos);
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\n", strerror(errno));
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);