diff --git a/tools/map/Makefile b/tools/map/Makefile new file mode 100755 index 000000000..7436406ef --- /dev/null +++ b/tools/map/Makefile @@ -0,0 +1,34 @@ +######################################################################## +# This is a GNU makefile - tested on CYGWIN and Linux +# +# You may need to compile or install libpng and/or zlib before +# compiling this. +# + +TARGET = mapgen +# These flags are needed to get it to compile with libpngX.dll on CYGWIN +CYGWINFLAGS = -DPNG_USE_DLL +#CYGWINFLAGS = +PNGFLAGS = -I. +SDLFLAGS = $(shell sdl-config --cflags) + +CC = gcc +CFLAGS = -W -Wall -O0 # -g +LIBS = -L/usr/local/lib -lpng -lm -lSDL_ttf -lSDL_image +LDFLAGS = $(shell sdl-config --libs) + +BINS = $(TARGET) $(TARGET).exe +OBJS = mapgen.o alist.o scriptlib.o stringbank.o unicode.o sdlpngdrv.o SDL_gfxPrimitives.o + +.SUFFIXES: .c .o + +.c.o: + $(CC) -c $(CFLAGS) -o $@ $*.c $(PNGFLAGS) $(SDLFLAGS) $(CYGWINFLAGS) + +all: $(TARGET) + +$(TARGET): $(OBJS) + $(CC) -o $(TARGET) $(OBJS) $(LIBS) $(LDFLAGS) + +clean: + rm -f $(BINS) *.o diff --git a/tools/map/SDL_gfxPrimitives.c b/tools/map/SDL_gfxPrimitives.c new file mode 100755 index 000000000..c6434e305 --- /dev/null +++ b/tools/map/SDL_gfxPrimitives.c @@ -0,0 +1,3513 @@ +/* + + SDL_gfxPrimitives - Graphics primitives for SDL surfaces + + LGPL (c) A. Schiffler + + 2006-02-01 - Alex Volkov + Fixed bugs in _putPixelAlpha() + Removed font/char ops + +*/ + +#include +#include +#include +#include + +#include "SDL_gfxPrimitives.h" + +/* -===================- */ + +/* ----- Defines for pixel clipping tests */ + +#define clip_xmin(surface) surface->clip_rect.x +#define clip_xmax(surface) surface->clip_rect.x+surface->clip_rect.w-1 +#define clip_ymin(surface) surface->clip_rect.y +#define clip_ymax(surface) surface->clip_rect.y+surface->clip_rect.h-1 + +/* ----- Pixel - fast, no blending, no locking, clipping */ + +int fastPixelColorNolock(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color) +{ + int bpp; + Uint8 *p; + + /* + * Honor clipping setup at pixel level + */ + if ((x >= clip_xmin(dst)) && (x <= clip_xmax(dst)) && (y >= clip_ymin(dst)) && (y <= clip_ymax(dst))) { + + /* + * Get destination format + */ + bpp = dst->format->BytesPerPixel; + p = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp; + switch (bpp) { + case 1: + *p = color; + break; + case 2: + *(Uint16 *) p = color; + break; + case 3: + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { + p[0] = (color >> 16) & 0xff; + p[1] = (color >> 8) & 0xff; + p[2] = color & 0xff; + } else { + p[0] = color & 0xff; + p[1] = (color >> 8) & 0xff; + p[2] = (color >> 16) & 0xff; + } + break; + case 4: + *(Uint32 *) p = color; + break; + } /* switch */ + + + } + + return (0); +} + +/* ----- Pixel - fast, no blending, no locking, no clipping */ + +/* (faster but dangerous, make sure we stay in surface bounds) */ + +int fastPixelColorNolockNoclip(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color) +{ + int bpp; + Uint8 *p; + + /* + * Get destination format + */ + bpp = dst->format->BytesPerPixel; + p = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp; + switch (bpp) { + case 1: + *p = color; + break; + case 2: + *(Uint16 *) p = color; + break; + case 3: + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { + p[0] = (color >> 16) & 0xff; + p[1] = (color >> 8) & 0xff; + p[2] = color & 0xff; + } else { + p[0] = color & 0xff; + p[1] = (color >> 8) & 0xff; + p[2] = (color >> 16) & 0xff; + } + break; + case 4: + *(Uint32 *) p = color; + break; + } /* switch */ + + return (0); +} + +/* ----- Pixel - fast, no blending, locking, clipping */ + +int fastPixelColor(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color) +{ + int result; + + /* + * Lock the surface + */ + if (SDL_MUSTLOCK(dst)) { + if (SDL_LockSurface(dst) < 0) { + return (-1); + } + } + + result = fastPixelColorNolock(dst, x, y, color); + + /* + * Unlock surface + */ + if (SDL_MUSTLOCK(dst)) { + SDL_UnlockSurface(dst); + } + + return (result); +} + +/* ----- Pixel - fast, no blending, locking, RGB input */ + +int fastPixelRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + Uint32 color; + + /* + * Setup color + */ + color = SDL_MapRGBA(dst->format, r, g, b, a); + + /* + * Draw + */ + return (fastPixelColor(dst, x, y, color)); + +} + +/* ----- Pixel - fast, no blending, no locking RGB input */ + +int fastPixelRGBANolock(SDL_Surface * dst, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + Uint32 color; + + /* + * Setup color + */ + color = SDL_MapRGBA(dst->format, r, g, b, a); + + /* + * Draw + */ + return (fastPixelColorNolock(dst, x, y, color)); +} + +/* PutPixel routine with alpha blending, input color in destination format */ + +/* New, faster routine - default blending pixel */ + +int _putPixelAlpha(SDL_Surface * surface, Sint16 x, Sint16 y, Uint32 color, Uint8 alpha) +{ + Uint32 Rmask = surface->format->Rmask, Gmask = + surface->format->Gmask, Bmask = surface->format->Bmask, Amask = surface->format->Amask; + Uint32 R, G, B, A = 0; + + if (x >= clip_xmin(surface) && x <= clip_xmax(surface) + && y >= clip_ymin(surface) && y <= clip_ymax(surface)) { + + switch (surface->format->BytesPerPixel) { + case 1:{ /* Assuming 8-bpp */ + if (alpha == 255) { + *((Uint8 *) surface->pixels + y * surface->pitch + x) = color; + } else { + Uint8 *pixel = (Uint8 *) surface->pixels + y * surface->pitch + x; + + Uint8 dR = surface->format->palette->colors[*pixel].r; + Uint8 dG = surface->format->palette->colors[*pixel].g; + Uint8 dB = surface->format->palette->colors[*pixel].b; + Uint8 sR = surface->format->palette->colors[color].r; + Uint8 sG = surface->format->palette->colors[color].g; + Uint8 sB = surface->format->palette->colors[color].b; + + dR = dR + ((sR - dR) * alpha >> 8); + dG = dG + ((sG - dG) * alpha >> 8); + dB = dB + ((sB - dB) * alpha >> 8); + + *pixel = SDL_MapRGB(surface->format, dR, dG, dB); + } + } + break; + + case 2:{ /* Probably 15-bpp or 16-bpp */ + if (alpha == 255) { + *((Uint16 *) surface->pixels + y * surface->pitch / 2 + x) = color; + } else { + Uint16 *pixel = (Uint16 *) surface->pixels + y * surface->pitch / 2 + x; + Uint32 dc = *pixel; + + R = ((dc & Rmask) + (((color & Rmask) - (dc & Rmask)) * alpha >> 8)) & Rmask; + G = ((dc & Gmask) + (((color & Gmask) - (dc & Gmask)) * alpha >> 8)) & Gmask; + B = ((dc & Bmask) + (((color & Bmask) - (dc & Bmask)) * alpha >> 8)) & Bmask; + if (Amask) + A = ((dc & Amask) + (((color & Amask) - (dc & Amask)) * alpha >> 8)) & Amask; + + *pixel = R | G | B | A; + } + } + break; + + case 3:{ /* Slow 24-bpp mode, usually not used */ + Uint8 *pix = (Uint8 *) surface->pixels + y * surface->pitch + x * 3; + Uint8 rshift8 = surface->format->Rshift / 8; + Uint8 gshift8 = surface->format->Gshift / 8; + Uint8 bshift8 = surface->format->Bshift / 8; + + if (alpha == 255) { + *(pix + rshift8) = color >> surface->format->Rshift; + *(pix + gshift8) = color >> surface->format->Gshift; + *(pix + bshift8) = color >> surface->format->Bshift; + } else { + Uint8 dR, dG, dB; + Uint8 sR, sG, sB; + + pix = (Uint8 *) surface->pixels + y * surface->pitch + x * 3; + + dR = *((pix) + rshift8); + dG = *((pix) + gshift8); + dB = *((pix) + bshift8); + + sR = (color >> surface->format->Rshift) & 0xff; + sG = (color >> surface->format->Gshift) & 0xff; + sB = (color >> surface->format->Bshift) & 0xff; + + dR = dR + ((sR - dR) * alpha >> 8); + dG = dG + ((sG - dG) * alpha >> 8); + dB = dB + ((sB - dB) * alpha >> 8); + + *((pix) + rshift8) = dR; + *((pix) + gshift8) = dG; + *((pix) + bshift8) = dB; + } + } + break; + + case 4:{ /* Probably 32-bpp */ + Uint32 *pixel = (Uint32 *)((Uint8 *) surface->pixels + y * surface->pitch) + x; + + if (alpha == 255) { + *pixel = color; + } else { + Uint32 dc = *pixel; + + R = ((dc & Rmask) + (((color & Rmask) - (dc & Rmask)) * alpha >> 8)) & Rmask; + G = ((dc & Gmask) + (((color & Gmask) - (dc & Gmask)) * alpha >> 8)) & Gmask; + B = ((dc & Bmask) + (((color & Bmask) - (dc & Bmask)) * alpha >> 8)) & Bmask; + if (Amask) + A = ((dc & Amask) + (((color & Amask) - (dc & Amask)) * alpha >> 8)) & Amask; + + *pixel = R | G | B | A; + } + } + break; + } + } + + return (0); +} + +/* ----- Pixel - pixel draw with blending enabled if a<255 */ + +int pixelColor(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color) +{ + Uint8 alpha; + Uint32 mcolor; + int result = 0; + + /* + * Lock the surface + */ + if (SDL_MUSTLOCK(dst)) { + if (SDL_LockSurface(dst) < 0) { + return (-1); + } + } + + /* + * Setup color + */ + alpha = color & 0x000000ff; + mcolor = + SDL_MapRGBA(dst->format, (color & 0xff000000) >> 24, + (color & 0x00ff0000) >> 16, (color & 0x0000ff00) >> 8, alpha); + + /* + * Draw + */ + result = _putPixelAlpha(dst, x, y, mcolor, alpha); + + /* + * Unlock the surface + */ + if (SDL_MUSTLOCK(dst)) { + SDL_UnlockSurface(dst); + } + + return (result); +} + +int pixelColorNolock(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color) +{ + Uint8 alpha; + Uint32 mcolor; + int result = 0; + + /* + * Setup color + */ + alpha = color & 0x000000ff; + mcolor = + SDL_MapRGBA(dst->format, (color & 0xff000000) >> 24, + (color & 0x00ff0000) >> 16, (color & 0x0000ff00) >> 8, alpha); + + /* + * Draw + */ + result = _putPixelAlpha(dst, x, y, mcolor, alpha); + + return (result); +} + + +/* Filled rectangle with alpha blending, color in destination format */ + +int _filledRectAlpha(SDL_Surface * surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, Uint8 alpha) +{ + Uint32 Rmask = surface->format->Rmask, Gmask = + surface->format->Gmask, Bmask = surface->format->Bmask, Amask = surface->format->Amask; + Uint32 R, G, B, A = 0; + Sint16 x, y; + + switch (surface->format->BytesPerPixel) { + case 1:{ /* Assuming 8-bpp */ + Uint8 *row, *pixel; + Uint8 dR, dG, dB; + + Uint8 sR = surface->format->palette->colors[color].r; + Uint8 sG = surface->format->palette->colors[color].g; + Uint8 sB = surface->format->palette->colors[color].b; + + for (y = y1; y <= y2; y++) { + row = (Uint8 *) surface->pixels + y * surface->pitch; + for (x = x1; x <= x2; x++) { + pixel = row + x; + + dR = surface->format->palette->colors[*pixel].r; + dG = surface->format->palette->colors[*pixel].g; + dB = surface->format->palette->colors[*pixel].b; + + dR = dR + ((sR - dR) * alpha >> 8); + dG = dG + ((sG - dG) * alpha >> 8); + dB = dB + ((sB - dB) * alpha >> 8); + + *pixel = SDL_MapRGB(surface->format, dR, dG, dB); + } + } + } + break; + + case 2:{ /* Probably 15-bpp or 16-bpp */ + Uint16 *row, *pixel; + Uint32 dR = (color & Rmask), dG = (color & Gmask), dB = (color & Bmask), dA = (color & Amask); + + for (y = y1; y <= y2; y++) { + row = (Uint16 *) surface->pixels + y * surface->pitch / 2; + for (x = x1; x <= x2; x++) { + pixel = row + x; + + R = ((*pixel & Rmask) + ((dR - (*pixel & Rmask)) * alpha >> 8)) & Rmask; + G = ((*pixel & Gmask) + ((dG - (*pixel & Gmask)) * alpha >> 8)) & Gmask; + B = ((*pixel & Bmask) + ((dB - (*pixel & Bmask)) * alpha >> 8)) & Bmask; + if (Amask) + A = ((*pixel & Amask) + ((dA - (*pixel & Amask)) * alpha >> 8)) & Amask; + + *pixel = R | G | B | A; + } + } + } + break; + + case 3:{ /* Slow 24-bpp mode, usually not used */ + Uint8 *row, *pix; + Uint8 dR, dG, dB, dA; + Uint8 rshift8 = surface->format->Rshift / 8; + Uint8 gshift8 = surface->format->Gshift / 8; + Uint8 bshift8 = surface->format->Bshift / 8; + Uint8 ashift8 = surface->format->Ashift / 8; + + Uint8 sR = (color >> surface->format->Rshift) & 0xff; + Uint8 sG = (color >> surface->format->Gshift) & 0xff; + Uint8 sB = (color >> surface->format->Bshift) & 0xff; + Uint8 sA = (color >> surface->format->Ashift) & 0xff; + + for (y = y1; y <= y2; y++) { + row = (Uint8 *) surface->pixels + y * surface->pitch; + for (x = x1; x <= x2; x++) { + pix = row + x * 3; + + dR = *((pix) + rshift8); + dG = *((pix) + gshift8); + dB = *((pix) + bshift8); + dA = *((pix) + ashift8); + + dR = dR + ((sR - dR) * alpha >> 8); + dG = dG + ((sG - dG) * alpha >> 8); + dB = dB + ((sB - dB) * alpha >> 8); + dA = dA + ((sA - dA) * alpha >> 8); + + *((pix) + rshift8) = dR; + *((pix) + gshift8) = dG; + *((pix) + bshift8) = dB; + *((pix) + ashift8) = dA; + } + } + + } + break; + + case 4:{ /* Probably 32-bpp */ + Uint32 *row, *pixel; + Uint32 dR = (color & Rmask), dG = (color & Gmask), dB = (color & Bmask), dA = (color & Amask); + + for (y = y1; y <= y2; y++) { + row = (Uint32 *) surface->pixels + y * surface->pitch / 4; + for (x = x1; x <= x2; x++) { + pixel = row + x; + + R = ((*pixel & Rmask) + ((dR - (*pixel & Rmask)) * alpha >> 8)) & Rmask; + G = ((*pixel & Gmask) + ((dG - (*pixel & Gmask)) * alpha >> 8)) & Gmask; + B = ((*pixel & Bmask) + ((dB - (*pixel & Bmask)) * alpha >> 8)) & Bmask; + if (Amask) + A = ((*pixel & Amask) + ((dA - (*pixel & Amask)) * alpha >> 8)) & Amask; + + *pixel = R | G | B | A; + } + } + } + break; + } + + return (0); +} + +/* Draw rectangle with alpha enabled from RGBA color. */ + +int filledRectAlpha(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color) +{ + Uint8 alpha; + Uint32 mcolor; + int result = 0; + + /* + * Lock the surface + */ + if (SDL_MUSTLOCK(dst)) { + if (SDL_LockSurface(dst) < 0) { + return (-1); + } + } + + /* + * Setup color + */ + alpha = color & 0x000000ff; + mcolor = + SDL_MapRGBA(dst->format, (color & 0xff000000) >> 24, + (color & 0x00ff0000) >> 16, (color & 0x0000ff00) >> 8, alpha); + + /* + * Draw + */ + result = _filledRectAlpha(dst, x1, y1, x2, y2, mcolor, alpha); + + /* + * Unlock the surface + */ + if (SDL_MUSTLOCK(dst)) { + SDL_UnlockSurface(dst); + } + + return (result); +} + +/* Draw horizontal line with alpha enabled from RGBA color */ + +int HLineAlpha(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color) +{ + return (filledRectAlpha(dst, x1, y, x2, y, color)); +} + + +/* Draw vertical line with alpha enabled from RGBA color */ + +int VLineAlpha(SDL_Surface * dst, Sint16 x, Sint16 y1, Sint16 y2, Uint32 color) +{ + return (filledRectAlpha(dst, x, y1, x, y2, color)); +} + + +/* Pixel - using alpha weight on color for AA-drawing */ + +int pixelColorWeight(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color, Uint32 weight) +{ + Uint32 a; + + /* + * Get alpha + */ + a = (color & (Uint32) 0x000000ff); + + /* + * Modify Alpha by weight + */ + a = ((a * weight) >> 8); + + return (pixelColor(dst, x, y, (color & (Uint32) 0xffffff00) | (Uint32) a)); +} + +/* Pixel - using alpha weight on color for AA-drawing - no locking */ + +int pixelColorWeightNolock(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color, Uint32 weight) +{ + Uint32 a; + + /* + * Get alpha + */ + a = (color & (Uint32) 0x000000ff); + + /* + * Modify Alpha by weight + */ + a = ((a * weight) >> 8); + + return (pixelColorNolock(dst, x, y, (color & (Uint32) 0xffffff00) | (Uint32) a)); +} + +int pixelRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + Uint32 color; + + /* + * Check Alpha + */ + if (a == 255) { + /* + * No alpha blending required + */ + /* + * Setup color + */ + color = SDL_MapRGBA(dst->format, r, g, b, a); + /* + * Draw + */ + return (fastPixelColor(dst, x, y, color)); + } else { + /* + * Alpha blending required + */ + /* + * Draw + */ + return (pixelColor(dst, x, y, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); + } +} + +/* ----- Horizontal line */ + +/* Just store color including alpha, no blending */ + +int hlineColorStore(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color) +{ + Sint16 left, right, top, bottom; + Uint8 *pixel, *pixellast; + int dx; + int pixx, pixy; + Sint16 w; + Sint16 xtmp; + int result = -1; + + /* + * Get clipping boundary + */ + left = dst->clip_rect.x; + right = dst->clip_rect.x + dst->clip_rect.w - 1; + top = dst->clip_rect.y; + bottom = dst->clip_rect.y + dst->clip_rect.h - 1; + + /* + * Check visibility of hline + */ + if ((x1right) && (x2>right)) { + return(0); + } + if ((ybottom)) { + return (0); + } + + /* + * Clip x + */ + if (x1 < left) { + x1 = left; + } + if (x2 > right) { + x2 = right; + } + + /* + * Swap x1, x2 if required + */ + if (x1 > x2) { + xtmp = x1; + x1 = x2; + x2 = xtmp; + } + + /* + * Calculate width + */ + w = x2 - x1; + + /* + * Sanity check on width + */ + if (w < 0) { + return (0); + } + + /* + * Lock surface + */ + SDL_LockSurface(dst); + + /* + * More variable setup + */ + dx = w; + pixx = dst->format->BytesPerPixel; + pixy = dst->pitch; + pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y; + + /* + * Draw + */ + switch (dst->format->BytesPerPixel) { + case 1: + memset(pixel, color, dx); + break; + case 2: + pixellast = pixel + dx + dx; + for (; pixel <= pixellast; pixel += pixx) { + *(Uint16 *) pixel = color; + } + break; + case 3: + pixellast = pixel + dx + dx + dx; + for (; pixel <= pixellast; pixel += pixx) { + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { + pixel[0] = (color >> 16) & 0xff; + pixel[1] = (color >> 8) & 0xff; + pixel[2] = color & 0xff; + } else { + pixel[0] = color & 0xff; + pixel[1] = (color >> 8) & 0xff; + pixel[2] = (color >> 16) & 0xff; + } + } + break; + default: /* case 4 */ + dx = dx + dx; + pixellast = pixel + dx + dx; + for (; pixel <= pixellast; pixel += pixx) { + *(Uint32 *) pixel = color; + } + break; + } + + /* + * Unlock surface + */ + SDL_UnlockSurface(dst); + + /* + * Set result code + */ + result = 0; + + return (result); +} + +int hlineRGBAStore(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (hlineColorStore(dst, x1, x2, y, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} + +int hlineColor(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color) +{ + Sint16 left, right, top, bottom; + Uint8 *pixel, *pixellast; + int dx; + int pixx, pixy; + Sint16 w; + Sint16 xtmp; + int result = -1; + Uint8 *colorptr; + + /* + * Get clipping boundary + */ + left = dst->clip_rect.x; + right = dst->clip_rect.x + dst->clip_rect.w - 1; + top = dst->clip_rect.y; + bottom = dst->clip_rect.y + dst->clip_rect.h - 1; + + /* + * Check visibility of hline + */ + if ((x1right) && (x2>right)) { + return(0); + } + if ((ybottom)) { + return (0); + } + + /* + * Clip x + */ + if (x1 < left) { + x1 = left; + } + if (x2 > right) { + x2 = right; + } + + /* + * Swap x1, x2 if required + */ + if (x1 > x2) { + xtmp = x1; + x1 = x2; + x2 = xtmp; + } + + /* + * Calculate width + */ + w = x2 - x1; + + /* + * Sanity check on width + */ + if (w < 0) { + return (0); + } + + /* + * Alpha check + */ + if ((color & 255) == 255) { + + /* + * No alpha-blending required + */ + + /* + * Setup color + */ + colorptr = (Uint8 *) & color; + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { + color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]); + } else { + color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]); + } + + /* + * Lock surface + */ + SDL_LockSurface(dst); + + /* + * More variable setup + */ + dx = w; + pixx = dst->format->BytesPerPixel; + pixy = dst->pitch; + pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y; + + /* + * Draw + */ + switch (dst->format->BytesPerPixel) { + case 1: + memset(pixel, color, dx); + break; + case 2: + pixellast = pixel + dx + dx; + for (; pixel <= pixellast; pixel += pixx) { + *(Uint16 *) pixel = color; + } + break; + case 3: + pixellast = pixel + dx + dx + dx; + for (; pixel <= pixellast; pixel += pixx) { + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { + pixel[0] = (color >> 16) & 0xff; + pixel[1] = (color >> 8) & 0xff; + pixel[2] = color & 0xff; + } else { + pixel[0] = color & 0xff; + pixel[1] = (color >> 8) & 0xff; + pixel[2] = (color >> 16) & 0xff; + } + } + break; + default: /* case 4 */ + dx = dx + dx; + pixellast = pixel + dx + dx; + for (; pixel <= pixellast; pixel += pixx) { + *(Uint32 *) pixel = color; + } + break; + } + + /* + * Unlock surface + */ + SDL_UnlockSurface(dst); + + /* + * Set result code + */ + result = 0; + + } else { + + /* + * Alpha blending blit + */ + + result = HLineAlpha(dst, x1, x1 + w, y, color); + + } + + return (result); +} + +int hlineRGBA(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (hlineColor(dst, x1, x2, y, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} + +/* ----- Vertical line */ + +int vlineColor(SDL_Surface * dst, Sint16 x, Sint16 y1, Sint16 y2, Uint32 color) +{ + Sint16 left, right, top, bottom; + Uint8 *pixel, *pixellast; + int dy; + int pixx, pixy; + Sint16 h; + Sint16 ytmp; + int result = -1; + Uint8 *colorptr; + + /* + * Get clipping boundary + */ + left = dst->clip_rect.x; + right = dst->clip_rect.x + dst->clip_rect.w - 1; + top = dst->clip_rect.y; + bottom = dst->clip_rect.y + dst->clip_rect.h - 1; + + /* + * Check visibility of vline + */ + if ((xright)) { + return (0); + } + if ((y1bottom) && (y2>bottom)) { + return(0); + } + + /* + * Clip y + */ + if (y1 < top) { + y1 = top; + } + if (y2 > bottom) { + y2 = bottom; + } + + /* + * Swap y1, y2 if required + */ + if (y1 > y2) { + ytmp = y1; + y1 = y2; + y2 = ytmp; + } + + /* + * Calculate height + */ + h = y2 - y1; + + /* + * Sanity check on height + */ + if (h < 0) { + return (0); + } + + /* + * Alpha check + */ + if ((color & 255) == 255) { + + /* + * No alpha-blending required + */ + + /* + * Setup color + */ + colorptr = (Uint8 *) & color; + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { + color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]); + } else { + color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]); + } + + /* + * Lock surface + */ + SDL_LockSurface(dst); + + /* + * More variable setup + */ + dy = h; + pixx = dst->format->BytesPerPixel; + pixy = dst->pitch; + pixel = ((Uint8 *) dst->pixels) + pixx * (int) x + pixy * (int) y1; + pixellast = pixel + pixy * dy; + + /* + * Draw + */ + switch (dst->format->BytesPerPixel) { + case 1: + for (; pixel <= pixellast; pixel += pixy) { + *(Uint8 *) pixel = color; + } + break; + case 2: + for (; pixel <= pixellast; pixel += pixy) { + *(Uint16 *) pixel = color; + } + break; + case 3: + for (; pixel <= pixellast; pixel += pixy) { + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { + pixel[0] = (color >> 16) & 0xff; + pixel[1] = (color >> 8) & 0xff; + pixel[2] = color & 0xff; + } else { + pixel[0] = color & 0xff; + pixel[1] = (color >> 8) & 0xff; + pixel[2] = (color >> 16) & 0xff; + } + } + break; + default: /* case 4 */ + for (; pixel <= pixellast; pixel += pixy) { + *(Uint32 *) pixel = color; + } + break; + } + + /* + * Unlock surface + */ + SDL_UnlockSurface(dst); + + /* + * Set result code + */ + result = 0; + + } else { + + /* + * Alpha blending blit + */ + + result = VLineAlpha(dst, x, y1, y1 + h, color); + + } + + return (result); +} + +int vlineRGBA(SDL_Surface * dst, Sint16 x, Sint16 y1, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (vlineColor(dst, x, y1, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} + +/* ----- Rectangle */ + +int rectangleColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color) +{ + int result; + Sint16 w, h, xtmp, ytmp; + + /* + * Swap x1, x2 if required + */ + if (x1 > x2) { + xtmp = x1; + x1 = x2; + x2 = xtmp; + } + + /* + * Swap y1, y2 if required + */ + if (y1 > y2) { + ytmp = y1; + y1 = y2; + y2 = ytmp; + } + + /* + * Calculate width&height + */ + w = x2 - x1; + h = y2 - y1; + + /* + * Sanity check + */ + if ((w < 0) || (h < 0)) { + return (0); + } + + /* + * Test for special cases of straight lines or single point + */ + if (x1 == x2) { + if (y1 == y2) { + return (pixelColor(dst, x1, y1, color)); + } else { + return (vlineColor(dst, x1, y1, y2, color)); + } + } else { + if (y1 == y2) { + return (hlineColor(dst, x1, x2, y1, color)); + } + } + + /* + * Draw rectangle + */ + result = 0; + result |= hlineColor(dst, x1, x2, y1, color); + result |= hlineColor(dst, x1, x2, y2, color); + y1 += 1; + y2 -= 1; + if (y1<=y2) { + result |= vlineColor(dst, x1, y1, y2, color); + result |= vlineColor(dst, x2, y1, y2, color); + } + return (result); + +} + +int rectangleRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (rectangleColor + (dst, x1, y1, x2, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} + +/* --------- Clipping routines for line */ + +/* Clipping based heavily on code from */ +/* http://www.ncsa.uiuc.edu/Vis/Graphics/src/clipCohSuth.c */ + +#define CLIP_LEFT_EDGE 0x1 +#define CLIP_RIGHT_EDGE 0x2 +#define CLIP_BOTTOM_EDGE 0x4 +#define CLIP_TOP_EDGE 0x8 +#define CLIP_INSIDE(a) (!a) +#define CLIP_REJECT(a,b) (a&b) +#define CLIP_ACCEPT(a,b) (!(a|b)) + +static int clipEncode(Sint16 x, Sint16 y, Sint16 left, Sint16 top, Sint16 right, Sint16 bottom) +{ + int code = 0; + + if (x < left) { + code |= CLIP_LEFT_EDGE; + } else if (x > right) { + code |= CLIP_RIGHT_EDGE; + } + if (y < top) { + code |= CLIP_TOP_EDGE; + } else if (y > bottom) { + code |= CLIP_BOTTOM_EDGE; + } + return code; +} + +static int clipLine(SDL_Surface * dst, Sint16 * x1, Sint16 * y1, Sint16 * x2, Sint16 * y2) +{ + Sint16 left, right, top, bottom; + int code1, code2; + int draw = 0; + Sint16 swaptmp; + float m; + + /* + * Get clipping boundary + */ + left = dst->clip_rect.x; + right = dst->clip_rect.x + dst->clip_rect.w - 1; + top = dst->clip_rect.y; + bottom = dst->clip_rect.y + dst->clip_rect.h - 1; + + while (1) { + code1 = clipEncode(*x1, *y1, left, top, right, bottom); + code2 = clipEncode(*x2, *y2, left, top, right, bottom); + if (CLIP_ACCEPT(code1, code2)) { + draw = 1; + break; + } else if (CLIP_REJECT(code1, code2)) + break; + else { + if (CLIP_INSIDE(code1)) { + swaptmp = *x2; + *x2 = *x1; + *x1 = swaptmp; + swaptmp = *y2; + *y2 = *y1; + *y1 = swaptmp; + swaptmp = code2; + code2 = code1; + code1 = swaptmp; + } + if (*x2 != *x1) { + m = (*y2 - *y1) / (float) (*x2 - *x1); + } else { + m = 1.0f; + } + if (code1 & CLIP_LEFT_EDGE) { + *y1 += (Sint16) ((left - *x1) * m); + *x1 = left; + } else if (code1 & CLIP_RIGHT_EDGE) { + *y1 += (Sint16) ((right - *x1) * m); + *x1 = right; + } else if (code1 & CLIP_BOTTOM_EDGE) { + if (*x2 != *x1) { + *x1 += (Sint16) ((bottom - *y1) / m); + } + *y1 = bottom; + } else if (code1 & CLIP_TOP_EDGE) { + if (*x2 != *x1) { + *x1 += (Sint16) ((top - *y1) / m); + } + *y1 = top; + } + } + } + + return draw; +} + +/* ----- Filled rectangle (Box) */ + +int boxColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color) +{ + Sint16 left, right, top, bottom; + Uint8 *pixel, *pixellast; + int x, dx; + int dy; + int pixx, pixy; + Sint16 w, h, tmp; + int result; + Uint8 *colorptr; + + /* + * Get clipping boundary + */ + left = dst->clip_rect.x; + right = dst->clip_rect.x + dst->clip_rect.w - 1; + top = dst->clip_rect.y; + bottom = dst->clip_rect.y + dst->clip_rect.h - 1; + + /* Check visibility */ + if ((x1right) && (x2>right)) { + return(0); + } + if ((y1bottom) && (y2>bottom)) { + return(0); + } + + /* Clip all points */ + if (x1right) { + x1=right; + } + if (x2right) { + x2=right; + } + if (y1bottom) { + y1=bottom; + } + if (y2bottom) { + y2=bottom; + } + + /* + * Order coordinates + */ + if (x1 > x2) { + tmp = x1; + x1 = x2; + x2 = tmp; + } + if (y1 > y2) { + tmp = y1; + y1 = y2; + y2 = tmp; + } + + /* + * Test for special cases of straight line or single point + */ + if (x1 == x2) { + if (y1 == y2) { + return (pixelColor(dst, x1, y1, color)); + } else { + return (vlineColor(dst, x1, y1, y2, color)); + } + } + if (y1 == y2) { + return (hlineColor(dst, x1, x2, y1, color)); + } + + + /* + * Calculate width&height + */ + w = x2 - x1; + h = y2 - y1; + + /* + * Alpha check + */ + if ((color & 255) == 255) { + + /* + * No alpha-blending required + */ + + /* + * Setup color + */ + colorptr = (Uint8 *) & color; + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { + color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]); + } else { + color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]); + } + + /* + * Lock surface + */ + SDL_LockSurface(dst); + + /* + * More variable setup + */ + dx = w; + dy = h; + pixx = dst->format->BytesPerPixel; + pixy = dst->pitch; + pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y1; + pixellast = pixel + pixx * dx + pixy * dy; + dx++; + + /* + * Draw + */ + switch (dst->format->BytesPerPixel) { + case 1: + for (; pixel <= pixellast; pixel += pixy) { + memset(pixel, (Uint8) color, dx); + } + break; + case 2: + pixy -= (pixx * dx); + for (; pixel <= pixellast; pixel += pixy) { + for (x = 0; x < dx; x++) { + *(Uint16 *) pixel = color; + pixel += pixx; + } + } + break; + case 3: + pixy -= (pixx * dx); + for (; pixel <= pixellast; pixel += pixy) { + for (x = 0; x < dx; x++) { + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { + pixel[0] = (color >> 16) & 0xff; + pixel[1] = (color >> 8) & 0xff; + pixel[2] = color & 0xff; + } else { + pixel[0] = color & 0xff; + pixel[1] = (color >> 8) & 0xff; + pixel[2] = (color >> 16) & 0xff; + } + pixel += pixx; + } + } + break; + default: /* case 4 */ + pixy -= (pixx * dx); + for (; pixel <= pixellast; pixel += pixy) { + for (x = 0; x < dx; x++) { + *(Uint32 *) pixel = color; + pixel += pixx; + } + } + break; + } + + /* + * Unlock surface + */ + SDL_UnlockSurface(dst); + + result = 0; + + } else { + + result = filledRectAlpha(dst, x1, y1, x1 + w, y1 + h, color); + + } + + return (result); +} + +int boxRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (boxColor(dst, x1, y1, x2, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} + +/* ----- Line */ + +/* Non-alpha line drawing code adapted from routine */ +/* by Pete Shinners, pete@shinners.org */ +/* Originally from pygame, http://pygame.seul.org */ + +#define ABS(a) (((a)<0) ? -(a) : (a)) + +int lineColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color) +{ + int pixx, pixy; + int x, y; + int dx, dy; + int ax, ay; + int sx, sy; + int swaptmp; + Uint8 *pixel; + Uint8 *colorptr; + + /* + * Clip line and test if we have to draw + */ + if (!(clipLine(dst, &x1, &y1, &x2, &y2))) { + return (0); + } + + /* + * Test for special cases of straight lines or single point + */ + if (x1 == x2) { + if (y1 < y2) { + return (vlineColor(dst, x1, y1, y2, color)); + } else if (y1 > y2) { + return (vlineColor(dst, x1, y2, y1, color)); + } else { + return (pixelColor(dst, x1, y1, color)); + } + } + if (y1 == y2) { + if (x1 < x2) { + return (hlineColor(dst, x1, x2, y1, color)); + } else if (x1 > x2) { + return (hlineColor(dst, x2, x1, y1, color)); + } + } + + /* + * Variable setup + */ + dx = x2 - x1; + dy = y2 - y1; + sx = (dx >= 0) ? 1 : -1; + sy = (dy >= 0) ? 1 : -1; + + /* Lock surface */ + if (SDL_MUSTLOCK(dst)) { + if (SDL_LockSurface(dst) < 0) { + return (-1); + } + } + + /* + * Check for alpha blending + */ + if ((color & 255) == 255) { + + /* + * No alpha blending - use fast pixel routines + */ + + /* + * Setup color + */ + colorptr = (Uint8 *) & color; + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { + color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]); + } else { + color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]); + } + + /* + * More variable setup + */ + dx = sx * dx + 1; + dy = sy * dy + 1; + pixx = dst->format->BytesPerPixel; + pixy = dst->pitch; + pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y1; + pixx *= sx; + pixy *= sy; + if (dx < dy) { + swaptmp = dx; + dx = dy; + dy = swaptmp; + swaptmp = pixx; + pixx = pixy; + pixy = swaptmp; + } + + /* + * Draw + */ + x = 0; + y = 0; + switch (dst->format->BytesPerPixel) { + case 1: + for (; x < dx; x++, pixel += pixx) { + *pixel = color; + y += dy; + if (y >= dx) { + y -= dx; + pixel += pixy; + } + } + break; + case 2: + for (; x < dx; x++, pixel += pixx) { + *(Uint16 *) pixel = color; + y += dy; + if (y >= dx) { + y -= dx; + pixel += pixy; + } + } + break; + case 3: + for (; x < dx; x++, pixel += pixx) { + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { + pixel[0] = (color >> 16) & 0xff; + pixel[1] = (color >> 8) & 0xff; + pixel[2] = color & 0xff; + } else { + pixel[0] = color & 0xff; + pixel[1] = (color >> 8) & 0xff; + pixel[2] = (color >> 16) & 0xff; + } + y += dy; + if (y >= dx) { + y -= dx; + pixel += pixy; + } + } + break; + default: /* case 4 */ + for (; x < dx; x++, pixel += pixx) { + *(Uint32 *) pixel = color; + y += dy; + if (y >= dx) { + y -= dx; + pixel += pixy; + } + } + break; + } + + } else { + + /* + * Alpha blending required - use single-pixel blits + */ + + ax = ABS(dx) << 1; + ay = ABS(dy) << 1; + x = x1; + y = y1; + if (ax > ay) { + int d = ay - (ax >> 1); + + while (x != x2) { + pixelColorNolock (dst, x, y, color); + if (d > 0 || (d == 0 && sx == 1)) { + y += sy; + d -= ax; + } + x += sx; + d += ay; + } + } else { + int d = ax - (ay >> 1); + + while (y != y2) { + pixelColorNolock (dst, x, y, color); + if (d > 0 || ((d == 0) && (sy == 1))) { + x += sx; + d -= ay; + } + y += sy; + d += ax; + } + } + pixelColorNolock (dst, x, y, color); + + } + + /* Unlock surface */ + if (SDL_MUSTLOCK(dst)) { + SDL_UnlockSurface(dst); + } + + return (0); +} + +int lineRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (lineColor(dst, x1, y1, x2, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} + +/* AA Line */ + +#define AAlevels 256 +#define AAbits 8 + +/* + +This implementation of the Wu antialiasing code is based on Mike Abrash's +DDJ article which was reprinted as Chapter 42 of his Graphics Programming +Black Book, but has been optimized to work with SDL and utilizes 32-bit +fixed-point arithmetic. (A. Schiffler). + +*/ + +int aalineColorInt(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, int draw_endpoint) +{ + Sint32 xx0, yy0, xx1, yy1; + int result; + Uint32 intshift, erracc, erradj; + Uint32 erracctmp, wgt, wgtcompmask; + int dx, dy, tmp, xdir, y0p1, x0pxdir; + + /* + * Clip line and test if we have to draw + */ + if (!(clipLine(dst, &x1, &y1, &x2, &y2))) { + return (0); + } + + /* + * Keep on working with 32bit numbers + */ + xx0 = x1; + yy0 = y1; + xx1 = x2; + yy1 = y2; + + /* + * Reorder points if required + */ + if (yy0 > yy1) { + tmp = yy0; + yy0 = yy1; + yy1 = tmp; + tmp = xx0; + xx0 = xx1; + xx1 = tmp; + } + + /* + * Calculate distance + */ + dx = xx1 - xx0; + dy = yy1 - yy0; + + /* + * Adjust for negative dx and set xdir + */ + if (dx >= 0) { + xdir = 1; + } else { + xdir = -1; + dx = (-dx); + } + + /* + * Check for special cases + */ + if (dx == 0) { + /* + * Vertical line + */ + return (vlineColor(dst, x1, y1, y2, color)); + } else if (dy == 0) { + /* + * Horizontal line + */ + return (hlineColor(dst, x1, x2, y1, color)); + } else if (dx == dy) { + /* + * Diagonal line + */ + return (lineColor(dst, x1, y1, x2, y2, color)); + } + + /* + * Line is not horizontal, vertical or diagonal + */ + result = 0; + + /* + * Zero accumulator + */ + erracc = 0; + + /* + * # of bits by which to shift erracc to get intensity level + */ + intshift = 32 - AAbits; + /* + * Mask used to flip all bits in an intensity weighting + */ + wgtcompmask = AAlevels - 1; + + /* Lock surface */ + if (SDL_MUSTLOCK(dst)) { + if (SDL_LockSurface(dst) < 0) { + return (-1); + } + } + + /* + * Draw the initial pixel in the foreground color + */ + result |= pixelColorNolock(dst, x1, y1, color); + + /* + * x-major or y-major? + */ + if (dy > dx) { + + /* + * y-major. Calculate 16-bit fixed point fractional part of a pixel that + * X advances every time Y advances 1 pixel, truncating the result so that + * we won't overrun the endpoint along the X axis + */ + /* + * Not-so-portable version: erradj = ((Uint64)dx << 32) / (Uint64)dy; + */ + erradj = ((dx << 16) / dy) << 16; + + /* + * draw all pixels other than the first and last + */ + x0pxdir = xx0 + xdir; + while (--dy) { + erracctmp = erracc; + erracc += erradj; + if (erracc <= erracctmp) { + /* + * rollover in error accumulator, x coord advances + */ + xx0 = x0pxdir; + x0pxdir += xdir; + } + yy0++; /* y-major so always advance Y */ + + /* + * the AAbits most significant bits of erracc give us the intensity + * weighting for this pixel, and the complement of the weighting for + * the paired pixel. + */ + wgt = (erracc >> intshift) & 255; + result |= pixelColorWeightNolock (dst, xx0, yy0, color, 255 - wgt); + result |= pixelColorWeightNolock (dst, x0pxdir, yy0, color, wgt); + } + + } else { + + /* + * x-major line. Calculate 16-bit fixed-point fractional part of a pixel + * that Y advances each time X advances 1 pixel, truncating the result so + * that we won't overrun the endpoint along the X axis. + */ + /* + * Not-so-portable version: erradj = ((Uint64)dy << 32) / (Uint64)dx; + */ + erradj = ((dy << 16) / dx) << 16; + + /* + * draw all pixels other than the first and last + */ + y0p1 = yy0 + 1; + while (--dx) { + + erracctmp = erracc; + erracc += erradj; + if (erracc <= erracctmp) { + /* + * Accumulator turned over, advance y + */ + yy0 = y0p1; + y0p1++; + } + xx0 += xdir; /* x-major so always advance X */ + /* + * the AAbits most significant bits of erracc give us the intensity + * weighting for this pixel, and the complement of the weighting for + * the paired pixel. + */ + wgt = (erracc >> intshift) & 255; + result |= pixelColorWeightNolock (dst, xx0, yy0, color, 255 - wgt); + result |= pixelColorWeightNolock (dst, xx0, y0p1, color, wgt); + } + } + + /* + * Do we have to draw the endpoint + */ + if (draw_endpoint) { + /* + * Draw final pixel, always exactly intersected by the line and doesn't + * need to be weighted. + */ + result |= pixelColorNolock (dst, x2, y2, color); + } + + /* Unlock surface */ + if (SDL_MUSTLOCK(dst)) { + SDL_UnlockSurface(dst); + } + + return (result); +} + +int aalineColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color) +{ + return (aalineColorInt(dst, x1, y1, x2, y2, color, 1)); +} + +int aalineRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + return (aalineColorInt + (dst, x1, y1, x2, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a, 1)); +} + + +/* ----- Circle */ + +/* Note: Based on algorithm from sge library, modified by A. Schiffler */ +/* with multiple pixel-draw removal and other minor speedup changes. */ + +int circleColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 r, Uint32 color) +{ + Sint16 left, right, top, bottom; + int result; + Sint16 x1, y1, x2, y2; + Sint16 cx = 0; + Sint16 cy = r; + Sint16 ocx = (Sint16) 0xffff; + Sint16 ocy = (Sint16) 0xffff; + Sint16 df = 1 - r; + Sint16 d_e = 3; + Sint16 d_se = -2 * r + 5; + Sint16 xpcx, xmcx, xpcy, xmcy; + Sint16 ypcy, ymcy, ypcx, ymcx; + Uint8 *colorptr; + + /* + * Sanity check radius + */ + if (r < 0) { + return (-1); + } + + /* + * Special case for r=0 - draw a point + */ + if (r == 0) { + return (pixelColor(dst, x, y, color)); + } + + /* + * Get clipping boundary + */ + left = dst->clip_rect.x; + right = dst->clip_rect.x + dst->clip_rect.w - 1; + top = dst->clip_rect.y; + bottom = dst->clip_rect.y + dst->clip_rect.h - 1; + + /* + * Test if bounding box of circle is visible + */ + x1 = x - r; + x2 = x + r; + y1 = y - r; + y2 = y + r; + if ((x1right) && (x2>right)) { + return(0); + } + if ((y1bottom) && (y2>bottom)) { + return(0); + } + + /* + * Draw circle + */ + result = 0; + + /* Lock surface */ + if (SDL_MUSTLOCK(dst)) { + if (SDL_LockSurface(dst) < 0) { + return (-1); + } + } + + /* + * Alpha Check + */ + if ((color & 255) == 255) { + + /* + * No Alpha - direct memory writes + */ + + /* + * Setup color + */ + colorptr = (Uint8 *) & color; + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { + color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]); + } else { + color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]); + } + + /* + * Draw + */ + do { + if ((ocy != cy) || (ocx != cx)) { + xpcx = x + cx; + xmcx = x - cx; + if (cy > 0) { + ypcy = y + cy; + ymcy = y - cy; + result |= fastPixelColorNolock(dst, xmcx, ypcy, color); + result |= fastPixelColorNolock(dst, xpcx, ypcy, color); + result |= fastPixelColorNolock(dst, xmcx, ymcy, color); + result |= fastPixelColorNolock(dst, xpcx, ymcy, color); + } else { + result |= fastPixelColorNolock(dst, xmcx, y, color); + result |= fastPixelColorNolock(dst, xpcx, y, color); + } + ocy = cy; + xpcy = x + cy; + xmcy = x - cy; + if (cx > 0) { + ypcx = y + cx; + ymcx = y - cx; + result |= fastPixelColorNolock(dst, xmcy, ypcx, color); + result |= fastPixelColorNolock(dst, xpcy, ypcx, color); + result |= fastPixelColorNolock(dst, xmcy, ymcx, color); + result |= fastPixelColorNolock(dst, xpcy, ymcx, color); + } else { + result |= fastPixelColorNolock(dst, xmcy, y, color); + result |= fastPixelColorNolock(dst, xpcy, y, color); + } + ocx = cx; + } + /* + * Update + */ + if (df < 0) { + df += d_e; + d_e += 2; + d_se += 2; + } else { + df += d_se; + d_e += 2; + d_se += 4; + cy--; + } + cx++; + } while (cx <= cy); + + /* + * Unlock surface + */ + SDL_UnlockSurface(dst); + + } else { + + /* + * Using Alpha - blended pixel blits + */ + + do { + /* + * Draw + */ + if ((ocy != cy) || (ocx != cx)) { + xpcx = x + cx; + xmcx = x - cx; + if (cy > 0) { + ypcy = y + cy; + ymcy = y - cy; + result |= pixelColorNolock (dst, xmcx, ypcy, color); + result |= pixelColorNolock (dst, xpcx, ypcy, color); + result |= pixelColorNolock (dst, xmcx, ymcy, color); + result |= pixelColorNolock (dst, xpcx, ymcy, color); + } else { + result |= pixelColorNolock (dst, xmcx, y, color); + result |= pixelColorNolock (dst, xpcx, y, color); + } + ocy = cy; + xpcy = x + cy; + xmcy = x - cy; + if (cx > 0) { + ypcx = y + cx; + ymcx = y - cx; + result |= pixelColorNolock (dst, xmcy, ypcx, color); + result |= pixelColorNolock (dst, xpcy, ypcx, color); + result |= pixelColorNolock (dst, xmcy, ymcx, color); + result |= pixelColorNolock (dst, xpcy, ymcx, color); + } else { + result |= pixelColorNolock (dst, xmcy, y, color); + result |= pixelColorNolock (dst, xpcy, y, color); + } + ocx = cx; + } + /* + * Update + */ + if (df < 0) { + df += d_e; + d_e += 2; + d_se += 2; + } else { + df += d_se; + d_e += 2; + d_se += 4; + cy--; + } + cx++; + } while (cx <= cy); + + } /* Alpha check */ + + /* Unlock surface */ + if (SDL_MUSTLOCK(dst)) { + SDL_UnlockSurface(dst); + } + + return (result); +} + +int circleRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (circleColor(dst, x, y, rad, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} + +/* ----- AA Circle */ + +/* AA circle is based on AAellipse */ + +int aacircleColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 r, Uint32 color) +{ + return (aaellipseColor(dst, x, y, r, r, color)); +} + +int aacircleRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (aaellipseColor + (dst, x, y, rad, rad, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} + +/* ----- Filled Circle */ + +/* Note: Based on algorithm from sge library with multiple-hline draw removal */ + +/* and other speedup changes. */ + +int filledCircleColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 r, Uint32 color) +{ + Sint16 left, right, top, bottom; + int result; + Sint16 x1, y1, x2, y2; + Sint16 cx = 0; + Sint16 cy = r; + Sint16 ocx = (Sint16) 0xffff; + Sint16 ocy = (Sint16) 0xffff; + Sint16 df = 1 - r; + Sint16 d_e = 3; + Sint16 d_se = -2 * r + 5; + Sint16 xpcx, xmcx, xpcy, xmcy; + Sint16 ypcy, ymcy, ypcx, ymcx; + + /* + * Sanity check radius + */ + if (r < 0) { + return (-1); + } + + /* + * Special case for r=0 - draw a point + */ + if (r == 0) { + return (pixelColor(dst, x, y, color)); + } + + /* + * Get clipping boundary + */ + left = dst->clip_rect.x; + right = dst->clip_rect.x + dst->clip_rect.w - 1; + top = dst->clip_rect.y; + bottom = dst->clip_rect.y + dst->clip_rect.h - 1; + + /* + * Test if bounding box of circle is visible + */ + x1 = x - r; + x2 = x + r; + y1 = y - r; + y2 = y + r; + if ((x1right) && (x2>right)) { + return(0); + } + if ((y1bottom) && (y2>bottom)) { + return(0); + } + + /* + * Draw + */ + result = 0; + do { + xpcx = x + cx; + xmcx = x - cx; + xpcy = x + cy; + xmcy = x - cy; + if (ocy != cy) { + if (cy > 0) { + ypcy = y + cy; + ymcy = y - cy; + result |= hlineColor(dst, xmcx, xpcx, ypcy, color); + result |= hlineColor(dst, xmcx, xpcx, ymcy, color); + } else { + result |= hlineColor(dst, xmcx, xpcx, y, color); + } + ocy = cy; + } + if (ocx != cx) { + if (cx != cy) { + if (cx > 0) { + ypcx = y + cx; + ymcx = y - cx; + result |= hlineColor(dst, xmcy, xpcy, ymcx, color); + result |= hlineColor(dst, xmcy, xpcy, ypcx, color); + } else { + result |= hlineColor(dst, xmcy, xpcy, y, color); + } + } + ocx = cx; + } + /* + * Update + */ + if (df < 0) { + df += d_e; + d_e += 2; + d_se += 2; + } else { + df += d_se; + d_e += 2; + d_se += 4; + cy--; + } + cx++; + } while (cx <= cy); + + return (result); +} + +int filledCircleRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (filledCircleColor + (dst, x, y, rad, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} + + +/* ----- Ellipse */ + +/* Note: Based on algorithm from sge library with multiple-hline draw removal */ +/* and other speedup changes. */ + +int ellipseColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color) +{ + Sint16 left, right, top, bottom; + int result; + Sint16 x1, y1, x2, y2; + int ix, iy; + int h, i, j, k; + int oh, oi, oj, ok; + int xmh, xph, ypk, ymk; + int xmi, xpi, ymj, ypj; + int xmj, xpj, ymi, ypi; + int xmk, xpk, ymh, yph; + Uint8 *colorptr; + + /* + * Sanity check radii + */ + if ((rx < 0) || (ry < 0)) { + return (-1); + } + + /* + * Special case for rx=0 - draw a vline + */ + if (rx == 0) { + return (vlineColor(dst, x, y - ry, y + ry, color)); + } + /* + * Special case for ry=0 - draw a hline + */ + if (ry == 0) { + return (hlineColor(dst, x - rx, x + rx, y, color)); + } + + /* + * Get clipping boundary + */ + left = dst->clip_rect.x; + right = dst->clip_rect.x + dst->clip_rect.w - 1; + top = dst->clip_rect.y; + bottom = dst->clip_rect.y + dst->clip_rect.h - 1; + + /* + * Test if bounding box of ellipse is visible + */ + x1 = x - rx; + x2 = x + rx; + y1 = y - ry; + y2 = y + ry; + if ((x1right) && (x2>right)) { + return(0); + } + if ((y1bottom) && (y2>bottom)) { + return(0); + } + + /* + * Init vars + */ + oh = oi = oj = ok = 0xFFFF; + + /* + * Draw + */ + result = 0; + + /* Lock surface */ + if (SDL_MUSTLOCK(dst)) { + if (SDL_LockSurface(dst) < 0) { + return (-1); + } + } + + /* + * Check alpha + */ + if ((color & 255) == 255) { + + /* + * No Alpha - direct memory writes + */ + + /* + * Setup color + */ + colorptr = (Uint8 *) & color; + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { + color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]); + } else { + color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]); + } + + + if (rx > ry) { + ix = 0; + iy = rx * 64; + + do { + h = (ix + 32) >> 6; + i = (iy + 32) >> 6; + j = (h * ry) / rx; + k = (i * ry) / rx; + + if (((ok != k) && (oj != k)) || ((oj != j) && (ok != j)) || (k != j)) { + xph = x + h; + xmh = x - h; + if (k > 0) { + ypk = y + k; + ymk = y - k; + result |= fastPixelColorNolock(dst, xmh, ypk, color); + result |= fastPixelColorNolock(dst, xph, ypk, color); + result |= fastPixelColorNolock(dst, xmh, ymk, color); + result |= fastPixelColorNolock(dst, xph, ymk, color); + } else { + result |= fastPixelColorNolock(dst, xmh, y, color); + result |= fastPixelColorNolock(dst, xph, y, color); + } + ok = k; + xpi = x + i; + xmi = x - i; + if (j > 0) { + ypj = y + j; + ymj = y - j; + result |= fastPixelColorNolock(dst, xmi, ypj, color); + result |= fastPixelColorNolock(dst, xpi, ypj, color); + result |= fastPixelColorNolock(dst, xmi, ymj, color); + result |= fastPixelColorNolock(dst, xpi, ymj, color); + } else { + result |= fastPixelColorNolock(dst, xmi, y, color); + result |= fastPixelColorNolock(dst, xpi, y, color); + } + oj = j; + } + + ix = ix + iy / rx; + iy = iy - ix / rx; + + } while (i > h); + } else { + ix = 0; + iy = ry * 64; + + do { + h = (ix + 32) >> 6; + i = (iy + 32) >> 6; + j = (h * rx) / ry; + k = (i * rx) / ry; + + if (((oi != i) && (oh != i)) || ((oh != h) && (oi != h) && (i != h))) { + xmj = x - j; + xpj = x + j; + if (i > 0) { + ypi = y + i; + ymi = y - i; + result |= fastPixelColorNolock(dst, xmj, ypi, color); + result |= fastPixelColorNolock(dst, xpj, ypi, color); + result |= fastPixelColorNolock(dst, xmj, ymi, color); + result |= fastPixelColorNolock(dst, xpj, ymi, color); + } else { + result |= fastPixelColorNolock(dst, xmj, y, color); + result |= fastPixelColorNolock(dst, xpj, y, color); + } + oi = i; + xmk = x - k; + xpk = x + k; + if (h > 0) { + yph = y + h; + ymh = y - h; + result |= fastPixelColorNolock(dst, xmk, yph, color); + result |= fastPixelColorNolock(dst, xpk, yph, color); + result |= fastPixelColorNolock(dst, xmk, ymh, color); + result |= fastPixelColorNolock(dst, xpk, ymh, color); + } else { + result |= fastPixelColorNolock(dst, xmk, y, color); + result |= fastPixelColorNolock(dst, xpk, y, color); + } + oh = h; + } + + ix = ix + iy / ry; + iy = iy - ix / ry; + + } while (i > h); + } + + } else { + + if (rx > ry) { + ix = 0; + iy = rx * 64; + + do { + h = (ix + 32) >> 6; + i = (iy + 32) >> 6; + j = (h * ry) / rx; + k = (i * ry) / rx; + + if (((ok != k) && (oj != k)) || ((oj != j) && (ok != j)) || (k != j)) { + xph = x + h; + xmh = x - h; + if (k > 0) { + ypk = y + k; + ymk = y - k; + result |= pixelColorNolock (dst, xmh, ypk, color); + result |= pixelColorNolock (dst, xph, ypk, color); + result |= pixelColorNolock (dst, xmh, ymk, color); + result |= pixelColorNolock (dst, xph, ymk, color); + } else { + result |= pixelColorNolock (dst, xmh, y, color); + result |= pixelColorNolock (dst, xph, y, color); + } + ok = k; + xpi = x + i; + xmi = x - i; + if (j > 0) { + ypj = y + j; + ymj = y - j; + result |= pixelColorNolock (dst, xmi, ypj, color); + result |= pixelColorNolock (dst, xpi, ypj, color); + result |= pixelColorNolock (dst, xmi, ymj, color); + result |= pixelColor(dst, xpi, ymj, color); + } else { + result |= pixelColorNolock (dst, xmi, y, color); + result |= pixelColorNolock (dst, xpi, y, color); + } + oj = j; + } + + ix = ix + iy / rx; + iy = iy - ix / rx; + + } while (i > h); + } else { + ix = 0; + iy = ry * 64; + + do { + h = (ix + 32) >> 6; + i = (iy + 32) >> 6; + j = (h * rx) / ry; + k = (i * rx) / ry; + + if (((oi != i) && (oh != i)) || ((oh != h) && (oi != h) && (i != h))) { + xmj = x - j; + xpj = x + j; + if (i > 0) { + ypi = y + i; + ymi = y - i; + result |= pixelColorNolock (dst, xmj, ypi, color); + result |= pixelColorNolock (dst, xpj, ypi, color); + result |= pixelColorNolock (dst, xmj, ymi, color); + result |= pixelColorNolock (dst, xpj, ymi, color); + } else { + result |= pixelColorNolock (dst, xmj, y, color); + result |= pixelColorNolock (dst, xpj, y, color); + } + oi = i; + xmk = x - k; + xpk = x + k; + if (h > 0) { + yph = y + h; + ymh = y - h; + result |= pixelColorNolock (dst, xmk, yph, color); + result |= pixelColorNolock (dst, xpk, yph, color); + result |= pixelColorNolock (dst, xmk, ymh, color); + result |= pixelColorNolock (dst, xpk, ymh, color); + } else { + result |= pixelColorNolock (dst, xmk, y, color); + result |= pixelColorNolock (dst, xpk, y, color); + } + oh = h; + } + + ix = ix + iy / ry; + iy = iy - ix / ry; + + } while (i > h); + } + + } /* Alpha check */ + + /* Unlock surface */ + if (SDL_MUSTLOCK(dst)) { + SDL_UnlockSurface(dst); + } + + return (result); +} + +int ellipseRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (ellipseColor(dst, x, y, rx, ry, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} + +/* ----- AA Ellipse */ + +/* Based on code from Anders Lindstroem, based on code from SGE, based on code from TwinLib */ + +int aaellipseColor(SDL_Surface * dst, Sint16 xc, Sint16 yc, Sint16 rx, Sint16 ry, Uint32 color) +{ + Sint16 left, right, top, bottom; + Sint16 x1,y1,x2,y2; + int i; + int a2, b2, ds, dt, dxt, t, s, d; + Sint16 x, y, xs, ys, dyt, xx, yy, xc2, yc2; + float cp; + Uint8 weight, iweight; + int result; + + /* + * Sanity check radii + */ + if ((rx < 0) || (ry < 0)) { + return (-1); + } + + /* + * Special case for rx=0 - draw a vline + */ + if (rx == 0) { + return (vlineColor(dst, xc, yc - ry, yc + ry, color)); + } + /* + * Special case for ry=0 - draw a hline + */ + if (ry == 0) { + return (hlineColor(dst, xc - rx, xc + rx, yc, color)); + } + + /* + * Get clipping boundary + */ + left = dst->clip_rect.x; + right = dst->clip_rect.x + dst->clip_rect.w - 1; + top = dst->clip_rect.y; + bottom = dst->clip_rect.y + dst->clip_rect.h - 1; + + /* + * Test if bounding box of ellipse is visible + */ + x1 = xc - rx; + x2 = xc + rx; + y1 = yc - ry; + y2 = yc + ry; + if ((x1right) && (x2>right)) { + return(0); + } + if ((y1bottom) && (y2>bottom)) { + return(0); + } + + /* Variable setup */ + a2 = rx * rx; + b2 = ry * ry; + + ds = 2 * a2; + dt = 2 * b2; + + xc2 = 2 * xc; + yc2 = 2 * yc; + + dxt = (int) (a2 / sqrt(a2 + b2)); + + t = 0; + s = -2 * a2 * ry; + d = 0; + + x = xc; + y = yc - ry; + + /* Draw */ + result = 0; + + /* Lock surface */ + if (SDL_MUSTLOCK(dst)) { + if (SDL_LockSurface(dst) < 0) { + return (-1); + } + } + + /* "End points" */ + result |= pixelColorNolock(dst, x, y, color); + result |= pixelColorNolock(dst, xc2 - x, y, color); + result |= pixelColorNolock(dst, x, yc2 - y, color); + result |= pixelColorNolock(dst, xc2 - x, yc2 - y, color); + + for (i = 1; i <= dxt; i++) { + x--; + d += t - b2; + + if (d >= 0) + ys = y - 1; + else if ((d - s - a2) > 0) { + if ((2 * d - s - a2) >= 0) + ys = y + 1; + else { + ys = y; + y++; + d -= s + a2; + s += ds; + } + } else { + y++; + ys = y + 1; + d -= s + a2; + s += ds; + } + + t -= dt; + + /* Calculate alpha */ + if (s != 0.0) { + cp = (float) abs(d) / (float) abs(s); + if (cp > 1.0) { + cp = 1.0; + } + } else { + cp = 1.0; + } + + /* Calculate weights */ + weight = (Uint8) (cp * 255); + iweight = 255 - weight; + + /* Upper half */ + xx = xc2 - x; + result |= pixelColorWeightNolock(dst, x, y, color, iweight); + result |= pixelColorWeightNolock(dst, xx, y, color, iweight); + + result |= pixelColorWeightNolock(dst, x, ys, color, weight); + result |= pixelColorWeightNolock(dst, xx, ys, color, weight); + + /* Lower half */ + yy = yc2 - y; + result |= pixelColorWeightNolock(dst, x, yy, color, iweight); + result |= pixelColorWeightNolock(dst, xx, yy, color, iweight); + + yy = yc2 - ys; + result |= pixelColorWeightNolock(dst, x, yy, color, weight); + result |= pixelColorWeightNolock(dst, xx, yy, color, weight); + } + + dyt = abs(y - yc); + + for (i = 1; i <= dyt; i++) { + y++; + d -= s + a2; + + if (d <= 0) + xs = x + 1; + else if ((d + t - b2) < 0) { + if ((2 * d + t - b2) <= 0) + xs = x - 1; + else { + xs = x; + x--; + d += t - b2; + t -= dt; + } + } else { + x--; + xs = x - 1; + d += t - b2; + t -= dt; + } + + s += ds; + + /* Calculate alpha */ + if (t != 0.0) { + cp = (float) abs(d) / (float) abs(t); + if (cp > 1.0) { + cp = 1.0; + } + } else { + cp = 1.0; + } + + /* Calculate weight */ + weight = (Uint8) (cp * 255); + iweight = 255 - weight; + + /* Left half */ + xx = xc2 - x; + yy = yc2 - y; + result |= pixelColorWeightNolock(dst, x, y, color, iweight); + result |= pixelColorWeightNolock(dst, xx, y, color, iweight); + + result |= pixelColorWeightNolock(dst, x, yy, color, iweight); + result |= pixelColorWeightNolock(dst, xx, yy, color, iweight); + + /* Right half */ + xx = 2 * xc - xs; + result |= pixelColorWeightNolock(dst, xs, y, color, weight); + result |= pixelColorWeightNolock(dst, xx, y, color, weight); + + result |= pixelColorWeightNolock(dst, xs, yy, color, weight); + result |= pixelColorWeightNolock(dst, xx, yy, color, weight); + + + } + + /* Unlock surface */ + if (SDL_MUSTLOCK(dst)) { + SDL_UnlockSurface(dst); + } + + return (result); +} + +int aaellipseRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (aaellipseColor + (dst, x, y, rx, ry, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} + +/* ---- Filled Ellipse */ + +/* Note: */ +/* Based on algorithm from sge library with multiple-hline draw removal */ +/* and other speedup changes. */ + +int filledEllipseColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color) +{ + Sint16 left, right, top, bottom; + int result; + Sint16 x1, y1, x2, y2; + int ix, iy; + int h, i, j, k; + int oh, oi, oj, ok; + int xmh, xph; + int xmi, xpi; + int xmj, xpj; + int xmk, xpk; + + /* + * Sanity check radii + */ + if ((rx < 0) || (ry < 0)) { + return (-1); + } + + /* + * Special case for rx=0 - draw a vline + */ + if (rx == 0) { + return (vlineColor(dst, x, y - ry, y + ry, color)); + } + /* + * Special case for ry=0 - draw a hline + */ + if (ry == 0) { + return (hlineColor(dst, x - rx, x + rx, y, color)); + } + + /* + * Get clipping boundary + */ + left = dst->clip_rect.x; + right = dst->clip_rect.x + dst->clip_rect.w - 1; + top = dst->clip_rect.y; + bottom = dst->clip_rect.y + dst->clip_rect.h - 1; + + /* + * Test if bounding box of ellipse is visible + */ + x1 = x - rx; + x2 = x + rx; + y1 = y - ry; + y2 = y + ry; + if ((x1right) && (x2>right)) { + return(0); + } + if ((y1bottom) && (y2>bottom)) { + return(0); + } + + /* + * Init vars + */ + oh = oi = oj = ok = 0xFFFF; + + /* + * Draw + */ + result = 0; + if (rx > ry) { + ix = 0; + iy = rx * 64; + + do { + h = (ix + 32) >> 6; + i = (iy + 32) >> 6; + j = (h * ry) / rx; + k = (i * ry) / rx; + + if ((ok != k) && (oj != k)) { + xph = x + h; + xmh = x - h; + if (k > 0) { + result |= hlineColor(dst, xmh, xph, y + k, color); + result |= hlineColor(dst, xmh, xph, y - k, color); + } else { + result |= hlineColor(dst, xmh, xph, y, color); + } + ok = k; + } + if ((oj != j) && (ok != j) && (k != j)) { + xmi = x - i; + xpi = x + i; + if (j > 0) { + result |= hlineColor(dst, xmi, xpi, y + j, color); + result |= hlineColor(dst, xmi, xpi, y - j, color); + } else { + result |= hlineColor(dst, xmi, xpi, y, color); + } + oj = j; + } + + ix = ix + iy / rx; + iy = iy - ix / rx; + + } while (i > h); + } else { + ix = 0; + iy = ry * 64; + + do { + h = (ix + 32) >> 6; + i = (iy + 32) >> 6; + j = (h * rx) / ry; + k = (i * rx) / ry; + + if ((oi != i) && (oh != i)) { + xmj = x - j; + xpj = x + j; + if (i > 0) { + result |= hlineColor(dst, xmj, xpj, y + i, color); + result |= hlineColor(dst, xmj, xpj, y - i, color); + } else { + result |= hlineColor(dst, xmj, xpj, y, color); + } + oi = i; + } + if ((oh != h) && (oi != h) && (i != h)) { + xmk = x - k; + xpk = x + k; + if (h > 0) { + result |= hlineColor(dst, xmk, xpk, y + h, color); + result |= hlineColor(dst, xmk, xpk, y - h, color); + } else { + result |= hlineColor(dst, xmk, xpk, y, color); + } + oh = h; + } + + ix = ix + iy / ry; + iy = iy - ix / ry; + + } while (i > h); + } + + return (result); +} + + +int filledEllipseRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (filledEllipseColor + (dst, x, y, rx, ry, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} + +/* ----- filled pie */ + +/* Low-speed float pie-calc implementation by drawing polygons/lines. */ + +int doPieColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint32 color, Uint8 filled) +{ + Sint16 left, right, top, bottom; + Sint16 x1, y1, x2, y2; + int result; + double angle, start_angle, end_angle; + double deltaAngle; + double dr; + int posX, posY; + int numpoints, i; + Sint16 *vx, *vy; + + /* + * Sanity check radii + */ + if (rad < 0) { + return (-1); + } + + /* + * Fixup angles + */ + start = start % 360; + end = end % 360; + + /* + * Special case for rad=0 - draw a point + */ + if (rad == 0) { + return (pixelColor(dst, x, y, color)); + } + + /* + * Get clipping boundary + */ + left = dst->clip_rect.x; + right = dst->clip_rect.x + dst->clip_rect.w - 1; + top = dst->clip_rect.y; + bottom = dst->clip_rect.y + dst->clip_rect.h - 1; + + /* + * Test if bounding box of pie's circle is visible + */ + x1 = x - rad; + x2 = x + rad; + y1 = y - rad; + y2 = y + rad; + if ((x1right) && (x2>right)) { + return(0); + } + if ((y1bottom) && (y2>bottom)) { + return(0); + } + + /* + * Variable setup + */ + dr = (double) rad; + deltaAngle = 3.0 / dr; + start_angle = (double) start *(2.0 * M_PI / 360.0); + end_angle = (double) end *(2.0 * M_PI / 360.0); + if (start > end) { + end_angle += (2.0 * M_PI); + } + + /* Count points (rather than calculate it) */ + numpoints = 1; + angle = start_angle; + while (angle <= end_angle) { + angle += deltaAngle; + numpoints++; + } + + /* Check size of array */ + if (numpoints == 1) { + return (pixelColor(dst, x, y, color)); + } else if (numpoints == 2) { + posX = x + (int) (dr * cos(start_angle)); + posY = y + (int) (dr * sin(start_angle)); + return (lineColor(dst, x, y, posX, posY, color)); + } + + /* Allocate vertex array */ + vx = vy = (Uint16 *) malloc(2 * sizeof(Uint16) * numpoints); + if (vx == NULL) { + return (-1); + } + vy += numpoints; + + /* Center */ + vx[0] = x; + vy[0] = y; + + /* Calculate and store vertices */ + i = 1; + angle = start_angle; + while (angle <= end_angle) { + vx[i] = x + (int) (dr * cos(angle)); + vy[i] = y + (int) (dr * sin(angle)); + angle += deltaAngle; + i++; + } + + /* Draw */ + if (filled) { + result = filledPolygonColor(dst, vx, vy, numpoints, color); + } else { + result = polygonColor(dst, vx, vy, numpoints, color); + } + + /* Free vertex array */ + free(vx); + + return (result); +} + +int pieColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, + Sint16 start, Sint16 end, Uint32 color) +{ + return (doPieColor(dst, x, y, rad, start, end, color, 0)); + +} + +int pieRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, + Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + return (doPieColor(dst, x, y, rad, start, end, + ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a, 0)); + +} + +int filledPieColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint32 color) +{ + return (doPieColor(dst, x, y, rad, start, end, color, 1)); +} + +int filledPieRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, + Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + return (doPieColor(dst, x, y, rad, start, end, + ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a, 1)); +} + +/* Trigon */ + +int trigonColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color) +{ + Sint16 vx[3]; + Sint16 vy[3]; + + vx[0]=x1; + vx[1]=x2; + vx[2]=x3; + vy[0]=y1; + vy[1]=y2; + vy[2]=y3; + + return(polygonColor(dst,vx,vy,3,color)); +} + +int trigonRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, + Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + Sint16 vx[3]; + Sint16 vy[3]; + + vx[0]=x1; + vx[1]=x2; + vx[2]=x3; + vy[0]=y1; + vy[1]=y2; + vy[2]=y3; + + return(polygonRGBA(dst,vx,vy,3,r,g,b,a)); +} + +/* AA-Trigon */ + +int aatrigonColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color) +{ + Sint16 vx[3]; + Sint16 vy[3]; + + vx[0]=x1; + vx[1]=x2; + vx[2]=x3; + vy[0]=y1; + vy[1]=y2; + vy[2]=y3; + + return(aapolygonColor(dst,vx,vy,3,color)); +} + +int aatrigonRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, + Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + Sint16 vx[3]; + Sint16 vy[3]; + + vx[0]=x1; + vx[1]=x2; + vx[2]=x3; + vy[0]=y1; + vy[1]=y2; + vy[2]=y3; + + return(aapolygonRGBA(dst,vx,vy,3,r,g,b,a)); +} + +/* Filled Trigon */ + +int filledTrigonColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color) +{ + Sint16 vx[3]; + Sint16 vy[3]; + + vx[0]=x1; + vx[1]=x2; + vx[2]=x3; + vy[0]=y1; + vy[1]=y2; + vy[2]=y3; + + return(filledPolygonColor(dst,vx,vy,3,color)); +} + +int filledTrigonRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, + Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + Sint16 vx[3]; + Sint16 vy[3]; + + vx[0]=x1; + vx[1]=x2; + vx[2]=x3; + vy[0]=y1; + vy[1]=y2; + vy[2]=y3; + + return(filledPolygonRGBA(dst,vx,vy,3,r,g,b,a)); +} + +/* ---- Polygon */ + +int polygonColor(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color) +{ + int result; + int i; + const Sint16 *x1, *y1, *x2, *y2; + + /* + * Sanity check + */ + if (n < 3) { + return (-1); + } + + /* + * Pointer setup + */ + x1 = x2 = vx; + y1 = y2 = vy; + x2++; + y2++; + + /* + * Draw + */ + result = 0; + for (i = 1; i < n; i++) { + result |= lineColor(dst, *x1, *y1, *x2, *y2, color); + x1 = x2; + y1 = y2; + x2++; + y2++; + } + result |= lineColor(dst, *x1, *y1, *vx, *vy, color); + + return (result); +} + +int polygonRGBA(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (polygonColor(dst, vx, vy, n, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} + +/* ---- AA-Polygon */ + +int aapolygonColor(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color) +{ + int result; + int i; + const Sint16 *x1, *y1, *x2, *y2; + + /* + * Sanity check + */ + if (n < 3) { + return (-1); + } + + /* + * Pointer setup + */ + x1 = x2 = vx; + y1 = y2 = vy; + x2++; + y2++; + + /* + * Draw + */ + result = 0; + for (i = 1; i < n; i++) { + result |= aalineColorInt(dst, *x1, *y1, *x2, *y2, color, 0); + x1 = x2; + y1 = y2; + x2++; + y2++; + } + result |= aalineColorInt(dst, *x1, *y1, *vx, *vy, color, 0); + + return (result); +} + +int aapolygonRGBA(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (aapolygonColor(dst, vx, vy, n, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} + +/* ---- Filled Polygon */ + +int gfxPrimitivesCompareInt(const void *a, const void *b); + +static int *gfxPrimitivesPolyInts = NULL; +static int gfxPrimitivesPolyAllocated = 0; + +int filledPolygonColor(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color) +{ + int result; + int i; + int x, y, xa, xb; + int miny, maxy; + int x1, y1; + int x2, y2; + int ind1, ind2; + int ints; + + /* + * Sanity check + */ + if (n < 3) { + return -1; + } + + /* + * Allocate temp array, only grow array + */ + if (!gfxPrimitivesPolyAllocated) { + gfxPrimitivesPolyInts = (int *) malloc(sizeof(int) * n); + gfxPrimitivesPolyAllocated = n; + } else { + if (gfxPrimitivesPolyAllocated < n) { + gfxPrimitivesPolyInts = (int *) realloc(gfxPrimitivesPolyInts, sizeof(int) * n); + gfxPrimitivesPolyAllocated = n; + } + } + + /* + * Determine Y maxima + */ + miny = vy[0]; + maxy = vy[0]; + for (i = 1; (i < n); i++) { + if (vy[i] < miny) { + miny = vy[i]; + } else if (vy[i] > maxy) { + maxy = vy[i]; + } + } + + /* + * Draw, scanning y + */ + result = 0; + for (y = miny; (y <= maxy); y++) { + ints = 0; + for (i = 0; (i < n); i++) { + if (!i) { + ind1 = n - 1; + ind2 = 0; + } else { + ind1 = i - 1; + ind2 = i; + } + y1 = vy[ind1]; + y2 = vy[ind2]; + if (y1 < y2) { + x1 = vx[ind1]; + x2 = vx[ind2]; + } else if (y1 > y2) { + y2 = vy[ind1]; + y1 = vy[ind2]; + x2 = vx[ind1]; + x1 = vx[ind2]; + } else { + continue; + } + if ( ((y >= y1) && (y < y2)) || ((y == maxy) && (y > y1) && (y <= y2)) ) { + gfxPrimitivesPolyInts[ints++] = ((65536 * (y - y1)) / (y2 - y1)) * (x2 - x1) + (65536 * x1); + } + + } + + qsort(gfxPrimitivesPolyInts, ints, sizeof(int), gfxPrimitivesCompareInt); + + for (i = 0; (i < ints); i += 2) { + xa = gfxPrimitivesPolyInts[i] + 1; + xa = (xa >> 16) + ((xa & 32768) >> 15); + xb = gfxPrimitivesPolyInts[i+1] - 1; + xb = (xb >> 16) + ((xb & 32768) >> 15); + result |= hlineColor(dst, xa, xb, y, color); + } + } + + return (result); +} + +int filledPolygonRGBA(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (filledPolygonColor + (dst, vx, vy, n, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} + +int gfxPrimitivesCompareInt(const void *a, const void *b) +{ + return (*(const int *) a) - (*(const int *) b); +} + + +/* ---- Bezier curve */ + +/* + Calculate bezier interpolator of data array with ndata values at position 't' +*/ + +double evaluateBezier (double *data, int ndata, double t) +{ + double mu, result; + int n,k,kn,nn,nkn; + double blend,muk,munk; + + /* Sanity check bounds */ + if (t<0.0) { + return(data[0]); + } + if (t>=(double)ndata) { + return(data[ndata-1]); + } + + /* Adjust t to the range 0.0 to 1.0 */ + mu=t/(double)ndata; + + /* Calculate interpolate */ + n=ndata-1; + result=0.0; + muk = 1; + munk = pow(1-mu,(double)n); + for (k=0;k<=n;k++) { + nn = n; + kn = k; + nkn = n - k; + blend = muk * munk; + muk *= mu; + munk /= (1-mu); + while (nn >= 1) { + blend *= nn; + nn--; + if (kn > 1) { + blend /= (double)kn; + kn--; + } + if (nkn > 1) { + blend /= (double)nkn; + nkn--; + } + } + result += data[k] * blend; + } + + return(result); +} + +int bezierColor(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, int s, Uint32 color) +{ + int result; + int i; + double *x, *y, t, stepsize; + Sint16 x1, y1, x2, y2; + + /* + * Sanity check + */ + if (n < 3) { + return (-1); + } + if (s < 2) { + return (-1); + } + + /* + * Variable setup + */ + stepsize=(double)1.0/(double)s; + + /* Transfer vertices into float arrays */ + if ((x=(double *)malloc(sizeof(double)*(n+1)))==NULL) { + return(-1); + } + if ((y=(double *)malloc(sizeof(double)*(n+1)))==NULL) { + free(x); + return(-1); + } + for (i=0; i +#ifndef M_PI +#define M_PI 3.141592654 +#endif + +#include "SDL.h" + +/* Set up for C function definitions, even when using C++ */ +#ifdef __cplusplus +extern "C" { +#endif + +/* ----- Versioning */ + +#define SDL_GFXPRIMITIVES_MAJOR 2 +#define SDL_GFXPRIMITIVES_MINOR 0 +#define SDL_GFXPRIMITIVES_MICRO 13 + +/* ----- W32 DLL interface */ + +#if 0 +#ifdef WIN32 +#ifdef BUILD_DLL +#define DLLINTERFACE __declspec(dllexport) +#else +#define DLLINTERFACE __declspec(dllimport) +#endif +#else +#define DLLINTERFACE +#endif +#else +#define DLLINTERFACE +#endif + +/* ----- Prototypes */ + +/* Note: all ___Color routines expect the color to be in format 0xRRGGBBAA */ + +/* Pixel */ + + DLLINTERFACE int pixelColor(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color); + DLLINTERFACE int pixelRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* Horizontal line */ + + DLLINTERFACE int hlineColor(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color); + DLLINTERFACE int hlineRGBA(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* Vertical line */ + + DLLINTERFACE int vlineColor(SDL_Surface * dst, Sint16 x, Sint16 y1, Sint16 y2, Uint32 color); + DLLINTERFACE int vlineRGBA(SDL_Surface * dst, Sint16 x, Sint16 y1, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* Rectangle */ + + DLLINTERFACE int rectangleColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color); + DLLINTERFACE int rectangleRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, + Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* Filled rectangle (Box) */ + + DLLINTERFACE int boxColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color); + DLLINTERFACE int boxRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, + Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* Line */ + + DLLINTERFACE int lineColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color); + DLLINTERFACE int lineRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, + Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* AA Line */ + DLLINTERFACE int aalineColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color); + DLLINTERFACE int aalineRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, + Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* Circle */ + + DLLINTERFACE int circleColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 r, Uint32 color); + DLLINTERFACE int circleRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* AA Circle */ + + DLLINTERFACE int aacircleColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 r, Uint32 color); + DLLINTERFACE int aacircleRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, + Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* Filled Circle */ + + DLLINTERFACE int filledCircleColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 r, Uint32 color); + DLLINTERFACE int filledCircleRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, + Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* Ellipse */ + + DLLINTERFACE int ellipseColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color); + DLLINTERFACE int ellipseRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, + Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* AA Ellipse */ + + DLLINTERFACE int aaellipseColor(SDL_Surface * dst, Sint16 xc, Sint16 yc, Sint16 rx, Sint16 ry, Uint32 color); + DLLINTERFACE int aaellipseRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, + Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* Filled Ellipse */ + + DLLINTERFACE int filledEllipseColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color); + DLLINTERFACE int filledEllipseRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, + Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +#define CLOCKWISE + +/* Pie */ + + DLLINTERFACE int pieColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, + Sint16 start, Sint16 end, Uint32 color); + DLLINTERFACE int pieRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, + Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* Filled Pie */ + + DLLINTERFACE int filledPieColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, + Sint16 start, Sint16 end, Uint32 color); + DLLINTERFACE int filledPieRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, + Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* Trigon */ + + DLLINTERFACE int trigonColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color); + DLLINTERFACE int trigonRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, + Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* AA-Trigon */ + + DLLINTERFACE int aatrigonColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color); + DLLINTERFACE int aatrigonRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, + Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* Filled Trigon */ + + DLLINTERFACE int filledTrigonColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color); + DLLINTERFACE int filledTrigonRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, + Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* Polygon */ + + DLLINTERFACE int polygonColor(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color); + DLLINTERFACE int polygonRGBA(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, + int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* AA-Polygon */ + + DLLINTERFACE int aapolygonColor(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color); + DLLINTERFACE int aapolygonRGBA(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, + int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* Filled Polygon */ + + DLLINTERFACE int filledPolygonColor(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color); + DLLINTERFACE int filledPolygonRGBA(SDL_Surface * dst, const Sint16 * vx, + const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* Bezier */ +/* s = number of steps */ + + DLLINTERFACE int bezierColor(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, int s, Uint32 color); + DLLINTERFACE int bezierRGBA(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, + int n, int s, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + + +/* Ends C function definitions when using C++ */ +#ifdef __cplusplus +}; +#endif + +#endif /* _SDL_gfxPrimitives_h */ diff --git a/tools/map/alist.c b/tools/map/alist.c new file mode 100755 index 000000000..d956d81a0 --- /dev/null +++ b/tools/map/alist.c @@ -0,0 +1,228 @@ +/* alist.c, Copyright (c) 2005 Michael C. Martin */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope thta it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Se the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +//#include "libs/reslib.h" +#include "alist.h" +#include "stringbank.h" + +alist_entry * +AlistEntry_New (const char *key, const char *value) +{ + alist_entry *e; + e = malloc (sizeof(alist_entry)); + e->key = key; + e->value = value; + e->next = NULL; + return e; +} + +void +AlistEntry_Free (alist_entry *e) +{ + if (e == NULL) + return; + AlistEntry_Free (e->next); + free (e); +} + +alist * +Alist_New (void) +{ + alist *result = malloc (sizeof(alist)); + result->first = NULL; + return result; +} + +void +Alist_Free (alist *m) { + if (m == NULL) return; + AlistEntry_Free (m->first); + free (m); +} + +alist_entry * +Alist_GetEntry (alist *m, const char *key) +{ + alist_entry *x = m->first; + while (x != NULL) { + if (!strcmp (x->key, key)) + return x; + x = x->next; + } + return NULL; +} + +const char * +Alist_GetString (alist *m, const char *key) +{ + alist_entry *x = Alist_GetEntry (m, key); + return x ? x->value : NULL; +} + +void +Alist_PutString (alist *m, const char *key, const char *value) +{ + alist_entry *e = Alist_GetEntry (m, key); + if (e == NULL) { + e = AlistEntry_New(key, value); + e->next = m->first; + m->first = e; + } else { + e->value = value; + } +} + +void +Alist_PutAll (alist *dst, alist *src) +{ + alist_entry *e = src->first; + while (e) { + Alist_PutString (dst, e->key, e->value); + e = e->next; + } +} + +alist * +Alist_New_FromFile (FILE *f) +{ + long flen; + alist *m; + char *data; + + fseek (f, 0, SEEK_END); + flen = ftell (f); + fseek (f, 0, SEEK_SET); + + data = malloc (flen + 1); + if (!data) { + return NULL; + } + + fread (data, 1, flen, f); + data[flen] = '\0'; + + m = Alist_New_FromString (data); + free (data); + return m; +} + +alist * +Alist_New_FromFilename (const char *fname) +{ + alist *result; + FILE *f = fopen (fname, "rt"); + if (!f) { + return NULL; + } + result = Alist_New_FromFile (f); + fclose(f); + return result; +} + +alist * +Alist_New_FromString (char *d) +{ + alist *m = Alist_New (); + int len, i; + if (!m) return NULL; + + len = strlen(d); + i = 0; + while (i < len) { + int key_start, key_end, value_start, value_end; + /* Starting a line: search for non-whitespace */ + while ((i < len) && isspace (d[i])) i++; + if (i >= len) break; /* Done parsing! */ + /* If it was a comment, skip to end of comment/file */ + if (d[i] == '#') { + while ((i < len) && (d[i] != '\n')) i++; + if (i >= len) break; + continue; /* Back to keyword search */ + } + key_start = i; + /* Find the = on this line */ + while ((i < len) && (d[i] != '=') && + (d[i] != '\n') && (d[i] != '#')) i++; + if (i >= len) { /* Bare key at EOF */ + fprintf (stderr, "Warning: Bare keyword at EOF"); + break; + } + /* Comments here mean incomplete line too */ + if (d[i] != '=') { + fprintf (stderr, "Warning: Key without value"); + while ((i < len) && (d[i] != '\n')) i++; + if (i >= len) break; + continue; /* Back to keyword search */ + } + /* Key ends at first whitespace before = , or at key_start*/ + key_end = i; + while ((key_end > key_start) && isspace (d[key_end-1])) + key_end--; + + /* Consume the = */ + i++; + /* Value starts at first non-whitespace after = on line... */ + while ((i < len) && (d[i] != '#') && (d[i] != '\n') && + isspace (d[i])) + i++; + value_start = i; + /* Until first non-whitespace before terminator */ + while ((i < len) && (d[i] != '#') && (d[i] != '\n')) + i++; + value_end = i; + while ((value_end > value_start) && isspace (d[value_end-1])) + value_end--; + /* Skip past EOL or EOF */ + while ((i < len) && (d[i] != '\n')) + i++; + i++; + + /* We now have start and end values for key and value. + We terminate the strings for both by writing \0s, then + make a new map entry. */ + d[key_end] = '\0'; + d[value_end] = '\0'; + Alist_PutString (m, StringBank_AddOrFindString(d+key_start), + StringBank_AddOrFindString(d+value_start)); + } + return m; +} + +void +Alist_Dump (alist *m, FILE *s, const char *prefix) +{ + alist_entry *e = m->first; + int prefix_len = 0; + if (prefix) + prefix_len = strlen (prefix); + while (e) { + if (!prefix || !strncmp (prefix, e->key, prefix_len)) { + fwrite (e->key, 1, strlen (e->key), s); + fputc (' ', s); + fputc ('=', s); + fputc (' ', s); + fwrite (e->value, 1, strlen (e->value), s); + fputc ('\n', s); + } + e = e->next; + } + return; +} diff --git a/tools/map/alist.h b/tools/map/alist.h new file mode 100755 index 000000000..c4a799b7c --- /dev/null +++ b/tools/map/alist.h @@ -0,0 +1,65 @@ +/* alist.h, Copyright (c) 2005 Michael C. Martin */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope thta it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Se the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _ALIST_H_ +#define _ALIST_H_ + +#include + +/* Associative List types. */ + +typedef struct _alist_entry { + const char *key, *value; + struct _alist_entry *next; +} alist_entry; + +typedef struct _alist_map { + alist_entry *first; +} alist; + +/* ***** alist_entry operations ***** */ + +/* Constructor and destructor */ +alist_entry *AlistEntry_New (const char *key, const char *value); +void AlistEntry_Free (alist_entry *e); + +/* ***** alist operations ***** */ + +/* Standard constructor and destructor */ +alist *Alist_New (void); +void Alist_Free (alist *m); + +/* Specialized constructors: Parse an alist out of a stream, file, or + string. It expects a bunch of key=value statements, one per + line. */ +alist *Alist_New_FromFile (FILE *f); +alist *Alist_New_FromFilename (const char *fname); +alist *Alist_New_FromString (char *d); + +/* Getting and Setting operations */ +alist_entry *Alist_GetEntry (alist *m, const char *key); +const char *Alist_GetString (alist *m, const char *key); +void Alist_PutString (alist *m, const char *key, const char *value); +void Alist_PutAll (alist *dest, alist *src); + +/* Dump the alist to the specified stream in a form that could be + read later by the Alist_New_From* routines. Dump only keys + that begin with the prefix; NULL means all keys. */ +void Alist_Dump (alist *m, FILE *s, const char *prefix); + +#endif /* _ALIST_H_ */ diff --git a/tools/map/clusters.map b/tools/map/clusters.map new file mode 100755 index 000000000..8c4ff5636 --- /dev/null +++ b/tools/map/clusters.map @@ -0,0 +1,102 @@ +Andromedae,s,AB +Antliae,ne,AB,BC,BE,CD,EF,FA +Apodis,w,AB,BC,CD,DA +Aquarii,ne,AG,AC,CD,DB,BE,EF,FA +Aquilae,se,AB,AC,AD,AE +Arae,nw,AB,AC,AD,DE,EA +Arianni,ne,AB,BC,CA +Arietis,nw,AB,BC,CD,DE +Aurigae,s,AB,BC,CD +Bootis,e,AD,AB,BC,CG,CF,FE,EA +Brahe,w,AB,BF,FE,ED,DC,CE +Caeli,n,AB,BC,CD,DE +Camelopardalis,e,AB,BH,HE,EA,AF,FG,AC,CD,DI +Cancri,e,AC,CB,BD,DC +Capricorni,w,AB,BC,CA +Carinae,nw,AC,CB +Cassiopeiae,s,AB,BD,DE,DC,CA +Centauri,w,CA,AE,EF,FB,BD +Cephei,n,AB +Cerenkov,n,AB +Ceti,e,EF,FA,AD,DC,CB,BG,GD +Chamaeleonis,e,AB,BC,CD,DE,EF,FG,GH,HI,IJ +Chandrasekhar,n,AC,CB,BE,EC,CD,DA +Circini,se,AB,BC,CD,DE,EF,FA +Columbae,e,BA,AC +Copernicus,n,CA,AB +Corvi,e,DG,GB,BF,FC,CE +Crateris,ne,AB,BD,DC,DH,DE,EG,GF +Crucis,nw,AB,BC,CD,DA +Cygnus,n,AB,BD,DC,CA,BE +Delphini,s,AB +Doradus,n,AB +Draconis,s,JM,ML,LJ,JN,NF,FB,BA,AD,DK,KC,CE,EH,HG,GI,IH +Equulei,n,AB +Eridani,s,AB,BC,CA +Fornacis,n,AB,BC,CD,DE,EG,DF +Geminorum,w,AB,BC,CD,DA +Giclas,ne,AB,BE,EH,AC,CG,AD,DF +Gorno,e,AB,BC,CD,DE,EA +Gruis,ne,BA,AC,CD,DE,EF,FG,GD +Herculis,w,AB +Horologii,ne,AB,BC,CD,DE,EF,FA,AG,GH,HI,IJ,JK,KA +Hyades,e,CB,BA,AD,DC,CE,EF,FG,GH,HI,IJ,JK +Hydrae,,AB,BC +Hyginus,ne,AB +Illuminati,,DA,AB,BC,CE,EF,FG,GH +Indi,n,AB +Kepler,nw,AB,BC,CA +Klystron,w,AB +Krueger,,FA,AC,CB,BD,DE,EA +Lacaille,ne,AB,BC,CA +Lacertae,s,AB +Lalande,w,CA,AB,BC,CD +Lentilis,se,AB,BD,DA,AC +Leonis,w,AB,BC +Leporis,s,AB,BC +Librae,s,AB,BC,CD,DE,EG,GF,FD +Lipi,ne,DC,CA,AB,BE +Luyten,e,AB,BC,CA +Lyncis,sw,AB,BC,CD,DA,AE,EF,BG,GH +Lyrae,e,AB +Maksutov,se,AB +Mensae,n,AB,BC +Mersenne,e,AB +Mira,,AB,BC,CA,AD +Monocerotis,w,AB +Muscae,nw,CB,BA,AD,DE,EF,FD +Normae,se,AB,BC,CD,DE,EF +Octantis,nw,AB +Olber,s,AB,BC,CA +Ophiuchi,e,AB,BC,CA +Orionis,nw,AB,BC,CD,DA,DE,DF,AH,HG,HI,BK,KL,KJ +Pavonis,n,AB +Pegasi,e,AB +Persei,nw,AB,BF,FA,AC,CD,AH,AE,EG,EI +Phoenicis,ne,AB,BC +Pictoris,s,CA,AB,BC,CD +Piscium,nw,AC,CD,DB,BC +Ptolemae,nw,AB,BC,CD,DB,AF,FE,FG +Puppis,sw,AB,BC,CA +Pyxidis,nw,AB,BC +Raynet,nw,CA,AB +Reticuli,sw,AB,BD,DA,AC +Sagittae,s,AB,BC,CA +Sagittarii,n,AB,BC,CD +Saurus,ne,AB,BC,CA +Scorpii,sw,AB,BC,CF,FE,ED +Sculptoris,,AC,AD,AE +Scuti,e,BA,AD,DF,FE,EC +Serpentis,nw,FA,AC,CE,EB,BD,DG,GH,HI +Sextantis,n,AB,BF,FE,ED,DC +Squidi,nw,AB,BC,CA +Tauri,ne,DA,AF,FE,EC,CA,CB +Telescopii,n,AB,BC,CA +Trianguli,n,AB,BC,CA +Tucanae,ne,AB,BC,CA +Velorum,ne,AB +Virginis,se,AB,BC,CD +Vitalis,w,AB,AC,CD,DA +Volantis,s,CA,AB,BC,CD,DF,FE,EG,GF +Vulpeculae,e,AB,AC,AD,AE,AF,AG +Wolf,nw,AB diff --git a/tools/map/config.h b/tools/map/config.h new file mode 100755 index 000000000..0a70fe8f0 --- /dev/null +++ b/tools/map/config.h @@ -0,0 +1,15 @@ +/* Dummy compile-time configuration options + * Only used when compiling in MS VC++ using UQM's getopt.c + */ + +#ifndef _CONFIG_H +#define _CONFIG_H + +/* Define if words are stored with the most significant byte first */ +#undef WORDS_BIGENDIAN + +/* Defined if your system has getopt.h */ +#undef HAVE_GETOPT_H + +#endif /* _CONFIG_H */ + diff --git a/tools/map/greek.map b/tools/map/greek.map new file mode 100755 index 000000000..f73b938ac --- /dev/null +++ b/tools/map/greek.map @@ -0,0 +1 @@ +αβγδεζηθικλμνξοπρστυφχψω diff --git a/tools/map/large300.map b/tools/map/large300.map new file mode 100755 index 000000000..09ee20cf7 --- /dev/null +++ b/tools/map/large300.map @@ -0,0 +1,213 @@ +##################################################################### +# Starmap image generation script +# +# 300 dpi, clipped A3 size +##################################################################### + +# General image definition + +image.dpi.x=300 +image.dpi.y=300 +# width and height in inches; v-trimmed A3 +image.width=11.69 +image.height=14.56 +image.backcolor=200020 +# layer Order +image.layers=sois,grid,soinames,clusters,stars,starnums,cnames + +grid.extent.x=1000 +grid.extent.y=1000 +grid.step.1=100 +grid.step.2=50 +grid.step.3=10 +# origins and dimensions in inches +grid.origin.x=0.6 +grid.origin.y=0.6 +grid.width=10.49 +grid.height=10.49 +grid.color=9566cb +# font: Arial Bold +grid.font.name=arialbd.ttf +# font point size is in 1/64th of an inch +grid.font.size=8 +# weight is in 1/64th of an inch +grid.box.weight=1 +grid.lines.weight=0.75 +grid.marks.color=8771b6 + +# Stars + +stars.definition=stars.map +stars.numcolor=989898 +# font: Times New Roman +stars.desig.font.name=times.ttf +stars.desig.font.size=4 +# designation letters/symbols in utf8 for the specified font +# using Greek letters +stars.desig.table=greek.map +# star images and/or colors +# radius in 1/64 of an inch +stars.colors=RGBOYW +stars.sizes=3 +stars.R.1.image=stars/fca_027_red.png +stars.R.1.radius=1.5 +stars.R.1.color=980000 +stars.R.2.image=stars/fca_037_red.png +stars.R.2.radius=2.8 +stars.R.2.color=b80000 +stars.R.3.image=stars/fca_070_red.png +stars.R.3.radius=3.8 +stars.R.3.color=d00000 +stars.G.1.image=stars/fca_027_green.png +stars.G.1.radius=1.5 +stars.G.1.color=009800 +stars.G.2.image=stars/fca_037_green.png +stars.G.2.radius=2.8 +stars.G.2.color=00b800 +stars.G.3.image=stars/fca_070_green.png +stars.G.3.radius=3.8 +stars.G.3.color=00d000 +stars.B.1.image=stars/fca_027_blue.png +stars.B.1.radius=1.5 +stars.B.1.color=000098 +stars.B.2.image=stars/fca_037_blue.png +stars.B.2.radius=2.8 +stars.B.2.color=0000b8 +stars.B.3.image=stars/fca_070_blue.png +stars.B.3.radius=3.8 +stars.B.3.color=0000d0 +stars.O.1.image=stars/fca_027_orange.png +stars.O.1.radius=1.5 +stars.O.1.color=b86000 +stars.O.2.image=stars/fca_037_orange.png +stars.O.2.radius=2.8 +stars.O.2.color=d06800 +stars.O.3.image=stars/fca_070_orange.png +stars.O.3.radius=3.8 +stars.O.3.color=e8700 +stars.Y.1.image=stars/fca_027_yellow.png +stars.Y.1.radius=1.5 +stars.Y.1.color=b8b420 +stars.Y.2.image=stars/fca_037_yellow.png +stars.Y.2.radius=2.8 +stars.Y.2.color=d0ca28 +stars.Y.3.image=stars/fca_070_yellow.png +stars.Y.3.radius=3.8 +stars.Y.3.color=e8e430 +stars.W.1.image=stars/fca_027_white.png +stars.W.1.radius=1.5 +stars.W.1.color=c8c8c8 +stars.W.2.image=stars/fca_037_white.png +stars.W.2.radius=2.8 +stars.W.2.color=d8d8d8 +stars.W.3.image=stars/fca_070_white.png +stars.W.3.radius=3.8 +stars.W.3.color=f0f0f0 + +# Star Clusters + +clusters.definition=clusters.map +# font: Arial Narrow Bold +clusters.names.font.name=arialnb.ttf +clusters.names.font.size=7 +clusters.names.color=7aa2ef +clusters.lines.color=8181a9 +clusters.lines.weight=0.75 + +# Spheres of Influence + +sois.font.name=arialbd.ttf +sois.font.size=16 +sois.count=14 + +sois.1.name=EARTHLING +sois.1.color=f05015 +sois.1.font.size=9 +sois.1.center.x=177 +sois.1.center.y=144.5 +sois.1.radius=44 + +sois.2.name=CHENJESU +sois.2.color=6090e0 +sois.2.font.size=14 +sois.2.center.x=70 +sois.2.center.y=218 +sois.2.radius=64 + +sois.3.name=MMRNMHRM +sois.3.color=e0e0e0 +sois.3.font.size=9 +sois.3.center.x=68 +sois.3.center.y=294 +sois.3.radius=48 + +sois.4.name=ILWRATH +sois.4.color=E00040 +sois.4.font.size=5 +sois.4.center.x=-10 +sois.4.center.y=355 +sois.4.radius=53 + +sois.5.name=SPATHI +sois.5.color=f0f000 +sois.5.center.x=245 +sois.5.center.y=365 +sois.5.radius=100 + +sois.6.name=ANDROSYNTH +sois.6.color=e000f0 +sois.6.font.size=8 +sois.6.center.x=370 +sois.6.center.y=261 +sois.6.radius=49 + +sois.7.name=SHOFIXTI +sois.7.color=e07038 +sois.7.font.size=9 +sois.7.center.x=288 +sois.7.center.y=20 +sois.7.radius=37 + +sois.8.name=VUX +sois.8.color=00f060 +sois.8.center.x=431 +sois.8.center.y=153 +sois.8.radius=58 + +sois.9.name=YEHAT +sois.9.color=f0c010 +sois.9.center.x=495 +sois.9.center.y=5 +sois.9.radius=105 + +sois.10.name=MYCON +sois.10.color=c0a810 +sois.10.center.x=624 +sois.10.center.y=235 +sois.10.radius=56 + +sois.11.name=UMGAH +sois.11.color=30d0a0 +sois.11.center.x=185 +sois.11.center.y=608 +sois.11.radius=49 + +sois.12.name=UNKNOWN +sois.12.color=80b050 +sois.12.font.size=8 +sois.12.center.x=58 +sois.12.center.y=46 +sois.12.radius=35 + +sois.13.name=UNKNOWN +sois.13.color=80b050 +sois.13.font.size=14 +sois.13.center.x=945 +sois.13.center.y=275 +sois.13.radius=74 + +sois.14.name=UNKNOWN +sois.14.color=80b050 +sois.14.center.x=282 +sois.14.center.y=850 +sois.14.radius=73 diff --git a/tools/map/mapdrv.h b/tools/map/mapdrv.h new file mode 100755 index 000000000..5076967e8 --- /dev/null +++ b/tools/map/mapdrv.h @@ -0,0 +1,84 @@ +/* + * UQM Starmap image generator + * Output Driver decl + * + * The GPL applies + * + */ + +#include +#include +#include +#include "port.h" + +typedef struct +{ + uint8_t r, g, b, a; +} mg_color_t; + +typedef struct +{ + int x; + int y; +} mg_point_t; + +typedef struct +{ + double x; + double y; +} mg_pointf_t; + +typedef struct +{ + int x; + int y; + int w; + int h; +} mg_rect_t; + +typedef struct +{ + double x; + double y; + double w; + double h; +} mg_rectf_t; + +typedef struct mg_font *mg_font_t; +typedef struct mg_image *mg_image_t; + +typedef struct +{ + const char* name; + const char* description; + + // func ptrs + int (* init)(int argc, char *argv[]); + int (* term)(void); + void (* usage)(void); + int (* setResolution)(int dpi_x, int dpi_y); + int (* begin)(double w, double h); + int (* write)(void); + int (* end)(void); + mg_font_t (* loadFont)(const char* name, double size, const char* filename /* optional */); + void (* freeFont)(mg_font_t); + mg_image_t (* loadImage)(const char* filename); + void (* freeImage)(mg_image_t); + int (* getImageSize)(mg_image_t, mg_rectf_t* r); + + // draw func ptrs + void (* setClipRect)(const mg_rectf_t*); + void (* drawPixel)(double x, double y, mg_color_t, double weight); + void (* drawLine)(double x0, double y0, double x1, double y1, mg_color_t color, double weight); + void (* drawRect)(const mg_rectf_t* r, mg_color_t color, double weight); + void (* drawFilledRect)(const mg_rectf_t* r, mg_color_t color); + void (* drawEllipse)(double xc, double yc, double xr, double yr, mg_color_t color, double weight); + void (* drawFilledEllipse)(double xc, double yc, double xr, double yr, mg_color_t color); + void (* drawImage)(double x, double y, mg_image_t image); + void (* drawText)(mg_font_t, double x, double y, const unsigned char* utf8str, mg_color_t); + void (* getTextSize)(mg_font_t, const unsigned char* utf8str, mg_rectf_t* r); + +} mg_driver_t; + +extern void mg_verbose(int level, const char* fmt, ...); + diff --git a/tools/map/mapgen.c b/tools/map/mapgen.c new file mode 100755 index 000000000..09c87eb2a --- /dev/null +++ b/tools/map/mapgen.c @@ -0,0 +1,2034 @@ +/* + * UQM Starmap image generator + * By Alex Volkov (codepro@usa.net), 20060220 + * + * The GPL applies + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "port.h" +#include "scriptlib.h" +#include "unicode.h" +#include "mapdrv.h" + + +extern const mg_driver_t sdlpng_drv; + +static const mg_driver_t* drvs[] = +{ + &sdlpng_drv, + 0 /* term */ +}; +static const mg_driver_t* drv; + +typedef struct +{ + const char* infile; + const char* driver; + int verbose; + +} options_t; + +typedef struct +{ + mg_image_t img; + mg_pointf_t hot; + char color; + int size; + double radius; + mg_color_t rend_color; // alternate rendering +} star_image_t; + +typedef struct +{ + char cluster[128]; + int prefix; + mg_pointf_t pos; + char color; + int size; +} star_t; + +typedef star_t* cluster_conn_t[2]; + +typedef struct +{ + int first; + int cstars; + int text_dx, text_dy; + mg_pointf_t center; + int cconns; + cluster_conn_t conns[20]; +} cluster_t; + +typedef struct +{ + const char* name; + mg_pointf_t center; + double radius; + mg_color_t clr; + mg_font_t font; +} soi_t; + +typedef enum +{ + sht_Null = 0, + sht_Point, + sht_Line, + sht_Rect, + sht_Ellipse, + +} shape_type_t; + +typedef struct +{ + shape_type_t type; + mg_pointf_t pt0; + mg_pointf_t pt1; + double radiusx; + double radiusy; + +} shape_t; + +typedef enum +{ + objt_Null = 0, + objt_Sphere = (1 << 0), + objt_SphereText = (1 << 1), + objt_Star = (1 << 2), + objt_ClusterLine = (1 << 3), + objt_ClusterText = (1 << 4), + objt_Designation = (1 << 5), + + objt_DesigPlacement = + objt_Star | + objt_ClusterLine | + objt_Designation, + + objt_TextPlacement = + objt_Star | + objt_ClusterLine | + objt_ClusterText | + objt_Designation, + +} obj_type_t; + +typedef struct +{ + obj_type_t type; + shape_t shape; + +} object_t; + +typedef struct +{ + unsigned char str[8]; +} desig_char_t; + +typedef struct +{ + unsigned char name[32]; +} layer_t; + +typedef struct +{ + int dpix; + int dpiy; + // all doubles represent inches + double w; + double h; + + mg_color_t backclr; + + layer_t* layers; + int clayers; + + int gridmx; // max grid coordinates + int gridmy; + int grids1; // grid steps; 1: numbers + int grids2; // 2: grid lines + int grids3; // 3: smaller marks + mg_rectf_t gridr; + mg_color_t gridclr; + mg_color_t gridmclr; + mg_font_t gridfnt; + double gridbw; // box weight + double gridlw; // lines weight + + const char* starclrs; + int starsizes; + star_image_t* starimgs; + int cstarimgs; + star_t* stars; + int cstars; + + cluster_t* clusters; + int cclusters; + mg_color_t clustclr; + double clustlw; // lines weight + mg_font_t cnamefnt; + mg_color_t cnameclr; + + mg_font_t desigfnt; + mg_color_t desigclr; + desig_char_t* desigtab; + int cdesigtab; + + soi_t* sois; + int csois; + const char* soifont; + double soifontsize; + + object_t* objs; + int cobjs; + int objalloc; + +} script_t; + +int verbose_level = 0; +void mg_verbose(int level, const char* fmt, ...); +static void parseArguments(int argc, char* argv[], options_t* opts); + +static const mg_driver_t* findDriver(const char* name); + +static int readScript(script_t*, FILE*); +static void freeScript(script_t*); +static object_t* addObject(script_t*, obj_type_t, shape_type_t, double x0, double y0, + double x1, double y1, double rx, double ry); + +static void drawLayers(const mg_driver_t*, script_t*); +static void drawGrid(const mg_driver_t*, script_t*); +static void drawStars(const mg_driver_t*, script_t*); +static void drawStarDesignations(const mg_driver_t*, script_t*); +static void drawClusterLines(const mg_driver_t*, script_t*); +static void drawClusterNames(const mg_driver_t*, script_t*); +static void drawSpheres(const mg_driver_t*, script_t*); +static void drawSphereNames(const mg_driver_t*, script_t*); + +static const struct map_layer +{ + const char* name; + void (* draw)(const mg_driver_t*, script_t*); +} +map_layers[] = +{ + {"grid", drawGrid}, + {"sois", drawSpheres}, + {"soinames", drawSphereNames}, + {"clusters", drawClusterLines}, + {"cnames", drawClusterNames}, + {"stars", drawStars}, + {"starnums", drawStarDesignations}, + + {0, 0} // term +}; + +int main(int argc, char *argv[]) +{ + int ret = EXIT_FAILURE; + options_t opts; + script_t scr; + FILE* fin = NULL; + + memset(&scr, 0, sizeof(scr)); + + parseArguments(argc, argv, &opts); + verbose_level = opts.verbose; + + if (!opts.driver) + opts.driver = "sdlpng"; // default + + drv = findDriver(opts.driver); + if (!drv) + { + mg_verbose(1, "Driver '%s' not found\n", opts.driver); + return EXIT_FAILURE; + } + + mg_verbose(2, "Using driver %s -- %s\n", drv->name, drv->description); + + do + { + if (opts.infile) + { + fin = fopen(opts.infile, "rt"); + if (!fin) + { + mg_verbose(1, "Cannot open file '%s' -- %s\n", opts.infile, strerror(errno)); + break; + } + } + else + { + fin = stdin; + } + + ret = drv->init(argc, argv); + if (ret) + { + mg_verbose(1, "Driver '%s' failed to initialize\n", drv->name); + break; + } + + if (readScript(&scr, fin)) + { + mg_verbose(1, "Cannot process input script -- %s\n", strerror(errno)); + break; + } + + ret = drv->begin(scr.w, scr.h); + if (ret) + { + mg_verbose(1, "Driver '%s' could not start\n"); + break; + } + + drv->drawFilledRect(NULL, scr.backclr); + +#if 0 + drawSpheres(drv, &scr); + drawGrid(drv, &scr); + drawSphereNames(drv, &scr); + drawClusterLines(drv, &scr); + drawStars(drv, &scr); + drawStarDesignations(drv, &scr); + drawClusterNames(drv, &scr); +#endif + drawLayers(drv, &scr); + + +#if 0 + { + int w = 7; + void drawLine(SDL_Surface* dst, int x0, int y0, int x1, int y1, Uint32 color, int weight); + + drawLine(img, 100, 3500, 150, 3300, 0xffffffff, w); + drawLine(img, 100, 3550, 150, 3490, 0xffffffff, w); + drawLine(img, 100, 3575, 150, 3525, 0xffffffff, w); + drawLine(img, 100, 3600, 200, 3570, 0xffffffff, w); + drawLine(img, 100, 3650, 200, 3680, 0xffffffff, w); + drawLine(img, 100, 3675, 150, 3725, 0xffffffff, w); + drawLine(img, 100, 3700, 150, 3760, 0xffffffff, w); + drawLine(img, 100, 3750, 150, 3950, 0xffffffff, w); + } +#endif + + drv->write(); + drv->end(); + + ret = EXIT_SUCCESS; + } while (0); + + freeScript(&scr); + + if (fin) + fclose(fin); + drv->term(); + + return ret; +} + +void mg_verbose(int level, const char* fmt, ...) +{ + va_list args; + + if (verbose_level < level) + return; + + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); +} + +static void usage() +{ + fprintf(stderr, + "mapgen [-i ] [-d ] [driver options]\n" + "Options:\n" + "\t-i input script file; stdin when none\n" + "\t-d use ; default is sdlpng\n" + "\t-v increase verbosity level (use more than once)\n" + "mapgen -d -h [to see driver options]\n" + ); +} + +static void parseArguments(int argc, char *argv[], options_t *opts) +{ + char ch; + + opterr = 0; + memset(opts, 0, sizeof (options_t)); + + while (-1 != (ch = getopt(argc, argv, "-h?vi:d:"))) + { + switch (ch) + { + case 'i': + opts->infile = optarg; + break; + case 'f': + break; + case 'd': + opts->driver = optarg; + break; + case 'n': + break; + case 'v': + opts->verbose++; + break; + case '?': + if (optopt != '?') + { // unknown option -- let driver handle it + break; + } + case 'h': + { + const mg_driver_t* drv = findDriver(opts->driver); + usage(); + if (drv) + drv->usage(); + exit(EXIT_FAILURE); + } + default: + // non-option -- probably an arg to unknown option + ; + } + } + optind = 1; // let the driver handle the rest +} + +static const mg_driver_t* findDriver(const char* name) +{ + const mg_driver_t** d; + + if (!name) + return 0; + + for (d = drvs; *d && strcmp((*d)->name, name) != 0; ++d) + ; + + return *d; +} + +static void parseColor(mg_color_t* clr, const char* key, uint32_t def) +{ + uint32_t cv; + const char* v = scr_GetString(key); + if (!v || 1 != sscanf(v, "%x", &cv)) + cv = def; + clr->r = (cv >> 16) & 0xff; + clr->g = (cv >> 8) & 0xff; + clr->b = (cv ) & 0xff; + clr->a = 0xff; +} + +static int parseFont(mg_font_t* fnt, const char* key) +{ + char buf[128]; + const char* name; + double size; + + sprintf(buf, "%s.name", key); + name = scr_GetString(buf); + if (!name) + return 0; + sprintf(buf, "%s.size", key); + size = scr_GetFloatDef(buf, 10) / 64.0; + + *fnt = drv->loadFont(name, size, name); + + return *fnt != NULL; +} + +static void freeFont(mg_font_t* fnt) +{ + if (!fnt) + return; + + drv->freeFont(*fnt); + *fnt = NULL; +} + +static layer_t* loadLayers(const char* key, int* count) +{ + layer_t* tab; + char buf[256]; + int i, max = 32; + char* sl; + layer_t* l; + + *count = 0; + + strcpy(buf, scr_GetStringDef(key, + "sois,grid,soinames,clusters,stars,starnums,cnames")); + + tab = calloc(max, sizeof(*tab)); + if (!tab) + return 0; + + for (i = 0, sl = strtok(buf, ","), l = tab; i < max && sl; + ++i, ++l, sl = strtok(0, ",")) + { + strcpy(l->name, sl); + } + + *count = i; + + return tab; +} + +static desig_char_t* loadDesignations(const char* key, int* count) +{ + const char* name; + FILE* f; + char buf[256] = ""; + char* end; + int len; + desig_char_t* tab; + const unsigned char* p; + int i; + + *count = 0; + + name = scr_GetString(key); + if (!name) + return 0; + + f = fopen(name, "rt"); + if (!f) + { + mg_verbose(1, "Cannot open '%s' -- %s\n", name, strerror(errno)); + return 0; + } + fgets(buf, sizeof(buf), f); + end = strchr(buf, '\n'); + if (end) + *end = '\0'; + fclose(f); + + len = utf8StringCount(buf); + tab = calloc(len, sizeof(desig_char_t)); + if (!tab) + { + mg_verbose(1, "Out of memory\n"); + return 0; + } + + for (i = 0, p = buf; i < len; ++i) + { + const unsigned char* prev = p; + int cl; + + getCharFromString(&p); + cl = p - prev; + memcpy(tab[i].str, prev, cl); + tab[i].str[cl] = '\0'; + } + + *count = len; + + return tab; +} + +static star_image_t* loadStarImages(const char* key, const char* colors, int sizes, int* count) +{ + star_image_t* tab; + int ccolors = strlen(colors); + const char* c; + int s; + star_image_t* img; + + *count = 0; + if (!ccolors || !sizes) + return 0; + + tab = calloc(ccolors * sizes, sizeof(*tab)); + if (!tab) + return 0; + + for (c = colors, img = tab; *c; ++c) + { + char starkey[256]; + char buf[300]; + + for (s = 1; s <= sizes; ++s, ++img) + { + const char* name; + mg_rectf_t r; + + sprintf(starkey, "%s.%c.%d", key, *c, s); + img->color = *c; + img->size = s - 1; + + sprintf(buf, "%s.image", starkey); + name = scr_GetString(buf); + if (name) + { + img->img = drv->loadImage(name); + if (img->img) + { + drv->getImageSize(img->img, &r); + img->hot.x = r.w / 2; + img->hot.y = r.h / 2; + } + } + + sprintf(buf, "%s.color", starkey); + parseColor(&img->rend_color, buf, 0); + + sprintf(buf, "%s.radius", starkey); + img->radius = scr_GetFloatDef(buf, 1) / 64.0; + } + } + + *count = ccolors * sizes; + + return tab; +} + +static int cmpStars(const void* elem1, const void* elem2) +{ + const star_t* star1 = (const star_t*)elem1; + const star_t* star2 = (const star_t*)elem2; + int ret; + + ret = strcmp(star1->cluster, star2->cluster); + if (ret != 0) + return ret; + + if (star1->prefix < star2->prefix) + return -1; + if (star1->prefix > star2->prefix) + return 1; + return 0; +} + +static int desigToPrefix(char desig) +{ + static const char* desigtab = "*ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + const char* cl = strchr(desigtab, toupper(desig)); + if (!cl || *cl == '\0') + return 0; + else + return cl - desigtab; +} + +static star_t* loadStars(const char* name, int* count) +{ + star_t* tab; + int tabsize; + int cstars; + FILE* f; + + *count = 0; + if (!name) + return 0; + + // grab more than we need to reduce reallocs + tabsize = 1000; + tab = malloc(tabsize * sizeof(*tab)); + if (!tab) + { + mg_verbose(1, "Out of memory\n"); + return 0; + } + memset(tab, 0, tabsize * sizeof(*tab)); + + f = fopen(name, "rt"); + if (!f) + { + mg_verbose(1, "Cannot open '%s' -- %s\n", name, strerror(errno)); + free(tab); + return 0; + } + + for (cstars = 0; !feof(f); ) + { + char buf[256]; + char dbuf[20]; + char cbuf[20]; + star_t* star; + + fgets(buf, sizeof(buf), f); + if (!buf[0] || buf[0] == '#') + continue; + + if (cstars >= tabsize) + { + tabsize += tabsize / 2; + tab = realloc(tab, tabsize * sizeof(*tab)); + if (!tab) + { + mg_verbose(1, "Out of memory\n"); + return 0; + } + } + star = tab + cstars; + + if (6 != sscanf(buf, "%127[^,\n\r],%19[^,\n\r],%lf,%lf,%19[^,\n\r],%d", + star->cluster, dbuf, &star->pos.x, &star->pos.y, + cbuf, &star->size)) + continue; + + star->prefix = desigToPrefix(dbuf[0]); + star->color = toupper(cbuf[0]); + star->size--; + + ++cstars; + ++star; + } + + fclose(f); + + tab = realloc(tab, cstars * sizeof(*tab)); + *count = cstars; + + // sort the stars + qsort(tab, cstars, sizeof(*tab), cmpStars); + + return tab; +} + +static cluster_t* initClusters(const star_t* stars, int cstars, int* count) +{ + int cclusters; + cluster_t* tab; + cluster_t* cluster; + int tabsize; + int i; + + *count = 0; + if (!stars || cstars == 0) + return 0; + + // grab more than we need to reduce reallocs + tabsize = 50; + tab = malloc(tabsize * sizeof(*tab)); + if (!tab) + { + mg_verbose(1, "Out of memory\n"); + return 0; + } + memset(tab, 0, tabsize * sizeof(*tab)); + + for (i = 0, cclusters = 0; i < cstars; ++i) + { + if (i > 0 && 0 == strcmp(stars[i].cluster, stars[i - 1].cluster)) + continue; + + // next cluster + if (cclusters > 0) + { // update last one + cluster = tab + cclusters - 1; + cluster->cstars = i - cluster->first; + } + + if (cclusters >= tabsize) + { + int newsize = tabsize + tabsize / 2; + tab = realloc(tab, newsize * sizeof(*tab)); + if (!tab) + { + mg_verbose(1, "Out of memory\n"); + return 0; + } + memset(tab + cclusters, 0, tabsize / 2 * sizeof(*tab)); + tabsize = newsize; + } + + cluster = tab + cclusters; + cluster->first = i; + + ++cclusters; + } + if (cclusters > 0) + { // update last one + cluster = tab + cclusters - 1; + cluster->cstars = i - cluster->first; + } + + tab = realloc(tab, cclusters * sizeof(*tab)); + *count = cclusters; + + // calc cluster centers + for (i = 0; i < cclusters; ++i) + { + int s; + double minx = 1000000000.0f, miny = 1000000000.0f; + double maxx = 0, maxy = 0; + + cluster = tab + i; + + for (s = 0; s < cluster->cstars; ++s) + { + const star_t* star = stars + cluster->first + s; + if (star->pos.x < minx) + minx = star->pos.x; + if (star->pos.x > maxx) + maxx = star->pos.x; + if (star->pos.y < miny) + miny = star->pos.y; + if (star->pos.y > maxy) + maxy = star->pos.y; + } + + cluster->center.x = (minx + maxx) / 2; + cluster->center.y = (miny + maxy) / 2; + } + + return tab; +} + +static cluster_t* findCluster(const char* cname, const script_t* scr) +{ + int i; + + for (i = 0; i < scr->cclusters && + strcmp(cname, scr->stars[scr->clusters[i].first].cluster) != 0; + ++i) + ; + if (i < scr->cclusters) + return scr->clusters + i; + else + return 0; +} + +static star_t* findStar(const char* cname, char desig, const script_t* scr) +{ + int i; + cluster_t* cluster; + int prefix; + + cluster = findCluster(cname, scr); + if (!cluster) + return 0; + + prefix = desigToPrefix(desig); + for (i = cluster->first; i < cluster->first + cluster->cstars && + scr->stars[i].prefix != prefix; + ++i) + ; + if (i < cluster->first + cluster->cstars) + return scr->stars + i; + else + return 0; +} + +static int loadClusters(const char* name, script_t* scr) +{ + FILE* f; + + if (!name) + return 0; + + f = fopen(name, "rt"); + if (!f) + { + mg_verbose(1, "Cannot open '%s' -- %s\n", name, strerror(errno)); + return 0; + } + + for ( ; !feof(f); ) + { + char buf[256]; + char* cname; + char* obuf; + char* pair; + char* next; + cluster_t* cluster; + int cconns; + + fgets(buf, sizeof(buf), f); + if (!buf[0] || buf[0] == '#') + continue; + + cname = buf; + next = strchr(cname, ','); + if (!next) + continue; + *next = '\0'; + obuf = next + 1; + next = strchr(obuf, ','); + if (next) + { + *next = '\0'; + pair = next + 1; + } + else + pair = 0; + + cluster = findCluster(cname, scr); + if (!cluster) + { + mg_verbose(2, "Cluster '%s' not found\n", cname); + continue; + } + + strupr(obuf); + if (strcmp(obuf, "N") == 0) + { + cluster->text_dx = 0; + cluster->text_dy = 1; + } + else if (strcmp(obuf, "NE") == 0) + { + cluster->text_dx = 1; + cluster->text_dy = 1; + } + else if (strcmp(obuf, "NW") == 0) + { + cluster->text_dx = -1; + cluster->text_dy = 1; + } + else if (strcmp(obuf, "S") == 0) + { + cluster->text_dx = 0; + cluster->text_dy = -1; + } + else if (strcmp(obuf, "SE") == 0) + { + cluster->text_dx = 1; + cluster->text_dy = -1; + } + else if (strcmp(obuf, "SW") == 0) + { + cluster->text_dx = -1; + cluster->text_dy = -1; + } + else if (strcmp(obuf, "E") == 0) + { + cluster->text_dx = 1; + cluster->text_dy = 0; + } + else if (strcmp(obuf, "W") == 0) + { + cluster->text_dx = -1; + cluster->text_dy = 0; + } + + for (cconns = 0; pair && cconns < (int)countof(cluster->conns); ) + { + next = strchr(pair, ','); + if (next) + next++; + + if (pair[0] != '\0' && pair[1] != '\0') + { + cluster->conns[cconns][0] = findStar(cname, toupper(pair[0]), scr); + cluster->conns[cconns][1] = findStar(cname, toupper(pair[1]), scr); + if (cluster->conns[cconns][0] && cluster->conns[cconns][1]) + ++cconns; + } + + pair = next; + } + cluster->cconns = cconns; + } + + fclose(f); + + return 1; +} + +static soi_t* loadSois(const char* key, int count, script_t* scr) +{ + soi_t* tab; + int i; + soi_t* soi; + + if (!key || !count) + return 0; + + tab = calloc(count, sizeof(*tab)); + if (!tab) + return 0; + + for (i = 1, soi = tab; i <= count; ++i, ++soi) + { + char buf[256]; + double fntsize; + + sprintf(buf, "%s.%d.%s", key, i, "name"); + soi->name = scr_GetString(buf); + if (!soi->name) + continue; + + sprintf(buf, "%s.%d.%s", key, i, "color"); + parseColor(&soi->clr, buf, 0); + sprintf(buf, "%s.%d.%s", key, i, "center.x"); + soi->center.x = scr_GetFloatDef(buf, 0); + sprintf(buf, "%s.%d.%s", key, i, "center.y"); + soi->center.y = scr_GetFloatDef(buf, 0); + sprintf(buf, "%s.%d.%s", key, i, "radius"); + soi->radius = scr_GetFloatDef(buf, 0); + sprintf(buf, "%s.%d.%s", key, i, "font.size"); + fntsize = scr_GetFloatDef(buf, scr->soifontsize) / 64.0; + soi->font = drv->loadFont(scr->soifont, fntsize, scr->soifont); + } + + return tab; +} + +static int readScript(script_t* scr, FILE* f) +{ + int ret = EXIT_SUCCESS; + + memset(scr, 0, sizeof(*scr)); + + scr_LoadFile(f); + + scr->dpix = scr_GetIntegerDef("image.dpi.x", 300); + scr->dpiy = scr_GetIntegerDef("image.dpi.y", 300); + + ret = drv->setResolution(scr->dpix, scr->dpiy); + if (ret) + { + mg_verbose(1, "Driver '%s' rejected resolution %dx%d\n", scr->dpix, scr->dpiy); + return ret; + } + + scr->w = scr_GetFloatDef("image.width", 297.0f / 25.4f); + scr->h = scr_GetFloatDef("image.height", 370.0f / 25.4f); + + parseColor(&scr->backclr, "image.backcolor", 0x200020); + + scr->layers = loadLayers("image.layers", &scr->clayers); + + scr->gridmx = scr_GetIntegerDef("grid.extent.x", 1000); + scr->gridmy = scr_GetIntegerDef("grid.extent.y", 1000); + scr->grids1 = scr_GetIntegerDef("grid.step.1", 100); + scr->grids2 = scr_GetIntegerDef("grid.step.2", 50); + scr->grids3 = scr_GetIntegerDef("grid.step.3", 10); + scr->gridr.x = scr_GetFloatDef("grid.origin.x", 1.0f); + scr->gridr.y = scr_GetFloatDef("grid.origin.y", 1.0f); + scr->gridr.w = scr_GetFloatDef("grid.width", 9.5f); + scr->gridr.h = scr_GetFloatDef("grid.height", 9.5f); + scr->gridbw = scr_GetFloatDef("grid.box.weight", 1.0f) / 64.0; + scr->gridlw = scr_GetFloatDef("grid.lines.weight", 0.75f) / 64.0; + parseFont(&scr->gridfnt, "grid.font"); + parseColor(&scr->gridclr, "grid.color", 0x9566cb); + parseColor(&scr->gridmclr, "grid.marks.color", 0x8771b6); + + scr->starclrs = scr_GetStringDef("stars.colors", ""); + scr->starsizes = scr_GetIntegerDef("stars.sizes", 0); + + parseColor(&scr->clustclr, "clusters.lines.color", 0x8181a9); + scr->clustlw = scr_GetFloatDef("clusters.lines.weight", 1.0f) / 64.0; + parseColor(&scr->cnameclr, "clusters.names.color", 0x7aa2ef); + parseFont(&scr->cnamefnt, "clusters.names.font"); + + parseColor(&scr->desigclr, "stars.desig.color", 0x989898); + parseFont(&scr->desigfnt, "stars.desig.font"); + + scr->desigtab = loadDesignations("stars.desig.table", &scr->cdesigtab); + + scr->starimgs = loadStarImages("stars", scr->starclrs, scr->starsizes, &scr->cstarimgs); + scr->stars = loadStars(scr_GetString("stars.definition"), &scr->cstars); + scr->clusters = initClusters(scr->stars, scr->cstars, &scr->cclusters); + loadClusters(scr_GetString("clusters.definition"), scr); + + scr->csois = scr_GetIntegerDef("sois.count", 0); + scr->soifont = scr_GetString("sois.font.name"); + scr->soifontsize = scr_GetFloatDef("sois.font.size", 16); + scr->sois = loadSois("sois", scr->csois, scr); + + return ret; +} + +static void freeMemory(void** ptr) +{ + if (*ptr) + free(*ptr); + *ptr = NULL; +} + +static void freeScript(script_t* scr) +{ + int i; + + freeFont(&scr->gridfnt); + freeFont(&scr->cnamefnt); + freeFont(&scr->desigfnt); + + // free SoI fonts + for (i = 0; i < scr->csois; ++i) + { + freeFont(&scr->sois[i].font); + } + + // free star images + for (i = 0; i < scr->cstarimgs; ++i) + { + if (scr->starimgs[i].img) + drv->freeImage(scr->starimgs[i].img); + scr->starimgs[i].img = 0; + } + + freeMemory(&scr->desigtab); + freeMemory(&scr->starimgs); + freeMemory(&scr->stars); + freeMemory(&scr->clusters); + freeMemory(&scr->sois); + freeMemory(&scr->objs); +} + +static void drawLayers(const mg_driver_t* dst, script_t* scr) +{ + int i; + layer_t* l; + + for (i = 0, l = scr->layers; i < scr->clayers; ++i, ++l) + { + int j; + const struct map_layer* map; + + for (j = 0, map = map_layers; + map->name && strcmp(map->name, l->name) != 0; + ++j, ++map) + ; + if (!map->name) + { + mg_verbose(1, "Warning: layer '%s' not defined\n", l->name); + continue; + } + + map->draw(dst, scr); + } +} + +static object_t* addObject(script_t* scr, obj_type_t otype, shape_type_t stype, + double x0, double y0, double x1, double y1, double rx, double ry) +{ + object_t* obj; + + if (!scr->objs) + { // prealloc something decent + int count = 2000; + scr->objs = calloc(count, sizeof(*scr->objs)); + if (!scr->objs) + return 0; + scr->objalloc = count; + } + else if (scr->cobjs >= scr->objalloc) + { // need more room + int count = scr->objalloc + scr->objalloc / 2; + object_t* newa = realloc(scr->objs, count * sizeof(*scr->objs)); + if (!newa) + return 0; + scr->objs = newa; + scr->objalloc = count; + } + + obj = scr->objs + scr->cobjs; + scr->cobjs++; + + obj->type = otype; + obj->shape.type = stype; + obj->shape.pt0.x = x0; + obj->shape.pt0.y = y0; + obj->shape.pt1.x = x1; + obj->shape.pt1.y = y1; + obj->shape.radiusx = rx; + obj->shape.radiusy = ry; + + return obj; +} + +static void shapeToBox(const shape_t* shp, mg_rectf_t* r) +{ + switch (shp->type) + { + case sht_Point: + r->w = r->h = 0; + r->x = shp->pt0.x; + r->y = shp->pt0.y; + break; + + case sht_Line: + case sht_Rect: + r->x = shp->pt0.x < shp->pt1.x ? shp->pt0.x : shp->pt1.x; + r->y = shp->pt0.y < shp->pt1.y ? shp->pt0.y : shp->pt1.y; + r->w = fabs(shp->pt0.x - shp->pt1.x); + r->h = fabs(shp->pt0.y - shp->pt1.y); + break; + + case sht_Ellipse: + r->x = shp->pt0.x - shp->radiusx; + r->y = shp->pt0.y - shp->radiusy; + r->w = shp->radiusx * 2; + r->h = shp->radiusy * 2; + break; + + default: + r->w = r->h = 0; + r->x = r->y = -1000; + } +} + +static int overlapBox(const mg_rectf_t* r1, const mg_rectf_t* r2) +{ + double dx, dy; + int overlap = 0; + + dx = r2->x - r1->x; + if ((dx >= 0 && dx <= r1->w) || (dx < 0 && -dx <= r2->w)) + overlap = 1; + + if (overlap) + { + dy = r2->y - r1->y; + if ((dy >= 0 && dy <= r1->h) || (dy < 0 && -dy <= r2->h)) + return 1; + } + + return 0; +} + +static inline int pointInBox(const mg_rectf_t* r, double x, double y) +{ + double dx = x - r->x; + double dy = y - r->y; + return dx >= 0 && dx < r->w && dy >= 0 && dy < r->h; +} + +static inline int coordSame(double c1, double c2) +{ +#define DIST_THRESH 0.0000001 + return fabs(c1 - c2) < DIST_THRESH; +} + +static inline int coordInRange(double c, double l0, double l1) +{ + double t; + if (l1 < l0) + { // swap ends + t = l0; + l0 = l1; + l1 = t; + } + return c >= l0 && c <= l1; +} + +static inline int pointOnLine(const shape_t* lin, double x, double y) +{ + double dx = lin->pt1.x - lin->pt0.x; + double dy = lin->pt1.y - lin->pt0.y; + double dl; + if (dx == 0 && dy == 0) + { // line is a point + return coordSame(x, lin->pt0.x) && coordSame(y, lin->pt0.y); + } + else if (dx == 0) + { // line is vertical + dl = (y - lin->pt0.y) / dy; + return coordSame(x, lin->pt0.x) && (dl >= 0 && dl <= 1.0); + } + + dl = (x - lin->pt0.x) / dx; + return coordSame(y, lin->pt0.y + dl * dy) && (dl >= 0 && dl <= 1.0); +} + +static inline int pointInEllipse(const shape_t* ell, double x, double y) +{ + double fy, radius_2; + double dist_2; + + x -= ell->pt0.x; + y -= ell->pt0.y; + + radius_2 = ell->radiusx * ell->radiusx; + fy = ell->radiusx / ell->radiusy; + + dist_2 = y * y * fy * fy + x * x; + + return dist_2 <= radius_2; +} + +static int overlapLine(const shape_t* lin1, const shape_t* lin2) +{ + const double dx1 = lin1->pt1.x - lin1->pt0.x; + const double dy1 = lin1->pt1.y - lin1->pt0.y; + const double dx2 = lin2->pt1.x - lin2->pt0.x; + const double dy2 = lin2->pt1.y - lin2->pt0.y; + const double v1t = dx2 * (lin1->pt0.y - lin2->pt0.y) - dy2 * (lin1->pt0.x - lin2->pt0.x); + const double v2t = dx1 * (lin1->pt0.y - lin2->pt0.y) - dy1 * (lin1->pt0.x - lin2->pt0.x); + const double dm = dy2 * dx1 - dx2 * dy1; // slope ratio + + if (dm == 0) + { // al least parallel + if (v1t == 0 || v2t == 0) + { // coinciding + const double cx1 = (lin1->pt0.x + lin1->pt1.x); + const double cx2 = (lin2->pt0.x + lin2->pt1.x); + const double cy1 = (lin1->pt0.y + lin1->pt1.y); + const double cy2 = (lin2->pt0.y + lin2->pt1.y); + + return (fabs(cx1 - cx2) <= fabs(dx1) + fabs(dx2) && + fabs(cy1 - cy2) <= fabs(dy1) + fabs(dy2) ); + } + return 0; + } + else + { + double v1 = v1t / dm; + double v2 = v2t / dm; + + return (v1 >= 0 && v1 <= 1) && (v2 >= 0 && v2 <= 1); + } +} + +static int overlapBoxWithLine(const mg_rectf_t* r, const shape_t* lin) +{ + double dx, dy, bc; + + // first the easy cases: obvious contained points + if (pointInBox(r, lin->pt0.x, lin->pt0.y) + || pointInBox(r, lin->pt1.x, lin->pt1.y)) + return 1; + + dx = lin->pt1.x - lin->pt0.x; + dy = lin->pt1.y - lin->pt0.y; + + if (dx == 0 && dy == 0) + { // line is a point + return 0; // point-in-box would catch it + } + else if (dx == 0) + { // line is vertical + // check if it crosses the rect completely, + // otherwise point-in-box would catch it + return (lin->pt0.x >= r->x) && (lin->pt0.x <= r->x + r->w) + && (r->y - lin->pt0.y) * (lin->pt1.y - (r->y + r->h)) >= 0; + } + else if (dy == 0) + { // line is horizontal + // check if it crosses the rect completely, + // otherwise point-in-box would catch it + return (lin->pt0.y >= r->y) && (lin->pt0.y <= r->y + r->h) + && (r->x - lin->pt0.x) * (lin->pt1.x - (r->x + r->w)) >= 0; + } + + // now check intercect with each of the 4 box-bounding lines + // non-parallel lines always intersect at *some* point in space + // we just check *which* point + bc = lin->pt0.y + (r->x - lin->pt0.x) / dx * dy; + if (coordInRange(bc, r->y, r->y + r->h)) + return 1; + + bc = lin->pt0.y + (r->x + r->w - lin->pt0.x) / dx * dy; + if (coordInRange(bc, r->y, r->y + r->h)) + return 1; + + bc = lin->pt0.x + (r->y - lin->pt0.y) / dy * dx; + if (coordInRange(bc, r->x, r->x + r->w)) + return 1; + + bc = lin->pt0.x + (r->y + r->h - lin->pt0.y) / dy * dx; + if (coordInRange(bc, r->x, r->x + r->w)) + return 1; + + return 0; +} + +static int overlapEllipseWithLine(const shape_t* ell, const shape_t* lin) +{ + shape_t l = *lin; + double dx = l.pt1.x - l.pt0.x; + double dy = l.pt1.y - l.pt0.y; + double fx, r, radius_2; + double a, b, c, d; + + // first the easy cases: obvious contained points + if (pointInEllipse(ell, lin->pt0.x, lin->pt0.y) + || pointInEllipse(ell, lin->pt1.x, lin->pt1.y)) + return 1; + + if (dx == 0 && dy == 0) + { // line is a point + return 0; // point-in-ellipse would catch it + } + else if (dx == 0) + { // line is vertical + // check if it crosses the ellipse completely, + // otherwise point-in-ellipse would catch it + return (lin->pt0.x >= ell->pt0.x - ell->radiusx) + && (lin->pt0.x <= ell->pt0.x + ell->radiusx) + && ((ell->pt0.y - ell->radiusy) - lin->pt0.y) + * (lin->pt1.y - (ell->pt0.y + ell->radiusy)) >= 0; + } + else if (dy == 0) + { // line is horizontal + // check if it crosses the ellipse completely, + // otherwise point-in-ellipse would catch it + return (lin->pt0.y >= ell->pt0.y - ell->radiusy) + && (lin->pt0.y <= ell->pt0.y + ell->radiusy) + && ((ell->pt0.x - ell->radiusx) - lin->pt0.x) + * (lin->pt1.x - (ell->pt0.x + ell->radiusx)) >= 0; + } + + // make center of ellipse origin + l.pt0.x -= ell->pt0.x; + l.pt0.y -= ell->pt0.y; + l.pt1.x -= ell->pt0.x; + l.pt1.y -= ell->pt0.y; + + // the (more or less) classic elliptic equation is + // (fx*x)^2 + (fy*y)^2 = r^2 (classic: fx=r/a, fy=r/b) + // we'll take b=r and transform + // (fx*x)^2 + y^2 = r^2 + r = ell->radiusy; + radius_2 = r * r; + fx = r / ell->radiusx; + // the classic line equation is + // y = b*x + c + b = dy / dx; + c = l.pt0.y - l.pt0.x * b; + + // (b*x + c)^2 = r^2 - fx^2*x^2 + // b^2*x^2 + 2*b*x*c + c^2 = r^2 - fx^2*x^2 + // (b^2+fx^2)x^2 + (2*b*c)x + (c^2-r^2) = 0 + a = b*b + fx*fx; + b = 2 * b * c; + c = c*c - r*r; + d = b*b - 4*a*c; + + if (d >= 0) + { + double root = sqrt(d); + double x; + + x = (-b + root) / (2*a); + if (coordInRange(x, l.pt0.x, l.pt1.x)) + return 1; + + x = (-b - root) / (2*a); + if (coordInRange(x, l.pt0.x, l.pt1.x)) + return 1; + } + + return 0; +} + +static int overlapBoxWithEllipse(const mg_rectf_t* r, const shape_t* ell) +{ + shape_t lin; + + // first the easy cases: obvious contained points + if (pointInBox(r, ell->pt0.x, ell->pt0.y) + || pointInEllipse(ell, r->x, r->y) + || pointInEllipse(ell, r->x + r->w, r->y) + || pointInEllipse(ell, r->x, r->y + r->h) + || pointInEllipse(ell, r->x + r->w, r->y + r->h)) + return 1; + + // now at least one rect-bounding line must intersect + // the ellipse, or no overlap + lin.pt0.x = r->x; + lin.pt1.x = r->x + r->w; + lin.pt0.y = lin.pt1.y = r->y; + if (overlapEllipseWithLine(ell, &lin)) + return 1; + + lin.pt0.y = lin.pt1.y = r->y + r->h; + if (overlapEllipseWithLine(ell, &lin)) + return 1; + + lin.pt0.y = r->y; + lin.pt1.y = r->y + r->h; + lin.pt0.x = lin.pt1.x = r->x; + if (overlapEllipseWithLine(ell, &lin)) + return 1; + + lin.pt0.x = lin.pt1.x = r->x + r->w; + if (overlapEllipseWithLine(ell, &lin)) + return 1; + + return 0; +} + +static int overlapEllipse(const shape_t* el1, const shape_t* el2) +{ + // This is mostly unfinished + // but it's not currently necessary for our application + double mr1, mr2; // major radius + double dx, dy; + double dist; + + // first the easy cases: obvious contained points + if (pointInEllipse(el1, el2->pt0.x, el2->pt0.y) + || pointInEllipse(el2, el1->pt1.x, el1->pt1.y)) + return 1; + + mr1 = el1->radiusx > el1->radiusy ? el1->radiusx : el1->radiusy; + mr2 = el2->radiusx > el2->radiusy ? el2->radiusx : el2->radiusy; + + // see if too far apart + dx = el2->pt0.x - el1->pt0.x; + dy = el2->pt0.y - el1->pt0.y; + dist = sqrt(dx*dx + dy*dy); + if (dist > mr1 + mr2) + return 0; // too far apart + + return 0; +} + +static int overlapShapes(const shape_t* obj1, const shape_t* obj2) +{ + mg_rectf_t r1, r2; + + shapeToBox(obj1, &r1); + shapeToBox(obj2, &r2); + + if (!overlapBox(&r1, &r2)) + return 0; + + switch (obj1->type) + { + case sht_Point: + if (obj2->type == sht_Line) + return pointOnLine(obj2, r1.x, r1.y); + if (obj2->type == sht_Ellipse) + return pointInEllipse(obj2, r1.x, r1.y); + // fallthrough + case sht_Rect: + if (obj2->type == sht_Point || obj2->type == sht_Rect) + return 1; // overlap is enough + if (obj2->type == sht_Line) + return overlapBoxWithLine(&r1, obj2); + if (obj2->type == sht_Ellipse) + return overlapBoxWithEllipse(&r1, obj2); + break; + + case sht_Line: + if (obj2->type == sht_Point) + return pointOnLine(obj1, r2.x, r2.y); + if (obj2->type == sht_Line) + return overlapLine(obj1, obj2); + if (obj2->type == sht_Rect) + return overlapBoxWithLine(&r2, obj1); + if (obj2->type == sht_Ellipse) + return overlapEllipseWithLine(obj2, obj1); + break; + + case sht_Ellipse: + if (obj2->type == sht_Point) + return pointInEllipse(obj1, r2.x, r2.y); + if (obj2->type == sht_Line) + return overlapEllipseWithLine(obj1, obj2); + if (obj2->type == sht_Rect) + return overlapBoxWithEllipse(&r2, obj1); + if (obj2->type == sht_Ellipse) + return overlapEllipse(obj1, obj2); + break; + + default: + ; + } + + return 0; +} + +static int isCollidingWith(const script_t* scr, const shape_t* shp, obj_type_t witht) +{ + int i; + object_t* testobj; + + for (i = 0, testobj = scr->objs; i < scr->cobjs; ++i, ++testobj) + { + if (!(testobj->type & witht)) + continue; + + if (overlapShapes(shp, &testobj->shape)) + return 1; + } + + return 0; +} + +static void imageToRectShape(const script_t* scr, const mg_image_t img, shape_t* shp) +{ + const double stepx = scr->gridr.w / scr->gridmx; + const double stepy = scr->gridr.h / scr->gridmy; + mg_rectf_t r; + + drv->getImageSize(img, &r); + shp->type = sht_Rect; + shp->pt0.x = 0; + shp->pt0.y = 0; + shp->pt1.x = r.w / stepx; + shp->pt1.y = r.h / stepy; +} + +static void boxToRectShape(const script_t* scr, const mg_rectf_t* r, shape_t* shp) +{ + const double stepx = scr->gridr.w / scr->gridmx; + const double stepy = scr->gridr.h / scr->gridmy; + + shp->type = sht_Rect; + shp->pt0.x = 0; + shp->pt0.y = 0; + shp->pt1.x = r->w / stepx; + shp->pt1.y = r->h / stepy; +} + + +static int isAlmostMod0(double x, double y) +{ +#undef DIST_THRESH +#define DIST_THRESH 0.000001 + double m = fmod(x, y); + return (m < DIST_THRESH || m > (y - DIST_THRESH)); +} + +static void drawGrid(const mg_driver_t* dst, script_t* scr) +{ + int i; + double x, y; + const double gxstep1 = scr->grids1 ? scr->gridr.w / (scr->gridmx / scr->grids1) : 0; + const double gystep1 = scr->grids1 ? scr->gridr.h / (scr->gridmy / scr->grids1) : 0; + const double gxstep2 = scr->grids2 ? scr->gridr.w / (scr->gridmx / scr->grids2) : 0; + const double gystep2 = scr->grids2 ? scr->gridr.h / (scr->gridmy / scr->grids2) : 0; + const double gxstep3 = scr->grids3 ? scr->gridr.w / (scr->gridmx / scr->grids3) : 0; + const double gystep3 = scr->grids3 ? scr->gridr.h / (scr->gridmy / scr->grids3) : 0; + const double gxl1 = scr->gridr.w / 120; + const double gyl1 = scr->gridr.h / 120; + const double gxl2 = scr->gridr.w / 180; + const double gyl2 = scr->gridr.h / 180; + const double gxl3 = scr->gridr.w / 240; + const double gyl3 = scr->gridr.h / 240; + const mg_rectf_t r = scr->gridr; + + // draw the box + dst->drawRect(&r, scr->gridclr, scr->gridbw); + + // draw grid lines + if (gxstep2) + { + for (x = r.x + gxstep2; x < r.x + r.w - gxstep2 / 2; x += gxstep2) + dst->drawLine(x, r.y, x, r.y + r.h, scr->gridclr, scr->gridlw); + for (y = r.y + gystep2; y < r.y + r.h - gystep2 / 2; y += gystep2) + dst->drawLine(r.x, y, r.x + r.w, y, scr->gridclr, scr->gridlw); + } + + // draw ruler markers + if (gxstep3) + { + for (x = r.x; x <= r.x + r.w; x += gxstep3) + { + if ((gxstep2 && isAlmostMod0(x - r.x, gxstep2)) || + (gxstep1 && isAlmostMod0(x - r.x, gxstep1))) + continue; + dst->drawLine(x, r.y - gyl3, x, r.y, scr->gridmclr, scr->gridlw); + dst->drawLine(x, r.y + r.h, x, r.y + r.h + gyl3, scr->gridmclr, scr->gridlw); + } + for (y = r.y; y <= r.y + r.h; y += gystep3) + { + if ((gystep2 && isAlmostMod0(y - r.y, gystep2)) || + (gystep1 && isAlmostMod0(y - r.y, gystep1))) + continue; + dst->drawLine(r.x - gxl3, y, r.x, y, scr->gridmclr, scr->gridlw); + dst->drawLine(r.x + r.w, y, r.x + r.w + gxl3, y, scr->gridmclr, scr->gridlw); + } + } + if (gxstep2) + { + for (x = r.x; x <= r.x + r.w; x += gxstep2) + { + if (gxstep1 && isAlmostMod0(x - r.x, gxstep1)) + continue; + dst->drawLine(x, r.y - gyl2, x, r.y, scr->gridmclr, scr->gridlw); + dst->drawLine(x, r.y + r.h, x, r.y + r.h + gyl2, scr->gridmclr, scr->gridlw); + } + for (y = r.y; y <= r.y + r.h; y += gystep2) + { + if (gystep1 && isAlmostMod0(y - r.y, gystep1)) + continue; + dst->drawLine(r.x - gxl2, y, r.x, y, scr->gridmclr, scr->gridlw); + dst->drawLine(r.x + r.w, y, r.x + r.w + gxl2, y, scr->gridmclr, scr->gridlw); + } + } + if (gxstep1) + { + for (x = r.x; x <= r.x + r.w; x += gxstep1) + { + dst->drawLine(x, r.y - gyl1, x, r.y, scr->gridmclr, scr->gridlw); + dst->drawLine(x, r.y + r.h, x, r.y + r.h + gyl1, scr->gridmclr, scr->gridlw); + } + for (y = r.y; y <= r.y + r.h; y += gystep1) + { + dst->drawLine(r.x - gxl1, y, r.x, y, scr->gridmclr, scr->gridlw); + dst->drawLine(r.x + r.w, y, r.x + r.w + gxl1, y, scr->gridmclr, scr->gridlw); + } + } + + // draw grid numbers + if (!scr->gridfnt || !gxstep1) + return; // nothing else to do + + for (i = 1, x = r.x + gxstep1; x < r.x + r.w - gxstep1 / 2; x += gxstep1, ++i) + { + mg_rectf_t tr; + char buf[20]; + + sprintf(buf, "%d", i * scr->grids1); + drv->getTextSize(scr->gridfnt, buf, &tr); + drv->drawText(scr->gridfnt, x - tr.w / 2, r.y - gyl1 - tr.h, buf, scr->gridclr); + drv->drawText(scr->gridfnt, x - tr.w / 2, r.y + r.h + gyl1 + tr.h / 6, buf, scr->gridclr); + } + for (i = 1, y = r.y + r.h - gystep1; y > r.y + gystep1 / 2; y -= gystep1, ++i) + { + mg_rectf_t tr; + char buf[20]; + + sprintf(buf, "%d", i * scr->grids1); + drv->getTextSize(scr->gridfnt, buf, &tr); + drv->drawText(scr->gridfnt, r.x - gxl1 - tr.w * 1.125, y - tr.h / 2, buf, scr->gridclr); + drv->drawText(scr->gridfnt, r.x + r.w + gxl1 + tr.w * 0.125, y - tr.h / 2, buf, scr->gridclr); + } +} + +static void drawStarsSize(const mg_driver_t* dst, script_t* scr, int size) +{ + int i; + const star_t* star; + const double orgx = scr->gridr.x; + const double orgy = scr->gridr.y + scr->gridr.h; + const double width = scr->gridr.w; + const double height = scr->gridr.h; + double stepx = width / scr->gridmx; + double stepy = height / scr->gridmy; + + for (i = 0, star = scr->stars; i < scr->cstars; ++i, ++star) + { + const char* cl; + int iclr; + const star_image_t* img; + + if (star->size != size) + continue; + + cl = strchr(scr->starclrs, star->color); + if (!cl) + continue; // cannot draw this color star + iclr = cl - scr->starclrs; + + img = scr->starimgs + iclr * scr->starsizes + star->size; + if (img->img) + { // use image + dst->drawImage(orgx + star->pos.x * stepx - img->hot.x, + orgy - star->pos.y * stepy - img->hot.y, + img->img); + } + else + { // this star image is not present, or not drawn + dst->drawFilledEllipse( + orgx + star->pos.x * stepx, + orgy - star->pos.y * stepy, + img->radius, img->radius, img->rend_color); + } + + // register an elliptical grid object + addObject(scr, objt_Star, sht_Ellipse, star->pos.x, star->pos.y, + 0, 0, img->radius / stepx, img->radius / stepy); + + } + +} + +static void drawStars(const mg_driver_t* dst, script_t* scr) +{ + int i; + int max = 0; + star_t* star; + + if (!scr->stars || !scr->starimgs || scr->cstarimgs == 0) + { + mg_verbose(2, "Warning: not enough data to render stars\n"); + return; + } + + // find max star size + for (i = 0, star = scr->stars; i < scr->cstars; ++i, ++star) + { + // make sure the star is not too big for us + if (star->size >= scr->starsizes) + star->size = scr->starsizes - 1; + + if (star->size > max) + max = star->size; + } + + // draw stars from larger to smaller + for (i = max; i >= 0; --i) + drawStarsSize(dst, scr, i); +} + +static void drawClusterLines(const mg_driver_t* dst, script_t* scr) +{ + const double orgx = scr->gridr.x; + const double orgy = scr->gridr.y + scr->gridr.h; + const double width = scr->gridr.w; + const double height = scr->gridr.h; + double stepx = width / scr->gridmx; + double stepy = height / scr->gridmy; + int i1; + int i2; + + if (!scr->clusters) + { + mg_verbose(2, "Warning: not enough data to render cluster lines\n"); + return; + } + + for (i1 = 0; i1 < scr->cclusters; ++i1) + { + cluster_t* cluster = scr->clusters + i1; + + for (i2 = 0; i2 < cluster->cconns; ++i2) + { + star_t* star1 = cluster->conns[i2][0]; + star_t* star2 = cluster->conns[i2][1]; + + dst->drawLine( + orgx + star1->pos.x * stepx, orgy - star1->pos.y * stepy, + orgx + star2->pos.x * stepx, orgy - star2->pos.y * stepy, + scr->clustclr, scr->clustlw); + + // register a line grid object + addObject(scr, objt_ClusterLine, sht_Line, + star1->pos.x, star1->pos.y, + star2->pos.x, star2->pos.y, + 0, 0); + } + } +} + +static void drawClusterNames(const mg_driver_t* dst, script_t* scr) +{ + int i; + const double orgx = scr->gridr.x; + const double orgy = scr->gridr.y + scr->gridr.h; + const double width = scr->gridr.w; + const double height = scr->gridr.h; + const double stepx = width / scr->gridmx; + const double stepy = height / scr->gridmy; + + if (!scr->stars || !scr->clusters) + { + mg_verbose(2, "Warning: not enough data to render cluster names\n"); + return; + } + + // draw cluster names + for (i = 0; i < scr->cclusters; ++i) + { + const cluster_t* cluster = scr->clusters + i; + shape_t shp; + mg_rectf_t r; + + r.x = r.y = 0; + dst->getTextSize(scr->cnamefnt, scr->stars[cluster->first].cluster, &r); + + boxToRectShape(scr, &r, &shp); + shp.pt0.x += cluster->center.x - shp.pt1.x / 2; + shp.pt0.y += cluster->center.y - shp.pt1.y / 2; + shp.pt1.x += shp.pt0.x; + shp.pt1.y += shp.pt0.y; + if (isCollidingWith(scr, &shp, objt_TextPlacement)) + continue; + + dst->drawText(scr->cnamefnt, + orgx + cluster->center.x * stepx - r.w / 2, + orgy - cluster->center.y * stepy - r.h / 2, + scr->stars[cluster->first].cluster, + scr->cnameclr); + + // register a rect grid object + addObject(scr, objt_ClusterText, sht_Rect, + shp.pt0.x, shp.pt0.y, shp.pt1.x, shp.pt1.y, + 0, 0); + } +} + +static void drawStarDesignations(const mg_driver_t* dst, script_t* scr) +{ + int i; + const double orgx = scr->gridr.x; + const double orgy = scr->gridr.y + scr->gridr.h; + const double width = scr->gridr.w; + const double height = scr->gridr.h; + double stepx = width / scr->gridmx; + double stepy = height / scr->gridmy; + + if (!scr->stars || !scr->desigtab || scr->cdesigtab == 0 || !scr->clusters) + { + mg_verbose(2, "Warning: not enough data to render star designations\n"); + return; + } + + // draw designations + for (i = 0; i < scr->cclusters; ++i) + { + const cluster_t* cluster = scr->clusters + i; + int s; + + for (s = 0; s < cluster->cstars; ++s) + { + const star_t* star = scr->stars + cluster->first + s; + double dx, dy; + double length; + double sinl, cosl; + double ofsx, ofsy; + shape_t shp; + const unsigned char* sdesig; + mg_rectf_t r; + + if (!star->prefix) + continue; // no designation + + sdesig = scr->desigtab[star->prefix - 1].str; + r.x = r.y = 0; + dst->getTextSize(scr->desigfnt, sdesig, &r); + + dx = star->pos.x - cluster->center.x; + dy = star->pos.y - cluster->center.y; + length = sqrt(dx*dx + dy*dy); + sinl = dy / length; + cosl = dx / length; + + ofsx = (r.w * cosl); + ofsy = (r.h * sinl); + + boxToRectShape(scr, &r, &shp); + shp.pt0.x += star->pos.x + shp.pt1.x * cosl - shp.pt1.x / 2; + shp.pt0.y += star->pos.y + shp.pt1.y * sinl - shp.pt1.y / 2; + shp.pt1.x += shp.pt0.x; + shp.pt1.y += shp.pt0.y; + if (isCollidingWith(scr, &shp, objt_DesigPlacement)) + continue; + + dst->drawText(scr->desigfnt, + orgx + (star->pos.x * stepx + ofsx) - r.w / 2, + orgy - (star->pos.y * stepy + ofsy) - r.h / 2, + sdesig, scr->desigclr); + + // register a rect grid object + addObject(scr, objt_Designation, sht_Rect, + shp.pt0.x, shp.pt0.y, shp.pt1.x, shp.pt1.y, + 0, 0); + } + } +} + +static void drawSphereNames(const mg_driver_t* dst, script_t* scr) +{ + int i; + soi_t* soi; + const double orgx = scr->gridr.x; + const double orgy = scr->gridr.y + scr->gridr.h; + const double width = scr->gridr.w; + const double height = scr->gridr.h; + double stepx = width / scr->gridmx; + double stepy = height / scr->gridmy; + + if (!scr->sois) + { + mg_verbose(2, "Warning: not enough data to render Spheres of Influence\n"); + return; + } + + dst->setClipRect(&scr->gridr); + + for (i = 0, soi = scr->sois; i < scr->csois; ++i, ++soi) + { + shape_t shp; + mg_rectf_t r; + double dstx, dsty; + mg_color_t clr = scr->backclr; + + if (!soi->name) + continue; + + r.x = r.y = 0; + dst->getTextSize(soi->font, soi->name, &r); + + dstx = orgx + soi->center.x * stepx - r.w / 2; + dsty = orgy - soi->center.y * stepy - r.h / 2; + // make sure the text is all within the grid + if (dstx < scr->gridr.x + stepx) + dstx = scr->gridr.x + stepx; + else if (dstx + r.w > scr->gridr.x + scr->gridr.w - stepx) + dstx = scr->gridr.x + scr->gridr.w - stepx - r.w; + if (dsty < scr->gridr.y) + dsty = scr->gridr.y; + else if (dsty + r.h > scr->gridr.y + scr->gridr.h) + dsty = scr->gridr.y + scr->gridr.h - r.h; + + //soi->clr + clr.a = 0x80; + dst->drawText(soi->font, dstx, dsty, soi->name, clr); + + // register a rect grid object + boxToRectShape(scr, &r, &shp); + shp.pt0.x += soi->center.x - shp.pt1.x / 2; + shp.pt0.y += soi->center.y - shp.pt1.y / 2; + shp.pt1.x += shp.pt0.x; + shp.pt1.y += shp.pt0.y; + addObject(scr, objt_SphereText, sht_Rect, + shp.pt0.x, shp.pt0.y, shp.pt1.x, shp.pt1.y, + 0, 0); + } + + dst->setClipRect(0); +} + +static void drawSpheres(const mg_driver_t* dst, script_t* scr) +{ + int i; + soi_t* soi; + const double orgx = scr->gridr.x; + const double orgy = scr->gridr.y + scr->gridr.h; + const double width = scr->gridr.w; + const double height = scr->gridr.h; + double stepx = width / scr->gridmx; + double stepy = height / scr->gridmy; + + if (!scr->sois) + { + mg_verbose(2, "Warning: not enough data to render Spheres of Influence\n"); + return; + } + + dst->setClipRect(&scr->gridr); + + for (i = 0, soi = scr->sois; i < scr->csois; ++i, ++soi) + { + mg_color_t clr = soi->clr; + double x, y, xr, yr; + + clr.a = 0x40; + x = orgx + soi->center.x * stepx; + y = orgy - soi->center.y * stepy; + xr = soi->radius * stepx; + yr = soi->radius * stepy; + dst->drawFilledEllipse(x, y, xr, yr, clr); + dst->drawEllipse(x, y, xr, yr, clr, 1.0 / 128); + + // register an elliptical grid object + addObject(scr, objt_Sphere, sht_Ellipse, + soi->center.x, soi->center.y, 0, 0, + soi->radius, soi->radius); + } + + dst->setClipRect(0); +} diff --git a/tools/map/mapgen.dsp b/tools/map/mapgen.dsp new file mode 100755 index 000000000..456ff0fb2 --- /dev/null +++ b/tools/map/mapgen.dsp @@ -0,0 +1,178 @@ +# Microsoft Developer Studio Project File - Name="mapgen" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=mapgen - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "mapgen.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "mapgen.mak" CFG="mapgen - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "mapgen - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "mapgen - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=xicl6.exe +RSC=rc.exe + +!IF "$(CFG)" == "mapgen - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\src\getopt" /I "." /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "PNG_USE_DLL" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=xilink6.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib advapi32.lib shell32.lib libpng.lib SDLmain.lib SDL.lib SDL_image.lib SDL_ttf.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "mapgen - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MD /W3 /Gm /GX /ZI /Od /I "..\..\src\getopt" /I "." /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "PNG_USE_DLL" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=xilink6.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib advapi32.lib shell32.lib libpng.lib SDLmain.lib SDL.lib SDL_image.lib SDL_ttf.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "mapgen - Win32 Release" +# Name "mapgen - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\alist.c +# End Source File +# Begin Source File + +SOURCE=.\alist.h +# End Source File +# Begin Source File + +SOURCE=.\config.h +# End Source File +# Begin Source File + +SOURCE=..\..\src\getopt\getopt.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\getopt\getopt.h +# End Source File +# Begin Source File + +SOURCE=.\mapdrv.h +# End Source File +# Begin Source File + +SOURCE=.\mapgen.c +# End Source File +# Begin Source File + +SOURCE=.\port.h +# End Source File +# Begin Source File + +SOURCE=.\scriptlib.c +# End Source File +# Begin Source File + +SOURCE=.\scriptlib.h +# End Source File +# Begin Source File + +SOURCE=.\SDL_gfxPrimitives.c +# End Source File +# Begin Source File + +SOURCE=.\SDL_gfxPrimitives.h +# End Source File +# Begin Source File + +SOURCE=.\sdlpngdrv.c +# End Source File +# Begin Source File + +SOURCE=.\stringbank.c +# End Source File +# Begin Source File + +SOURCE=.\stringbank.h +# End Source File +# Begin Source File + +SOURCE=.\unicode.c +# End Source File +# Begin Source File + +SOURCE=.\unicode.h +# End Source File +# End Group +# Begin Group "Map Files" + +# PROP Default_Filter "*.map" +# Begin Source File + +SOURCE=.\clusters.map +# End Source File +# Begin Source File + +SOURCE=.\greek.map +# End Source File +# Begin Source File + +SOURCE=.\large300.map +# End Source File +# Begin Source File + +SOURCE=.\stars.map +# End Source File +# End Group +# End Target +# End Project diff --git a/tools/map/port.h b/tools/map/port.h new file mode 100755 index 000000000..455bfd92e --- /dev/null +++ b/tools/map/port.h @@ -0,0 +1,18 @@ +#ifndef _PORT_H +#define _PORT_H + +#if defined(WIN32) && defined(_MSC_VER) +# include +# include +# define inline __inline +#else +# include +#endif +#if defined(__GNUC__) +# define inline __inline__ +#endif + +#define countof(a) ( sizeof(a)/sizeof(*a) ) + +#endif /* _PORT_H */ + diff --git a/tools/map/scriptlib.c b/tools/map/scriptlib.c new file mode 100755 index 000000000..d878f0943 --- /dev/null +++ b/tools/map/scriptlib.c @@ -0,0 +1,253 @@ +/* Copyright (c) 2005 Michael C. Martin */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope thta it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Se the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include "scriptlib.h" +#include "alist.h" +#include "stringbank.h" + +static alist *map = NULL; + +static void +check_map_init (void) +{ + if (map == NULL) { + map = Alist_New (); + } +} + +void +scr_ClearTables (void) +{ + if (map != NULL) { + Alist_Free (map); + map = NULL; + } +} + +/* Type conversion routines. */ +static const char * +bool2str (bool b) +{ + return b ? "yes" : "no"; +} + +static const char * +int2str (int i) { + char buf[20]; + sprintf (buf, "%d", i); + return StringBank_AddOrFindString (buf); +} + +static int +str2int (const char *s) { + return atoi(s); +} + +static float +str2float (const char *s) { + return (float) atof(s); +} + +static bool +str2bool (const char *s) { + if (!stricmp (s, "yes") || + !stricmp (s, "true") || + !stricmp (s, "1") ) + return true; + return false; +} + +void +scr_LoadFile (FILE *s) +{ + alist *d; + check_map_init (); + + d = Alist_New_FromFile (s); + if (d) { + Alist_PutAll (map, d); + Alist_Free (d); + } +} + +void +scr_LoadFilename (const char *fname) +{ + alist *d; + check_map_init (); + + d = Alist_New_FromFilename (fname); + if (d) { + Alist_PutAll (map, d); + Alist_Free (d); + } +} + +void +scr_SaveFile (FILE *f, const char *root) +{ + check_map_init (); + Alist_Dump (map, f, root); +} + +void +scr_SaveFilename (const char *fname, const char *root) +{ + FILE *f; + + check_map_init (); + f = fopen (fname, "wt"); + if (f) { + scr_SaveFile (f, root); + fclose (f); + } +} + +bool +scr_IsBoolean (const char *key) +{ + const char *d; + check_map_init (); + + d = scr_GetString (key); + if (!d) return 0; + + return !stricmp (d, "yes") || + !stricmp (d, "no") || + !stricmp (d, "true") || + !stricmp (d, "false") || + !stricmp (d, "0") || + !stricmp (d, "1") || + !stricmp (d, ""); +} + +bool +scr_IsInteger (const char *key) +{ + const char *d; + check_map_init (); + + d = scr_GetString (key); + while (*d) { + if (!isdigit (*d)) + return 0; + d++; + } + return 1; +} + +const char * +scr_GetString (const char *key) +{ + check_map_init (); + return Alist_GetString (map, key); +} + +const char * +scr_GetStringDef (const char *key, const char *def) +{ + const char *v; + check_map_init (); + + v = scr_GetString (key); + if (!v) + v = def; + return v; +} + +void +scr_PutString (const char *key, const char *value) +{ + check_map_init (); + Alist_PutString (map, key, value); +} + +int +scr_GetInteger (const char *key) +{ + check_map_init (); + return str2int (scr_GetString (key)); +} + +int +scr_GetIntegerDef (const char *key, int def) +{ + const char *v; + check_map_init (); + + v = scr_GetString (key); + return v ? str2int (v) : def; +} + +void +scr_PutInteger (const char *key, int value) +{ + check_map_init (); + scr_PutString (key, int2str(value)); +} + +float +scr_GetFloat (const char *key) +{ + check_map_init (); + return str2float (scr_GetString (key)); +} + +float +scr_GetFloatDef (const char *key, float def) +{ + const char *v; + check_map_init (); + + v = scr_GetString (key); + return v ? str2float (v) : def; +} + +bool +scr_GetBoolean (const char *key) +{ + check_map_init (); + return str2bool (scr_GetString (key)); +} + +bool +scr_GetBooleanDef (const char *key, bool def) +{ + const char *v; + check_map_init (); + + v = scr_GetString (key); + return v ? str2bool (v) : def; +} + +void +scr_PutBoolean (const char *key, bool value) +{ + check_map_init (); + scr_PutString (key, bool2str(value)); +} + +bool +scr_HasKey (const char *key) +{ + check_map_init (); + return (scr_GetString (key) != NULL); +} diff --git a/tools/map/scriptlib.h b/tools/map/scriptlib.h new file mode 100755 index 000000000..9d67680f7 --- /dev/null +++ b/tools/map/scriptlib.h @@ -0,0 +1,57 @@ +/* Copyright (c) 2005 Michael C. Martin */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _SCRIPTLIB_H +#define _SCRIPTLIB_H + +#include + +#ifndef __cpluspluc +typedef enum { false, true } bool; +#endif + +/* Key-Value resources */ +void scr_ClearTables (void); + +void scr_LoadFilename (const char *fname); +void scr_SaveFilename (const char *fname, const char *root); + +void scr_LoadFile (FILE *fname); +void scr_SaveFile (FILE *fname, const char *root); + +bool scr_HasKey (const char *key); + +const char *scr_GetString (const char *key); +const char *scr_GetStringDef (const char *key, const char *def); +void scr_PutString (const char *key, const char *value); + +bool scr_IsInteger (const char *key); +int scr_GetInteger (const char *key); +int scr_GetIntegerDef (const char *key, int def); +void scr_PutInteger (const char *key, int value); + +float scr_GetFloat (const char *key); +float scr_GetFloatDef (const char *key, float def); + +bool scr_IsBoolean (const char *key); +bool scr_GetBoolean (const char *key); +bool scr_GetBooleanDef (const char *key, bool def); +void scr_PutBoolean (const char *key, bool value); + +#endif /* _RESLIB_H */ + diff --git a/tools/map/sdlpngdrv.c b/tools/map/sdlpngdrv.c new file mode 100755 index 000000000..74dda0835 --- /dev/null +++ b/tools/map/sdlpngdrv.c @@ -0,0 +1,861 @@ +/* + * UQM Starmap image generator + * SDL/PNG driver implementation + * + * Uses: SDL, SDL_image, SDL_ttf, parts of SDL_gfx, and libpng + * + * + * The GPL applies + * + */ + +#include "mapdrv.h" +#include +#include +#include +#include "SDL.h" +#include "SDL_image.h" +#include "SDL_ttf.h" +#include "SDL_gfxPrimitives.h" +#include + +struct mg_font +{ + char* name; + TTF_Font* font; + int size; +}; + +struct mg_image +{ + SDL_Surface* img; + double width; + double height; +}; + +static int drv_init(int argc, char *argv[]); +static int drv_term(void); +static void drv_usage(void); +static int drv_setResolution(int dpi_x, int dpi_y); +static int drv_begin(double w, double h); +static int drv_write(void); +static int drv_end(void); +static mg_font_t drv_loadFont(const char* name, double size, const char*); +static void drv_freeFont(mg_font_t); +static mg_image_t drv_loadImage(const char*); +static void drv_freeImage(mg_image_t); +static int drv_getImageSize(mg_image_t, mg_rectf_t*); + +static void drv_setClipRect(const mg_rectf_t*); +static void drv_drawPixel(double x, double y, mg_color_t, double weight); +static void drv_drawLine(double x0, double y0, double x1, double y1, mg_color_t, double weight); +static void drv_drawRect(const mg_rectf_t*, mg_color_t color, double weight); +static void drv_drawFilledRect(const mg_rectf_t*, mg_color_t color); +static void drv_drawEllipse(double xc, double yc, double xr, double yr, mg_color_t, double weight); +static void drv_drawFilledEllipse(double xc, double yc, double xr, double yr, mg_color_t); +static void drv_drawImage(double x, double y, mg_image_t); +static void drv_drawText(mg_font_t, double x, double y, const unsigned char* utf8str, mg_color_t); +static void drv_getTextSize(mg_font_t, const unsigned char* utf8str, mg_rectf_t*); + +const mg_driver_t sdlpng_drv = +{ + "sdlpng", // name + "SDL/PNG image writer", // description + + // func ptrs + drv_init, + drv_term, + drv_usage, + drv_setResolution, + drv_begin, + drv_write, + drv_end, + drv_loadFont, + drv_freeFont, + drv_loadImage, + drv_freeImage, + drv_getImageSize, + + // draw func ptrs + drv_setClipRect, + drv_drawPixel, + drv_drawLine, + drv_drawRect, + drv_drawFilledRect, + drv_drawEllipse, + drv_drawFilledEllipse, + drv_drawImage, + drv_drawText, + drv_getTextSize, + +}; + +#if SDL_BYTEORDER == SDL_BIG_ENDIAN +# define R_MASK 0xff000000 +# define G_MASK 0x00ff0000 +# define B_MASK 0x0000ff00 +# define A_MASK 0x000000ff + +# define PNG_R_MASK 0x00ff0000 +# define PNG_G_MASK 0x0000ff00 +# define PNG_B_MASK 0x000000ff +# define PNG_A_MASK 0xff000000 + +#else +# define R_MASK 0x00ff0000 +# define G_MASK 0x0000ff00 +# define B_MASK 0x000000ff +# define A_MASK 0xff000000 + +# define PNG_R_MASK 0x000000ff +# define PNG_G_MASK 0x0000ff00 +# define PNG_B_MASK 0x00ff0000 +# define PNG_A_MASK 0xff000000 +#endif + +static int parseArguments(int argc, char* argv[]); + +static SDL_PixelFormat* imgfmt; +static SDL_Surface* fmtimg; +static SDL_Surface* outimg; + +static int use32bpp; +static const char* fontdir = "."; +static const char* outdev = "starmap.png"; +static FILE* fout; +static int dpix, dpiy; + +static char* strcopy(const char* str) +{ + int l; + char* s; + + if (!str) + return 0; + l = strlen(str); + s = malloc(l + 1); + if (!s) + return 0; + memcpy(s, str, l + 1); + return s; +} + +static int drv_init(int argc, char *argv[]) +{ + int ret; + ret = parseArguments(argc, argv); + if (ret) + return ret; + + if (SDL_Init(SDL_INIT_NOPARACHUTE)) + { + mg_verbose(1, "Cannot init SDL\n"); + return EXIT_FAILURE; + } + + if (TTF_Init()) + { + mg_verbose(1, "Cannot init SDL_ttf\n"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +static int drv_term(void) +{ + imgfmt = 0; + if (fmtimg) + SDL_FreeSurface(fmtimg); + fmtimg = 0; + if (outimg) + SDL_FreeSurface(outimg); + outimg = 0; + + if (fout) + fclose(fout); + fout = 0; + + TTF_Quit(); + SDL_Quit(); + + return EXIT_SUCCESS; +} + +static void drv_usage(void) +{ + mg_verbose(0, + "sdlpng driver : [-f ] [-n] [-o ]\n" + "Options:\n" + "\t-f dir where font files are located\n" + "\t-n use native 32bpp surface for rendering\n" + "\t doubles memory requirement but may increase quality in some cases\n" + "\t-o save image as (default is 'starmap.png')\n" + ); +} + +static int parseArguments(int argc, char* argv[]) +{ + char ch; + + while (-1 != (ch = getopt(argc, argv, "-f:no:"))) + { + switch (ch) + { + case 'f': + fontdir = optarg; + break; + case 'n': + use32bpp = 1; + break; + case 'o': + outdev = optarg; + break; + default: + // non-option -- probably an arg to unknown option + ; + } + } + + return EXIT_SUCCESS; +} + +static int drv_setResolution(int dpi_x, int dpi_y) +{ + dpix = dpi_x; + dpiy = dpi_y; + + return EXIT_SUCCESS; +} + +static inline int inchToPixelsX(double inch) +{ + int v = (int)(inch * dpix); + // make sure it's at least 1 pixel wide if present + if (!v && inch) + v = 1; + return v; +} + +static inline int inchToPixelsY(double inch) +{ + int v = (int)(inch * dpiy); + // make sure it's at least 1 pixel wide if present + if (!v && inch) + v = 1; + return v; +} + +static inline double pixelsToInchX(int pixels) +{ + return (double)pixels / dpix; +} + +static inline double pixelsToInchY(int pixels) +{ + return (double)pixels / dpiy; +} + +static int drv_begin(double w, double h) +{ + int targetbpp; + + fout = fopen(outdev, "wb"); + if (!fout) + { + mg_verbose(1, "Cannot open file '%s' -- %s\n", outdev, strerror(errno)); + return EXIT_FAILURE; + } + + if (use32bpp) + { // SDL-native channel order; allows exact accelerated blits + fmtimg = SDL_CreateRGBSurface(SDL_SWSURFACE, 0, 0, 32, + R_MASK, G_MASK, B_MASK, A_MASK); + targetbpp = 32; + } + else + { // PNG-native channel order; saves memory + fmtimg = SDL_CreateRGBSurface(SDL_SWSURFACE, 0, 0, 32, + PNG_R_MASK, PNG_G_MASK, PNG_B_MASK, PNG_A_MASK); + targetbpp = 24; + } + + if (!fmtimg) + { + mg_verbose(1, "Cannot create format image\n"); + return EXIT_FAILURE; + } + imgfmt = fmtimg->format; + + outimg = SDL_CreateRGBSurface(SDL_SWSURFACE, inchToPixelsX(w), inchToPixelsY(h), + targetbpp, imgfmt->Rmask, imgfmt->Gmask, imgfmt->Bmask, 0); + if (!outimg) + { + mg_verbose(1, "Cannot create work image\n"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +static int drv_end(void) +{ + imgfmt = 0; + if (fmtimg) + SDL_FreeSurface(fmtimg); + fmtimg = 0; + if (outimg) + SDL_FreeSurface(outimg); + outimg = 0; + + if (fout) + fclose(fout); + fout = 0; + + return EXIT_SUCCESS; +} + +static int drv_write(void) +{ + png_structp png_ptr; + png_infop info_ptr; + SDL_Surface* cimg = NULL; + SDL_PixelFormat* fmt = outimg->format; + png_bytep* lines = NULL; + int i; + + if (!outimg || !fout) + return EXIT_FAILURE; + + mg_verbose(2, "Writing image to '%s'\n", outdev); + + if (fmt->BytesPerPixel != 3 || + fmt->Rmask != PNG_R_MASK || + fmt->Gmask != PNG_G_MASK || + fmt->Bmask != PNG_B_MASK) + { + cimg = SDL_CreateRGBSurface(SDL_SWSURFACE, outimg->w, outimg->h, 24, + PNG_R_MASK, PNG_G_MASK, PNG_B_MASK, 0); + if (!cimg) + return EXIT_FAILURE; + SDL_BlitSurface(outimg, NULL, cimg, NULL); + outimg = cimg; + } + + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL); + if (!png_ptr) + { + mg_verbose(1, "png_create_write_struct failed.\n"); + return EXIT_FAILURE; + } + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_write_struct(&png_ptr, (png_infopp) NULL); + mg_verbose(1, "png_create_info_struct failed.\n"); + return EXIT_FAILURE; + } + if (setjmp(png_jmpbuf(png_ptr))) + { + mg_verbose(1, "png error.\n"); + png_destroy_write_struct(&png_ptr, &info_ptr); + return EXIT_FAILURE; + } + + lines = calloc(outimg->h, sizeof(png_bytep)); + if (!lines) + return EXIT_FAILURE; + for (i = 0; i < outimg->h; ++i) + lines[i] = (Uint8*)outimg->pixels + i * outimg->pitch; + + png_init_io(png_ptr, fout); + png_set_IHDR(png_ptr, info_ptr, outimg->w, outimg->h, 8, + PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_BASE); + png_set_compression_level(png_ptr, Z_BEST_COMPRESSION); + png_set_pHYs(png_ptr, info_ptr, dpix * 10000 / 254, dpiy * 10000 / 254, + PNG_RESOLUTION_METER); + png_write_info(png_ptr, info_ptr); + png_set_packing(png_ptr); + + png_write_image(png_ptr, lines); + + png_write_end(png_ptr, info_ptr); + png_destroy_write_struct(&png_ptr, &info_ptr); + + if (cimg) + SDL_FreeSurface(cimg); + if (lines) + free(lines); + + return EXIT_SUCCESS; +} + +static mg_font_t drv_loadFont(const char* name, double size, const char* filename) +{ + char buf[512]; + struct mg_font* fnt; + + fnt = calloc(1, sizeof(*fnt)); + if (!fnt) + return 0; + fnt->size = inchToPixelsY(size); + fnt->name = strcopy(name); + sprintf(buf, "%s/%s", fontdir, filename); + fnt->font = TTF_OpenFont(buf, fnt->size); + if (!fnt->font) + { + free(fnt); + return 0; + } + + return fnt; +} + +static void drv_freeFont(mg_font_t fnt) +{ + if (!fnt) + return; + + if (fnt->name) + free(fnt->name); + if (fnt->font) + TTF_CloseFont(fnt->font); + free(fnt); +} + +static mg_image_t drv_loadImage(const char* filename) +{ + struct mg_image* img; + + img = calloc(1, sizeof(*img)); + if (!img) + return 0; + img->img = IMG_Load(filename); + if (!img->img) + { + free(img); + return 0; + } + img->width = pixelsToInchX(img->img->w); + img->height = pixelsToInchY(img->img->h); + + return img; +} + +static void drv_freeImage(mg_image_t img) +{ + if (!img) + return; + + if (img->img) + SDL_FreeSurface(img->img); + free(img); +} + +static int drv_getImageSize(mg_image_t img, mg_rectf_t* r) +{ + if (!r) + return EXIT_FAILURE; + + r->x = r->y = 0; + if (img) + { + r->w = img->width; + r->h = img->height; + } + else + { + r->w = 0; + r->h = 0; + } + return EXIT_SUCCESS; +} + +static void drv_setClipRect(const mg_rectf_t* r) +{ + if (!r) + { + SDL_SetClipRect(outimg, 0); + } + else + { + SDL_Rect dr; + dr.x = (int)(r->x * dpix); + dr.y = (int)(r->y * dpiy); + dr.w = (int)(r->w * dpix); + dr.h = (int)(r->h * dpiy); + SDL_SetClipRect(outimg, &dr); + } +} + +static inline Uint32 colorToGfx(mg_color_t clr) +{ + return (clr.r << 24) | (clr.g << 16) | (clr.b << 8) | (clr.a); +} + +static inline Uint32 colorToSDL(mg_color_t clr) +{ + return SDL_MapRGBA(imgfmt, clr.r, clr.g, clr.b, clr.a); +} + +static void drv_drawPixel(double xf, double yf, mg_color_t color, double weightf) +{ + // weight is ignored here + const int x0 = (int)(xf * dpix); + const int y0 = (int)(yf * dpiy); + const Uint32 clr = colorToGfx(color); + pixelColor(outimg, x0, y0, clr); + + (void)weightf; // hush little compiler +} + +static void drawHLine(int x0, int x1, int y, mg_color_t color, int weight) +{ + int i; + int y0 = y - weight / 2; + const Uint32 clr = colorToGfx(color); + Uint32 aaclr; + Uint32 c; + + color.a = 0xb0; + aaclr = colorToGfx(color); + + for (i = 0; i < weight; ++i, ++y0) + { + if (weight > 2 && (i == 0 || i == weight - 1)) + c = aaclr; + else + c = clr; + + hlineColor(outimg, x0, x1, y0, c); + } +} + +static void drawVLine(int x, int y0, int y1, mg_color_t color, int weight) +{ + int i; + int x0 = x - weight / 2; + const Uint32 clr = colorToGfx(color); + Uint32 aaclr; + Uint32 c; + + color.a = 0xb0; + aaclr = colorToGfx(color); + + for (i = 0; i < weight; ++i, ++x0) + { + if (weight > 2 && (i == 0 || i == weight - 1)) + c = aaclr; + else + c = clr; + + vlineColor(outimg, x0, y0, y1, c); + } +} + +// This is a pretty crude floating point algorithm +// for drawing thick anti-aliased lines with rounded end-points +// Not optimized at all, but we do not need speed here +static void drv_drawLine(double x0f, double y0f, double x1f, double y1f, mg_color_t color, double weightf) +{ + int x0 = (int)(x0f * dpix); + int y0 = (int)(y0f * dpiy); + int x1 = (int)(x1f * dpix); + int y1 = (int)(y1f * dpiy); + int dx, dy; + double length; + double sinl, cosl; + double hw, thres; + int x, y; + const Uint32 clr = colorToGfx(color); + const Uint32 clrna = clr & 0xffffff00; + int weight; + + if (x0 == x1) + { + drawVLine(x0, y0, y1, color, inchToPixelsX(weightf)); + return; + } + if (y0 == y1) + { + drawHLine(x0, x1, y0, color, inchToPixelsY(weightf)); + return; + } + + weight = (int)((weightf * dpix + weightf * dpiy) / 2); + if (weight <= 1) + { // 1-pixel wide + aalineColor(outimg, x0, y0, x1, y1, clr); + return; + } + + if (x1 < x0) + { // swap line endpoints + int t; + t = x0; + x0 = x1; + x1 = t; + t = y0; + y0 = y1; + y1 = t; + } + + dx = x1 - x0; + dy = y1 - y0; + length = sqrt(dx*dx + dy*dy); + sinl = (double)dy / length; + cosl = (double)dx / length; + hw = (double)weight / 2; + thres = hw - 0.6; + if (thres < 0) + thres = 0; + + for (x = x0 - weight; x < x1 + weight; ++x) + { + double py = (double)(x - x0) / dx * dy; + double ly = y0 + py; + int iy; + int sy; + + if (x < x0) + sy = y0; + else if (x > x1) + sy = y1; + else + sy = (int)ly; + + for (iy = -1; iy <= 1; ++iy) + { + if (iy == 0) + { + ++iy; + ++sy; + } + + for (y = sy; ; y += iy) + { + double oy = py + (y - ly) * fabs(sinl); + double dist; + + if (y1 < y0) + oy = -oy; + + // distance from ideal line point dictates opacity + if (oy < 0) + { + dist = sqrt((x - x0) * (x - x0) + (y - y0) * (y - y0)); + } + else if (oy > abs(dy)) + { + dist = sqrt((x - x1) * (x - x1) + (y - y1) * (y - y1)); + } + else + { + dist = fabs((double)y - ly) * fabs(cosl); + } + + if (dist <= thres) + { + pixelColor(outimg, x, y, clr); + } + else + { // anti-alias the pixel + int a = (int)((1 - (dist - thres)) * 255); + if (a <= 0) + break; + pixelColor(outimg, x, y, clrna | ((color.a * a) >> 8)); + } + } + } + } +} + +static void drv_drawRect(const mg_rectf_t* r, mg_color_t color, double weightf) +{ + // draw the box + drv_drawLine(r->x, r->y, r->x + r->w, r->y, color, weightf); + drv_drawLine(r->x, r->y + r->h, r->x + r->w, r->y + r->h, color, weightf); + drv_drawLine(r->x, r->y, r->x, r->y + r->h, color, weightf); + drv_drawLine(r->x + r->w, r->y, r->x + r->w, r->y + r->h, color, weightf); +} + +static void drv_drawFilledRect(const mg_rectf_t* r, mg_color_t color) +{ + const Uint32 clr = colorToSDL(color); + + if (!r) + { // whole surface + SDL_FillRect(outimg, NULL, clr); + } + else + { + SDL_Rect dr; + dr.x = (int)(r->x * dpix); + dr.y = (int)(r->y * dpiy); + dr.w = (int)(r->w * dpix); + dr.h = (int)(r->h * dpiy); + SDL_FillRect(outimg, &dr, clr); + } +} + +static void drv_drawEllipse(double xcf, double ycf, double xrf, double yrf, mg_color_t color, double weight) +{ + // weight currently ignored + int xc = (int)(xcf * dpix); + int yc = (int)(ycf * dpiy); + int xr = (int)(xrf * dpix); + int yr = (int)(yrf * dpiy); + const Uint32 clr = colorToGfx(color); + + aaellipseColor(outimg, xc, yc, xr, yr, clr); + + (void)weight; // hush little compiler +} + +// This is a pretty crude floating point algorithm +// for drawing anti-aliased filled ellipse +// Not really optimized at all, but we do not need speed here +static void drv_drawFilledEllipse(double xcf, double ycf, double xrf, double yrf, mg_color_t color) +{ + const int xc = (int)(xcf * dpix); + const int yc = (int)(ycf * dpiy); + const int xr = (int)(xrf * dpix); + const int yr = (int)(yrf * dpiy); + const Uint32 clr = colorToGfx(color); + const Uint32 clrna = clr & 0xffffff00; + int x, y; + double radius, radius_2, rad_thres; + double fx_2, fy_2; + + // the (more or less) classic elliptic equation is + // (fx*x)^2 + (fy*y)^2 = r^2 (classic: fx=r/a, fy=r/b) + // we'll take a=r (or b=r) and transform + // x^2 + (fy*y)^2 = r^2 + // or more precisely, along the major axis + if (xr >= yr) + radius = xr; + else + radius = yr; + + radius_2 = radius * radius; + fx_2 = radius / xr; + fx_2 = fx_2 * fx_2; + fy_2 = radius / yr; + fy_2 = fy_2 * fy_2; + rad_thres = (radius + 1) * (radius + 1); + + for (y = -yr; y <= yr; y++) + { + double y_2 = y * y * fy_2; + + for (x = -xr; x <= xr; x++) + { + double r_2 = y_2 + x * x * fx_2; + + if (r_2 >= rad_thres) + { // outside bounds + continue; + } + + if (r_2 <= radius_2) + { // solid pixels inside the ellipse + pixelColor(outimg, xc + x, yc + y, clr); + } + else + { // anti-aliased edge + int a = (int) ((1 - (sqrt(r_2) - radius)) * 255); + if (a < 0) + continue; // should never happen + pixelColor(outimg, xc + x, yc + y, clrna | ((color.a * a) >> 8)); + } + } + } + +} + +static void setImageAlpha(SDL_Surface* img, int alpha) +{ + SDL_PixelFormat* fmt = img->format; + int x, y; + + if (!fmt->Amask) + { + SDL_SetAlpha(img, SDL_SRCALPHA, alpha); + return; + } + + if (fmt->BytesPerPixel != 4) + { + mg_verbose(1, "Unsuppoted surface format for alpha -- %d bytes/pixel\n", (int)fmt->BytesPerPixel); + return; + } + + // adjust the alpha channel accordingly + for (y = 0; y < img->h; ++y) + { + Uint32* dst = (Uint32*)((Uint8*)img->pixels + img->pitch * y); + + for (x = 0; x < img->w; ++x, ++dst) + { + Uint32 p = *dst; + Uint32 a = (p & fmt->Amask) >> fmt->Ashift; + p &= ~fmt->Amask; + a = a * alpha / 255; + *dst = p | (a << fmt->Ashift); + } + } +} + +static void drv_drawImage(double xf, double yf, struct mg_image* img) +{ + SDL_Rect dr; + + dr.x = (int)(xf * dpix); + dr.y = (int)(yf * dpiy); + + SDL_BlitSurface(img->img, NULL, outimg, &dr); +} + +static void drv_drawText(struct mg_font* fnt, double xf, double yf, const unsigned char* utf8str, mg_color_t color) +{ + SDL_Rect dr; + SDL_Color clr = {color.r, color.g, color.b, 0}; + SDL_Surface* text; + + if (!fnt || !utf8str) + return; + + dr.x = (int)(xf * dpix); + dr.y = (int)(yf * dpiy); + + text = TTF_RenderUTF8_Blended(fnt->font, utf8str, clr); + if (!text) + return; + if (color.a != 0xff) + setImageAlpha(text, color.a); + SDL_BlitSurface(text, NULL, outimg, &dr); + SDL_FreeSurface(text); +} + +static void drv_getTextSize(struct mg_font* fnt, const unsigned char* utf8str, mg_rectf_t* r) +{ + int w = 0; + int h = 0; + + if (!r) + return; + if (!fnt || !utf8str) + { + r->w = 0; + r->h = 0; + return; + } + + TTF_SizeUTF8(fnt->font, utf8str, &w, &h); + r->w = (double)w / dpix; + r->h = (double)h / dpiy; +} diff --git a/tools/map/stars.map b/tools/map/stars.map new file mode 100755 index 000000000..3f34d4101 --- /dev/null +++ b/tools/map/stars.map @@ -0,0 +1,502 @@ +Achernar,*,537.5,272.9,B,1 +Alcor,*,970.8,025.0,B,1 +Aldebaran,*,737.5,356.2,B,1 +Algol,*,900.0,325.0,R,1 +Almagest,*,990.9,235.9,B,1 +Altair,*,450.0,650.0,B,1 +Andromedae,A,862.5,700.0,G,1 +Andromedae,B,866.6,710.4,G,1 +Antares,*,647.9,754.1,O,1 +Antliae,A,268.7,900.0,B,1 +Antliae,B,270.6,891.0,Y,1 +Antliae,C,283.1,885.4,G,1 +Antliae,D,305.0,883.3,B,1 +Antliae,E,253.5,891.7,W,1 +Antliae,F,258.1,910.5,R,1 +Apodis,A,258.2,850.7,Y,3 +Apodis,B,259.3,856.9,R,1 +Apodis,C,256.2,857.2,O,1 +Apodis,D,253.6,850.4,G,1 +Aquarii,A,856.0,863.8,G,1 +Aquarii,B,863.0,869.3,G,1 +Aquarii,C,853.4,879.7,O,1 +Aquarii,D,858.8,881.2,B,1 +Aquarii,E,875.0,864.5,B,1 +Aquarii,F,862.5,856.2,O,1 +Aquarii,G,849.2,857.8,W,1 +Aquilae,A,915.9,974.5,B,3 +Aquilae,B,918.6,974.1,R,1 +Aquilae,C,912.0,974.1,R,1 +Aquilae,D,914.4,968.6,Y,1 +Aquilae,E,914.7,979.0,O,1 +Arae,A,933.9,084.3,W,1 +Arae,B,933.3,093.7,Y,3 +Arae,C,941.9,094.2,B,1 +Arae,D,929.2,075.0,Y,1 +Arae,E,923.7,082.1,B,1 +Arcturus,*,964.5,579.1,O,1 +Arianni,A,739.5,175.0,B,1 +Arianni,B,718.7,183.3,Y,1 +Arianni,C,739.5,168.7,Y,1 +Arietis,A,937.5,158.3,G,1 +Arietis,B,946.9,154.8,G,1 +Arietis,C,947.7,167.0,Y,1 +Arietis,D,954.1,168.7,R,2 +Arietis,E,955.9,173.5,O,1 +Aurigae,A,806.2,208.3,W,1 +Aurigae,B,808.0,201.1,O,1 +Aurigae,C,816.3,200.9,W,1 +Aurigae,D,818.7,193.7,W,1 +Bellatrix,*,545.8,191.6,Y,1 +Betelgeuse,*,412.5,377.0,B,1 +Bootis,A,022.9,266.6,G,1 +Bootis,B,035.1,275.8,Y,1 +Bootis,C,038.4,290.0,O,1 +Bootis,D,021.7,250.9,O,1 +Bootis,E,013.8,269.6,R,1 +Bootis,F,016.7,287.5,R,1 +Bootis,G,067.2,286.3,O,1 +Brahe,A,620.8,233.3,O,1 +Brahe,B,639.5,231.2,G,1 +Brahe,C,635.4,272.9,W,1 +Brahe,D,645.8,275.0,G,1 +Brahe,E,641.6,262.5,O,1 +Brahe,F,650.0,245.8,R,1 +Caeli,A,241.1,071.8,R,1 +Caeli,B,258.9,074.1,R,1 +Caeli,C,285.4,078.7,R,1 +Caeli,D,308.9,078.2,R,1 +Caeli,E,333.3,080.1,R,1 +Camelopardalis,A,606.2,404.1,Y,2 +Camelopardalis,B,595.8,408.3,G,1 +Camelopardalis,C,612.5,393.7,G,1 +Camelopardalis,D,627.0,383.3,G,1 +Camelopardalis,E,593.7,393.7,O,1 +Camelopardalis,F,616.6,412.5,O,1 +Camelopardalis,G,620.8,422.9,O,1 +Camelopardalis,H,589.5,402.0,R,1 +Camelopardalis,I,629.1,393.7,R,1 +Cancri,A,493.7,514.5,G,1 +Cancri,B,515.5,512.2,G,1 +Cancri,C,500.6,501.1,O,1 +Cancri,D,509.4,493.1,R,1 +Canopus,*,218.7,150.0,B,1 +Capella,*,424.4,009.1,B,1 +Capricorni,A,297.9,516.6,O,2 +Capricorni,B,303.5,517.8,O,1 +Capricorni,C,299.3,531.8,R,1 +Carinae,A,362.5,543.7,G,2 +Carinae,B,341.6,543.7,B,1 +Carinae,C,358.3,547.9,G,1 +Cassiopeiae,A,354.1,518.7,B,1 +Cassiopeiae,B,377.0,525.0,G,1 +Cassiopeiae,C,367.9,506.8,Y,1 +Cassiopeiae,D,387.5,514.5,Y,1 +Cassiopeiae,E,399.4,518.5,R,1 +Centauri,A,155.9,099.3,R,3 +Centauri,B,141.2,090.5,G,1 +Centauri,C,157.9,111.5,G,1 +Centauri,D,131.2,126.0,Y,1 +Centauri,E,151.5,086.6,G,1 +Centauri,F,146.3,077.9,R,2 +Cephei,A,375.0,583.3,G,2 +Cephei,B,362.5,575.0,R,2 +Cerenkov,A,422.1,198.6,B,1 +Cerenkov,B,450.0,200.0,O,1 +Ceti,A,287.5,447.9,W,2 +Ceti,B,287.5,404.1,B,1 +Ceti,C,303.8,408.3,B,1 +Ceti,D,293.7,430.6,B,1 +Ceti,E,270.8,470.8,B,1 +Ceti,F,289.5,468.7,G,1 +Ceti,G,281.2,425.0,O,1 +Chamaeleonis,A,497.1,710.4,W,1 +Chamaeleonis,B,495.5,703.4,O,1 +Chamaeleonis,C,489.5,704.1,G,1 +Chamaeleonis,D,485.4,712.5,O,1 +Chamaeleonis,E,487.9,720.1,Y,1 +Chamaeleonis,F,495.8,722.9,G,1 +Chamaeleonis,G,508.3,714.5,B,1 +Chamaeleonis,H,514.5,695.8,B,1 +Chamaeleonis,I,514.5,687.5,G,1 +Chamaeleonis,J,506.2,675.0,B,1 +Chandrasekhar,A,012.5,654.1,R,2 +Chandrasekhar,B,037.5,671.6,W,1 +Chandrasekhar,C,020.8,662.5,G,1 +Chandrasekhar,D,018.7,652.0,O,1 +Chandrasekhar,E,031.2,672.8,O,1 +Circini,A,039.5,597.9,G,2 +Circini,B,036.5,609.3,B,1 +Circini,C,043.7,627.0,B,1 +Circini,D,054.1,614.5,O,1 +Circini,E,056.3,598.0,O,1 +Circini,F,045.6,598.9,O,1 +Columbae,A,075.0,645.8,W,2 +Columbae,B,077.0,660.2,R,1 +Columbae,C,072.9,620.8,G,1 +Copernicus,A,579.1,262.5,G,1 +Copernicus,B,600.8,263.1,Y,1 +Copernicus,C,562.5,252.0,R,1 +Corvi,B,033.3,981.2,G,1 +Corvi,C,006.2,947.9,G,1 +Corvi,D,100.0,939.5,O,1 +Corvi,E,010.4,912.5,R,1 +Corvi,F,008.3,997.9,R,1 +Corvi,G,102.0,993.7,R,1 +Crateris,A,601.4,563.2,B,2 +Crateris,B,610.7,578.5,Y,1 +Crateris,C,616.6,600.0,W,1 +Crateris,D,620.0,593.5,Y,1 +Crateris,E,630.1,587.5,Y,1 +Crateris,F,649.6,603.2,O,1 +Crateris,G,642.9,595.8,R,1 +Crateris,H,621.5,625.5,R,1 +Crucis,A,558.3,629.1,W,1 +Crucis,B,547.9,668.7,G,1 +Crucis,C,525.0,622.9,Y,1 +Crucis,D,543.7,591.6,Y,1 +Cygnus,A,047.9,458.3,B,1 +Cygnus,B,047.9,464.5,G,1 +Cygnus,C,056.2,470.8,G,1 +Cygnus,D,041.6,471.7,R,1 +Cygnus,E,025.0,458.3,R,1 +Delphini,A,371.6,645.8,R,1 +Delphini,B,377.0,650.0,G,1 +Deneb,*,218.7,008.3,O,1 +Doradus,A,420.8,685.4,O,1 +Doradus,B,429.1,693.7,O,1 +Draconis,A,277.1,835.1,B,1 +Draconis,B,282.2,839.5,R,1 +Draconis,C,251.8,805.6,W,1 +Draconis,D,253.5,835.8,Y,1 +Draconis,E,283.6,785.7,W,1 +Draconis,F,277.6,867.3,O,1 +Draconis,G,315.1,839.0,R,1 +Draconis,H,327.0,800.0,Y,1 +Draconis,I,356.2,825.0,Y,1 +Draconis,J,245.8,866.6,W,1 +Draconis,K,236.2,839.5,G,1 +Draconis,L,231.0,870.2,R,1 +Draconis,M,230.0,886.1,R,1 +Draconis,N,258.8,865.3,R,1 +Equulei,A,591.0,662.4,B,1 +Equulei,B,602.0,672.9,B,1 +Eridani,A,587.5,772.9,Y,3 +Eridani,B,595.8,764.5,W,1 +Eridani,C,579.1,758.3,W,1 +Fomalhaut,*,437.5,856.2,R,1 +Fornacis,A,537.5,787.5,W,1 +Fornacis,B,564.5,802.0,B,1 +Fornacis,C,587.5,806.2,B,1 +Fornacis,D,597.9,797.9,G,1 +Fornacis,E,604.1,791.6,O,1 +Fornacis,F,610.4,800.0,O,1 +Fornacis,G,618.7,787.5,R,1 +Geminorum,A,495.8,779.1,W,2 +Geminorum,B,497.9,779.1,W,1 +Geminorum,C,489.5,745.8,O,1 +Geminorum,D,464.5,747.9,R,1 +Giclas,A,084.3,038.0,O,2 +Giclas,B,084.3,043.1,Y,1 +Giclas,C,080.3,033.7,Y,1 +Giclas,D,087.7,034.0,Y,1 +Giclas,E,095.8,046.8,B,1 +Giclas,F,111.6,033.4,G,1 +Giclas,G,070.8,004.1,W,1 +Giclas,H,067.5,074.2,O,1 +Gorno,A,277.1,014.6,B,1 +Gorno,B,281.4,008.9,O,1 +Gorno,C,293.9,011.6,O,1 +Gorno,D,290.8,026.9,B,1 +Gorno,E,282.0,030.1,G,1 +Groombridge,*,996.0,904.2,W,2 +Gruis,A,227.4,366.3,W,1 +Gruis,B,214.8,355.1,W,1 +Gruis,C,225.0,370.8,W,1 +Gruis,D,235.4,374.1,R,1 +Gruis,E,241.6,368.7,O,2 +Gruis,F,258.3,375.0,W,1 +Gruis,G,247.9,395.8,O,1 +Herculis,A,160.4,364.5,W,1 +Herculis,B,175.8,341.8,B,1 +Horologii,A,720.8,754.1,Y,1 +Horologii,B,712.5,725.0,R,1 +Horologii,C,720.8,700.0,R,1 +Horologii,D,736.0,718.4,R,1 +Horologii,E,753.2,725.8,R,1 +Horologii,F,744.3,753.8,R,1 +Horologii,G,739.5,785.4,R,1 +Horologii,H,720.0,784.9,R,1 +Horologii,I,708.3,799.3,R,1 +Horologii,J,688.9,780.3,R,1 +Horologii,K,694.0,751.4,R,1 +Hyades,A,832.2,893.4,W,1 +Hyades,B,837.5,895.8,B,1 +Hyades,C,837.5,904.1,O,1 +Hyades,D,824.9,895.8,O,1 +Hyades,E,850.0,912.5,O,1 +Hyades,F,850.0,937.2,Y,1 +Hyades,G,845.8,939.3,Y,1 +Hyades,H,829.6,954.8,G,1 +Hyades,I,800.0,950.5,W,1 +Hyades,J,766.4,958.9,G,1 +Hyades,K,725.5,937.4,G,1 +Hydrae,A,733.3,650.0,W,1 +Hydrae,B,781.2,656.2,O,1 +Hydrae,C,816.6,625.0,R,1 +Hyginus,A,852.0,416.6,R,1 +Hyginus,B,864.5,406.2,R,1 +Hyperion,*,656.2,127.0,O,1 +Illuminati,A,235.4,329.1,R,3 +Illuminati,B,252.0,343.7,O,1 +Illuminati,C,268.7,333.3,B,1 +Illuminati,D,235.4,316.6,Y,2 +Illuminati,E,272.7,295.1,G,1 +Illuminati,F,245.8,275.0,G,1 +Illuminati,G,220.8,285.4,O,1 +Illuminati,H,201.1,304.3,O,1 +Indi,A,400.0,136.3,O,1 +Indi,B,395.8,135.4,B,1 +Kepler,A,581.2,320.8,Y,1 +Kepler,B,562.5,295.8,B,1 +Kepler,C,602.0,297.9,O,1 +Klystron,A,193.7,997.9,R,1 +Klystron,B,291.6,954.1,R,1 +Krueger,A,030.4,047.7,Y,1 +Krueger,B,053.0,044.2,W,1 +Krueger,C,052.2,052.5,Y,1 +Krueger,D,057.0,028.9,G,1 +Krueger,E,026.5,015.6,O,1 +Krueger,F,013.4,056.5,G,1 +Lacaille,A,014.6,095.5,R,1 +Lacaille,B,023.0,095.2,Y,1 +Lacaille,C,024.2,085.7,O,2 +Lacertae,A,841.6,808.3,B,1 +Lacertae,B,822.9,804.1,R,1 +Lalande,A,349.9,264.8,B,1 +Lalande,B,340.0,280.4,W,1 +Lalande,C,361.9,283.0,O,1 +Lalande,D,375.9,277.8,O,1 +Lentilis,A,462.5,600.0,B,1 +Lentilis,B,462.5,589.5,G,1 +Lentilis,C,458.3,604.1,O,1 +Lentilis,D,472.9,595.8,O,1 +Leonis,A,900.0,822.9,G,1 +Leonis,B,943.7,785.4,R,1 +Leonis,C,968.7,733.3,W,1 +Leporis,A,807.3,858.8,O,1 +Leporis,B,766.6,866.6,O,1 +Leporis,C,718.7,881.2,B,1 +Librae,A,735.4,906.2,B,1 +Librae,B,741.4,912.4,G,1 +Librae,C,754.5,910.7,O,1 +Librae,D,779.1,918.7,O,1 +Librae,E,779.1,922.9,W,1 +Librae,F,783.3,908.3,W,1 +Librae,G,788.9,918.1,G,1 +Lipi,A,556.2,864.5,G,1 +Lipi,B,550.0,839.5,O,1 +Lipi,C,547.5,882.3,O,1 +Lipi,D,564.5,897.9,R,1 +Lipi,E,543.7,827.0,R,1 +Luyten,A,425.0,164.5,R,1 +Luyten,B,433.3,168.7,O,1 +Luyten,C,433.3,156.2,R,1 +Lyncis,A,560.0,955.2,O,1 +Lyncis,B,571.1,947.5,O,1 +Lyncis,C,578.1,971.1,Y,1 +Lyncis,D,570.4,979.5,Y,1 +Lyncis,E,532.9,953.8,Y,1 +Lyncis,F,522.9,972.9,R,1 +Lyncis,G,598.9,949.6,O,1 +Lyncis,H,612.5,960.4,R,1 +Lyrae,A,191.6,127.0,R,1 +Lyrae,B,189.5,104.1,R,1 +Maksutov,A,597.7,524.6,G,1 +Maksutov,B,627.0,547.9,R,1 +Menkar,*,481.2,927.0,O,1 +Mensae,A,383.3,318.7,R,1 +Mensae,B,403.0,288.7,R,1 +Mensae,C,464.5,295.8,R,1 +Mersenne,A,260.4,664.5,R,1 +Mersenne,B,241.6,729.1,R,1 +Metis,*,570.8,460.4,R,1 +Microscopii,*,439.5,997.9,G,1 +Mira,A,355.1,232.0,R,1 +Mira,B,367.8,192.6,B,1 +Mira,C,388.4,226.2,Y,1 +Mira,D,335.4,235.4,O,1 +Mizar,*,041.6,130.1,R,1 +Monocerotis,A,387.5,718.7,O,1 +Monocerotis,B,385.4,729.1,G,1 +Muscae,A,112.5,779.1,B,2 +Muscae,B,104.1,770.8,O,1 +Muscae,C,102.0,718.7,R,1 +Muscae,D,139.5,804.1,R,1 +Muscae,E,152.0,833.3,O,1 +Muscae,F,112.5,858.3,O,1 +Normae,A,142.5,540.4,B,1 +Normae,B,141.6,531.5,W,1 +Normae,C,152.0,526.1,R,1 +Normae,D,161.3,527.9,G,1 +Normae,E,185.4,541.6,W,1 +Normae,F,215.9,561.4,O,1 +Octantis,A,157.8,666.8,G,3 +Octantis,B,136.0,648.9,G,1 +Olber,A,027.0,218.7,B,1 +Olber,B,012.5,222.9,B,1 +Olber,C,031.2,225.0,B,1 +Ophiuchi,A,043.7,877.0,R,1 +Ophiuchi,B,047.9,887.5,R,1 +Ophiuchi,C,033.3,891.6,G,1 +Organon,*,685.8,057.7,G,1 +Orionis,A,190.2,606.5,G,1 +Orionis,B,197.8,596.8,G,1 +Orionis,C,192.3,587.8,O,1 +Orionis,D,171.4,592.6,Y,1 +Orionis,E,154.5,581.8,O,1 +Orionis,F,155.8,605.8,Y,1 +Orionis,G,179.5,632.9,Y,1 +Orionis,H,188.1,630.8,G,1 +Orionis,I,211.8,637.9,B,1 +Orionis,J,220.0,617.6,B,1 +Orionis,K,215.9,607.3,Y,1 +Orionis,L,222.8,603.8,B,1 +Pavonis,A,056.2,800.0,G,2 +Pavonis,B,068.7,800.0,O,1 +Pegasi,A,033.3,762.5,B,1 +Pegasi,B,039.5,745.8,B,1 +Persei,A,929.1,258.3,B,1 +Persei,B,947.9,266.6,W,1 +Persei,C,933.3,279.1,R,1 +Persei,D,925.0,285.4,W,1 +Persei,E,903.8,240.7,R,1 +Persei,F,946.9,280.6,O,1 +Persei,G,889.5,268.7,O,1 +Persei,H,937.5,241.6,G,1 +Persei,I,887.5,231.2,G,1 +Phoenicis,A,941.6,439.5,B,1 +Phoenicis,B,957.3,418.2,R,1 +Phoenicis,C,981.2,414.5,B,1 +Pictoris,A,933.3,370.8,G,1 +Pictoris,B,931.2,356.2,B,1 +Pictoris,C,937.5,360.4,Y,1 +Pictoris,D,959.9,358.3,G,1 +Piscium,A,843.7,345.8,G,1 +Piscium,B,879.1,354.1,O,1 +Piscium,C,870.8,362.5,O,1 +Piscium,D,877.0,345.8,G,1 +Pollux,*,565.2,009.8,W,1 +Procyon,*,074.2,226.8,O,1 +Ptolemae,A,200.4,044.1,B,1 +Ptolemae,B,205.8,047.5,Y,1 +Ptolemae,C,210.0,055.4,Y,1 +Ptolemae,D,215.6,044.0,O,1 +Ptolemae,E,185.5,027.0,G,1 +Ptolemae,F,178.7,033.8,G,1 +Ptolemae,G,174.0,042.3,B,1 +Puppis,A,812.5,308.3,O,1 +Puppis,B,829.1,297.9,O,1 +Puppis,C,827.0,295.8,G,1 +Pyxidis,A,895.8,500.0,B,2 +Pyxidis,B,900.0,500.0,R,1 +Pyxidis,C,906.2,508.3,O,1 +Raynet,A,284.0,167.6,G,1 +Raynet,B,288.1,161.4,G,1 +Raynet,C,279.1,189.5,R,1 +Regulus,*,373.2,106.7,G,1 +Reticuli,A,731.2,506.2,O,1 +Reticuli,B,702.0,529.1,B,1 +Reticuli,C,741.6,508.3,G,1 +Reticuli,D,725.0,458.3,G,1 +Rigel,*,210.4,208.3,O,1 +Sagittae,A,025.0,568.7,G,1 +Sagittae,B,037.1,577.2,R,1 +Sagittae,C,015.2,590.0,R,1 +Sagittarii,A,683.3,200.0,B,1 +Sagittarii,B,702.0,239.5,Y,1 +Sagittarii,C,708.3,277.0,R,1 +Sagittarii,D,656.2,302.0,B,1 +Saurus,A,230.6,228.5,O,1 +Saurus,B,240.2,230.9,R,1 +Saurus,C,229.8,238.5,R,1 +Scorpii,A,646.7,187.8,B,1 +Scorpii,B,650.0,191.6,W,1 +Scorpii,C,647.9,206.2,G,1 +Scorpii,D,603.6,203.5,B,1 +Scorpii,E,629.1,220.8,G,1 +Scorpii,F,650.0,220.8,B,1 +Sculptoris,A,604.1,156.2,B,1 +Sculptoris,C,608.3,162.5,G,1 +Sculptoris,D,581.2,120.8,O,1 +Sculptoris,E,570.8,152.0,O,1 +Scuti,A,503.9,037.3,O,1 +Scuti,B,501.4,058.4,R,1 +Scuti,C,525.6,060.8,G,1 +Scuti,D,516.0,028.0,Y,1 +Scuti,E,533.8,035.5,W,1 +Scuti,F,531.3,015.0,W,1 +Serpentis,A,491.1,018.0,O,2 +Serpentis,B,486.1,026.2,W,1 +Serpentis,C,492.3,029.4,Y,1 +Serpentis,D,474.7,022.1,O,1 +Serpentis,E,487.2,040.8,R,1 +Serpentis,F,500.7,003.5,G,1 +Serpentis,G,471.4,007.8,G,1 +Serpentis,H,452.9,016.9,B,1 +Serpentis,I,459.6,042.9,W,1 +Sextantis,A,433.7,106.6,B,1 +Sextantis,B,460.4,118.7,O,1 +Sextantis,C,487.5,114.5,O,1 +Sextantis,D,487.3,096.8,G,1 +Sextantis,E,477.0,089.5,B,1 +Sextantis,F,468.1,091.6,O,1 +Sirius,*,180.6,150.7,W,2 +Sol,*,175.2,145.0,Y,1 +Squidi,A,214.5,391.6,G,1 +Squidi,B,206.2,399.1,O,1 +Squidi,C,214.5,420.8,R,1 +Tauri,A,022.9,366.6,G,1 +Tauri,B,028.8,373.5,W,1 +Tauri,C,026.7,364.5,B,1 +Tauri,D,016.6,377.0,W,1 +Tauri,E,014.9,351.9,R,1 +Tauri,F,009.0,361.4,B,1 +Telescopii,A,028.5,402.0,W,1 +Telescopii,B,029.1,410.4,O,1 +Telescopii,C,050.0,418.7,B,1 +Trianguli,A,793.4,031.8,B,1 +Trianguli,B,795.8,027.0,B,1 +Trianguli,C,806.2,031.8,R,1 +Tucanae,A,400.0,543.7,G,1 +Tucanae,B,393.7,562.5,O,1 +Tucanae,C,408.3,551.3,R,1 +Vega,*,033.3,975.0,R,1 +Vela,*,334.5,193.1,Y,1 +Velorum,A,086.0,406.5,B,1 +Velorum,B,092.6,397.2,R,1 +Virginis,A,029.1,325.0,G,1 +Virginis,B,050.1,325.9,G,1 +Virginis,C,079.1,327.0,R,1 +Virginis,D,110.4,333.3,W,1 +Vitalis,A,300.0,350.0,B,1 +Vitalis,B,318.7,337.5,B,1 +Vitalis,C,308.3,367.4,R,1 +Vitalis,D,277.0,362.5,R,1 +Volantis,A,095.1,177.0,Y,1 +Volantis,B,114.0,184.7,W,1 +Volantis,C,104.8,191.9,G,1 +Volantis,D,097.7,195.3,Y,1 +Volantis,E,070.5,183.8,G,1 +Volantis,F,073.6,173.7,B,2 +Volantis,G,065.0,164.6,G,1 +Vulpeculae,A,365.4,258.7,G,3 +Vulpeculae,B,364.1,251.2,G,1 +Vulpeculae,C,371.3,253.7,G,1 +Vulpeculae,D,372.1,261.9,G,1 +Vulpeculae,E,366.8,266.6,G,1 +Vulpeculae,F,360.8,263.7,G,1 +Vulpeculae,G,358.7,256.6,G,1 +Wolf,A,160.1,174.6,R,1 +Wolf,B,166.6,181.2,Y,1 +Zeeman,*,335.2,194.0,W,3 diff --git a/tools/map/stringbank.c b/tools/map/stringbank.c new file mode 100755 index 000000000..059c850d7 --- /dev/null +++ b/tools/map/stringbank.c @@ -0,0 +1,106 @@ +/* stringbank.c, Copyright (c) 2005 Michael C. Martin */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope thta it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Se the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include + +#include "stringbank.h" + +#define CHUNK_SIZE (1024 - sizeof (void *) - sizeof (int)) + +typedef struct _stringbank_chunk { + char data[CHUNK_SIZE]; + int len; + struct _stringbank_chunk *next; +} chunk; + +static chunk *bank = NULL; + +static void +add_chunk (void) +{ + chunk *n = malloc (sizeof (chunk)); + n->len = 0; + n->next = bank; + bank = n; +} + +const char * +StringBank_AddString (const char *str) +{ + int len = strlen (str); + chunk *x = bank; + if (len > CHUNK_SIZE) + return NULL; + while (x) { + int remaining = CHUNK_SIZE - x->len; + if (len < remaining) { + char *result = x->data + x->len; + strcpy (result, str); + x->len += len + 1; + return result; + } + x = x->next; + } + /* No room in any currently existing chunk */ + add_chunk (); + strcpy (bank->data, str); + bank->len += len + 1; + return bank->data; +} + +const char * +StringBank_AddOrFindString (const char *str) +{ + int len = strlen (str); + chunk *x = bank; + if (len > CHUNK_SIZE) + return NULL; + while (x) { + int i = 0; + while (i < x->len) { + if (!strcmp (x->data + i, str)) + return x->data + i; + while (x->data[i]) i++; + i++; + } + x = x->next; + } + /* We didn't find it, so add it */ + return StringBank_AddString (str); +} + +#ifdef DEBUG + +void +StringBank_Dump (FILE *s) +{ + chunk *x = bank; + while (x) { + int i = 0; + while (i < x->len) { + fprintf (s, "\"%s\"\n", x->data + i); + while (x->data[i]) i++; + i++; + } + x = x->next; + } +} + +#endif diff --git a/tools/map/stringbank.h b/tools/map/stringbank.h new file mode 100755 index 000000000..94e0aa807 --- /dev/null +++ b/tools/map/stringbank.h @@ -0,0 +1,37 @@ +/* stringbank.h, Copyright (c) 2005 Michael C. Martin */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope thta it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Se the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _STRINGBANK_H_ +#define _STRINGBANK_H_ + +#ifdef DEBUG +#include +#endif + +/* Put str into the string bank. */ +const char *StringBank_AddString (const char *str); + +/* Put str into the string bank if it's not already there. Much slower. */ +const char *StringBank_AddOrFindString (const char *str); + +#ifdef DEBUG +/* Print out a list of the contents of the string bank to the named stream. */ +void StringBank_Dump (FILE *s); +#endif /* DEBUG */ + +#endif /* _STRINGBANK_H_ */ diff --git a/tools/map/unicode.c b/tools/map/unicode.c new file mode 100755 index 000000000..4857c2a1f --- /dev/null +++ b/tools/map/unicode.c @@ -0,0 +1,232 @@ +/* Portions Copyright (C) 2005 Serge van den Boom */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include "unicode.h" +#include "port.h" + + +// Resynchronise (skip everything starting with 0x10xxxxxx): +static inline void +resyncUTF8(const unsigned char **ptr) { + while ((**ptr & 0xc0) == 0x80) + *ptr++; +} + +// Get one character from a UTF-8 encoded string. +// *ptr will point to the start of the next character. +// Returns 0 if the encoding is bad. This can be distinguished from the +// '\0' character by checking whether **ptr == '\0' before calling this +// function. +wchar_t +getCharFromString(const unsigned char **ptr) { + wchar_t result; + + if (**ptr < 0x80) { + // 0xxxxxxx, regular ASCII + result = **ptr; + (*ptr)++; + + return result; + } + + if ((**ptr & 0xe0) == 0xc0) { + // 110xxxxx; 10xxxxxx must follow + // Value between 0x00000080 and 0x000007ff (inclusive) + result = **ptr & 0x1f; + (*ptr)++; + + if ((**ptr & 0xc0) != 0x80) + goto err; + result = (result << 6) | ((**ptr) & 0x3f); + (*ptr)++; + + if (result < 0x00000080) { + // invalid encoding - must reject + goto err; + } + return result; + } + + if ((**ptr & 0xf0) == 0xe0) { + // 1110xxxx; 10xxxxxx 10xxxxxx must follow + // Value between 0x00000800 and 0x0000ffff (inclusive) + result = **ptr & 0x0f; + (*ptr)++; + + if ((**ptr & 0xc0) != 0x80) + goto err; + result = (result << 6) | ((**ptr) & 0x3f); + (*ptr)++; + + if ((**ptr & 0xc0) != 0x80) + goto err; + result = (result << 6) | ((**ptr) & 0x3f); + (*ptr)++; + + if (result < 0x00000800) { + // invalid encoding - must reject + goto err; + } + return result; + } + + if ((**ptr & 0xf8) == 0xf0) { + // 11110xxx; 10xxxxxx 10xxxxxx 10xxxxxx must follow + // Value between 0x00010000 and 0x0010ffff (inclusive) + result = **ptr & 0x07; + (*ptr)++; + + if ((**ptr & 0xc0) != 0x80) + goto err; + result = (result << 6) | ((**ptr) & 0x3f); + (*ptr)++; + + if ((**ptr & 0xc0) != 0x80) + goto err; + result = (result << 6) | ((**ptr) & 0x3f); + (*ptr)++; + + if ((**ptr & 0xc0) != 0x80) + goto err; + result = (result << 6) | ((**ptr) & 0x3f); + (*ptr)++; + + if (result < 0x00010000) { + // invalid encoding - must reject + goto err; + } + return result; + } + +err: + fprintf(stderr, "Warning: Invalid UTF8 sequence.\n"); + + // Resynchronise (skip everything starting with 0x10xxxxxx): + resyncUTF8(ptr); + + return 0; +} + +size_t +utf8StringCount(const unsigned char *start) { + size_t count = 0; + wchar_t ch; + + for (;;) { + ch = getCharFromString(&start); + if (ch == '\0') + return count; + count++; + } +} + +// Locates a wide char (ch) in a UTF-8 string (pStr) +// returns the char positions when found +// -1 when not found +int +utf8StringPos (const unsigned char *pStr, wchar_t ch) +{ + int pos; + + for (pos = 0; *pStr != '\0'; ++pos) + { + if (getCharFromString (&pStr) == ch) + return pos; + } + + if (ch == '\0' && *pStr == '\0') + return pos; + + return -1; +} + +// Safe version of strcpy(), somewhat analogous to strncpy() +// except it guarantees a 0-term when size > 0 +// when size == 0, returns NULL +unsigned char * +utf8StringCopy (unsigned char *dst, size_t size, const unsigned char *src) +{ + if (size == 0) + return 0; + + strncpy (dst, src, size); + dst[size - 1] = '\0'; + + return dst; +} + +// Decodes a UTF-8 string (start) into a wide char string (wstr) +// returns number of chars decoded and stored, not counting 0-term +// any chars that do not fit are truncated +// wide string term 0 is always appended, unless the destination +// buffer is 0 chars long +size_t +getWideFromString(wchar_t *wstr, size_t maxcount, const unsigned char *start) +{ + wchar_t *next; + + if (maxcount == 0) + return 0; + + // always leave room for 0-term + --maxcount; + + for (next = wstr; maxcount > 0; ++next, --maxcount) + { + *next = getCharFromString(&start); + if (*next == 0) + break; + } + + *next = 0; // term + + return next - wstr; +} + +int +isWideGraphChar(wchar_t ch) +{ // this is not technically sufficient, but close enough for us + // we'll consider all non-control (CO and C1) chars in 'graph' class + return (ch > 0xa0) || (ch > 0x20 && ch < 0x7f); +} + +int +isWidePrintChar(wchar_t ch) +{ // this is not technically sufficient, but close enough for us + // chars in 'print' class are 'graph' + 'space' classes + // the only space we currently have defined is 0x20 + return (ch == 0x20) || isWideGraphChar(ch); +} + +wchar_t +toWideUpper(wchar_t ch) +{ // this is a very basic Latin-1 implementation + // just to get things going + return (ch < 0x100) ? toupper(ch) : ch; +} + +wchar_t +toWideLower(wchar_t ch) +{ // this is a very basic Latin-1 implementation + // just to get things going + return (ch < 0x100) ? tolower(ch) : ch; +} diff --git a/tools/map/unicode.h b/tools/map/unicode.h new file mode 100755 index 000000000..e0dcc0020 --- /dev/null +++ b/tools/map/unicode.h @@ -0,0 +1,37 @@ +/* Portions Copyright (C) 2005 Serge van den Boom */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _UNICODE_H +#define _UNICODE_H + +#include + +wchar_t getCharFromString(const unsigned char **ptr); +size_t utf8StringCount(const unsigned char *start); +int utf8StringPos (const unsigned char *pStr, wchar_t ch); +unsigned char *utf8StringCopy (unsigned char *dst, size_t size, + const unsigned char *src); +size_t getWideFromString(wchar_t *wstr, size_t maxcount, + const unsigned char *start); +int isWideGraphChar(wchar_t ch); +int isWidePrintChar(wchar_t ch); +wchar_t toWideUpper(wchar_t ch); +wchar_t toWideLower(wchar_t ch); + +#endif /* _UNICODE_H */ +