Tools: map generator maintenance; added SVG output driver (from Jan Lönnberg, bug #1100); attempt to load fonts with various filename capitalization

git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@3665 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
avolkov
2011-08-03 20:27:14 +00:00
parent 35281c14c0
commit 62a291f2c2
7 changed files with 588 additions and 33 deletions
+10 -5
View File
@@ -3,22 +3,27 @@
#
# You may need to compile or install libpng and/or zlib before
# compiling this.
# When building on Cygwin, do not use Cygwin-supplied libpng.
#
TARGET = mapgen
# These flags are needed to get it to compile with libpngX.dll on CYGWIN
#CYGWINFLAGS = -DPNG_USE_DLL
CYGWINFLAGS =
PNGFLAGS = -I.
PNGFLAGS = -I/usr/include/libpng12
SDLFLAGS = $(shell sdl-config --cflags)
CC = gcc
CFLAGS += -W -Wall -O0 # -g
LIBS = -L/usr/local/lib -lpng -lm -lSDL_ttf -lSDL_image
LIBS = -L/usr/local/lib -lpng12 -lSDL_ttf -lSDL_image
LDFLAGS += $(shell sdl-config --libs)
# This is needed for Cygwin; -L. so that we can link with private libpng
#LDFLAGS += -mconsole -L.
BINS = $(TARGET) $(TARGET).exe
OBJS = mapgen.o alist.o scriptlib.o stringbank.o unicode.o sdlpngdrv.o SDL_gfxPrimitives.o port.o
OBJS = mapgen.o alist.o scriptlib.o stringbank.o unicode.o port.o
OBJS += SDL_gfxPrimitives.o
OBJS += sdlpngdrv.o
OBJS += sdlsvgdrv.o
.SUFFIXES: .c .o
@@ -28,7 +33,7 @@ OBJS = mapgen.o alist.o scriptlib.o stringbank.o unicode.o sdlpngdrv.o SDL_gfxPr
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) -o $(TARGET) $(OBJS) $(LIBS) $(LDFLAGS)
$(CC) -o $(TARGET) $(OBJS) $(LDFLAGS) $(LIBS)
clean:
rm -f $(BINS) *.o
+4 -1
View File
@@ -30,10 +30,12 @@
#endif
extern const mg_driver_t sdlpng_drv;
extern const mg_driver_t sdlsvg_drv;
static const mg_driver_t* drvs[] =
{
&sdlpng_drv,
&sdlsvg_drv,
0 /* term */
};
static const mg_driver_t* drv;
@@ -355,7 +357,7 @@ static void usage()
static void parseArguments(int argc, char *argv[], options_t *opts)
{
char ch;
int ch;
opterr = 0;
memset(opts, 0, sizeof (options_t));
@@ -395,6 +397,7 @@ static void parseArguments(int argc, char *argv[], options_t *opts)
;
}
}
// TODO: this does not work with all versions of getopt()
optind = 1; // let the driver handle the rest
}
+11 -7
View File
@@ -25,7 +25,7 @@ CFG=mapgen - Win32 Debug
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=xicl6.exe
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "mapgen - Win32 Release"
@@ -42,13 +42,13 @@ RSC=rc.exe
# 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 CPP /nologo /MD /W3 /GX /O2 /I "..\..\sc2\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
LINK32=link.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
@@ -66,13 +66,13 @@ LINK32=xilink6.exe
# 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 CPP /nologo /MD /W3 /Gm /GX /ZI /Od /I "..\..\sc2\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
LINK32=link.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
@@ -99,11 +99,11 @@ SOURCE=.\config.h
# End Source File
# Begin Source File
SOURCE=..\..\src\getopt\getopt.c
SOURCE=..\..\sc2\src\getopt\getopt.c
# End Source File
# Begin Source File
SOURCE=..\..\src\getopt\getopt.h
SOURCE=..\..\sc2\src\getopt\getopt.h
# End Source File
# Begin Source File
@@ -143,6 +143,10 @@ SOURCE=.\sdlpngdrv.c
# End Source File
# Begin Source File
SOURCE=.\sdlsvgdrv.c
# End Source File
# Begin Source File
SOURCE=.\stringbank.c
# End Source File
# Begin Source File
+22
View File
@@ -20,3 +20,25 @@ strupr (char *str)
#endif
#ifdef _MSC_VER
// MSVC does not have snprintf() and vsnprintf(). It does have a _snprintf()
// and _vsnprintf(), but these do not terminate a truncated string as
// the C standard prescribes.
#include <stdio.h>
#include <stdarg.h>
int
snprintf(char *str, size_t size, const char *format, ...)
{
int result;
va_list args;
va_start (args, format);
result = _vsnprintf (str, size, format, args);
if (str != NULL && size != 0)
str[size - 1] = '\0';
va_end (args);
return result;
}
#endif /* _MSC_VER */
+5
View File
@@ -26,5 +26,10 @@
# define strcasecmp stricmp
#endif
#ifdef _MSC_VER
// Defined in port.c
int snprintf(char *str, size_t size, const char *format, ...);
#endif /* _MSC_VER */
#endif /* _PORT_H */
+37 -20
View File
@@ -126,21 +126,6 @@ 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;
@@ -197,7 +182,7 @@ static void drv_usage(void)
static int parseArguments(int argc, char* argv[])
{
char ch;
int ch;
while (-1 != (ch = getopt(argc, argv, "-f:no:")))
{
@@ -401,9 +386,42 @@ static int drv_write(void)
return EXIT_SUCCESS;
}
static mg_font_t drv_loadFont(const char* name, double size, const char* filename)
static TTF_Font* openFont(const char* filename, int size)
{
char buf[512];
char namebuf[128];
TTF_Font* font;
strncpy(namebuf, filename, sizeof(namebuf));
namebuf[sizeof(namebuf) - 1] = '\0';
// first try the proper case filename
snprintf(buf, sizeof(buf), "%s/%s", fontdir, namebuf);
font = TTF_OpenFont(buf, size);
if (font)
return font;
// then try the lowercase filename
strlwr(namebuf);
snprintf(buf, sizeof(buf), "%s/%s", fontdir, namebuf);
font = TTF_OpenFont(buf, size);
if (font)
return font;
// last try the uppercase filename
strupr(namebuf);
snprintf(buf, sizeof(buf), "%s/%s", fontdir, namebuf);
font = TTF_OpenFont(buf, size);
if (font)
return font;
mg_verbose(2, "TTF_OpenFont(): %s\n", TTF_GetError());
return 0;
}
static mg_font_t drv_loadFont(const char* name, double size, const char* filename)
{
struct mg_font* fnt;
if (!filename)
@@ -416,9 +434,8 @@ static mg_font_t drv_loadFont(const char* name, double size, const char* filenam
if (!fnt)
return 0;
fnt->size = inchToPixelsY(size);
fnt->name = strcopy(name ? name : "<Unknown>");
sprintf(buf, "%s/%s", fontdir, filename);
fnt->font = TTF_OpenFont(buf, fnt->size);
fnt->name = strdup(name ? name : "<Unknown>");
fnt->font = openFont(filename, fnt->size);
if (!fnt->font)
{
free(fnt);
+499
View File
@@ -0,0 +1,499 @@
/*
* UQM Starmap image generator
* SDL/SVG driver implementation
*
* Uses: SDL, SDL_ttf
*
*
* The GPL applies
*
*/
#include "mapdrv.h"
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <errno.h>
#include "SDL_image.h"
#include "SDL.h"
#include "SDL_ttf.h"
static double width, height;
struct mg_font
{
char* name;
TTF_Font* font;
double size;
};
struct mg_image
{
SDL_Surface* img;
char *filename;
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_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 int drv_setResolution(int dpi_x, int dpi_y);
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 sdlsvg_drv =
{
"sdlsvg", // name
"SDL/SVG 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,
};
static int parseArguments(int argc, char* argv[]);
static const char* fontdir = ".";
static const char* outdev = "starmap.svg";
static FILE* fout;
static int dpix, dpiy;
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 char colbuffer[8];
static char *color_string(mg_color_t color)
{
snprintf(colbuffer, 8, "#%2.2x%2.2x%2.2x", color.r, color.g, color.b);
return colbuffer;
}
static char alphabuffer[6];
static char *alpha_string(mg_color_t color)
{
snprintf(alphabuffer, 6, "%1.3f", color.a/255.0);
return alphabuffer;
}
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)
{
if (fout)
fclose(fout);
fout = 0;
TTF_Quit();
SDL_Quit();
return EXIT_SUCCESS;
}
static void drv_usage(void)
{
mg_verbose(0,
"sdlsvg driver : [-f <fontdir>] [-o <outfile>]\n"
"Options:\n"
"\t-f dir where font files are located\n"
"\t-o save image as <outfile> (default is 'starmap.svg')\n"
);
}
static int parseArguments(int argc, char* argv[])
{
int ch;
while (-1 != (ch = getopt(argc, argv, "-f:o:")))
{
switch (ch)
{
case 'f':
fontdir = optarg;
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 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)
{
width = w;
height = h;
fout = fopen(outdev, "wt");
if (!fout)
{
mg_verbose(1, "Cannot open file '%s' -- %s\n", outdev, strerror(errno));
return EXIT_FAILURE;
}
fprintf(fout, "<?xml version=\"1.0\" standalone=\"no\"?>\n");
fprintf(fout, "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n");
fprintf(fout, "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
fprintf(fout, "<svg width=\"%fin\" height=\"%fin\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" version=\"1.1\">\n", w, h);
return EXIT_SUCCESS;
}
static int drv_end(void)
{
if (fout)
{
fprintf(fout, "</svg>\n");
fclose(fout);
fout = 0;
}
return EXIT_SUCCESS;
}
static int drv_write(void)
{
if (!fout)
return EXIT_FAILURE;
return EXIT_SUCCESS;
}
static TTF_Font* openFont(const char* filename, int size)
{
char buf[512];
char namebuf[128];
TTF_Font* font;
strncpy(namebuf, filename, sizeof(namebuf));
namebuf[sizeof(namebuf) - 1] = '\0';
// first try the proper case filename
snprintf(buf, sizeof(buf), "%s/%s", fontdir, namebuf);
font = TTF_OpenFont(buf, size);
if (font)
return font;
// then try the lowercase filename
strlwr(namebuf);
snprintf(buf, sizeof(buf), "%s/%s", fontdir, namebuf);
font = TTF_OpenFont(buf, size);
if (font)
return font;
// last try the uppercase filename
strupr(namebuf);
snprintf(buf, sizeof(buf), "%s/%s", fontdir, namebuf);
font = TTF_OpenFont(buf, size);
if (font)
return font;
mg_verbose(2, "TTF_OpenFont(): %s\n", TTF_GetError());
return 0;
}
static mg_font_t drv_loadFont(const char* name, double size, const char* filename)
{
struct mg_font* fnt;
if (!filename)
{
mg_verbose(1, "sdlsvg: filename not specified for font '%s'\n", name);
return 0;
}
fnt = calloc(1, sizeof(*fnt));
if (!fnt)
return 0;
fnt->size = size;
fnt->name = strdup(name ? name : "<Unknown>");
fnt->font = openFont(filename, inchToPixelsY(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->filename = strdup(filename);
if (!img->filename)
{
drv_freeImage(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->filename)
free(img->filename);
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 int clipon = 0;
static int clipcount = 0;
static void drv_setClipRect(const mg_rectf_t* r)
{
if (clipon)
fprintf(fout, "</g>\n");
if (!r)
clipon = 0;
else
{
mg_color_t t;
fprintf(fout, "<clipPath id=\"clip%d\">\n", clipcount);
t.r = t.g = t.b = t.a = 255;
drv_drawFilledRect(r, t);
fprintf(fout, "</clipPath>\n");
clipon = 1;
fprintf(fout, "<g clip-path=\"url(#clip%d)\">\n", clipcount++);
}
}
static void drv_drawPixel(double xf, double yf, mg_color_t color, double weightf)
{
drv_drawLine(xf, yf, xf, yf, color, weightf);
}
static void drv_drawLine(double x0f, double y0f, double x1f, double y1f, mg_color_t color, double weightf)
{
fprintf(fout,
"<line x1=\"%fin\" y1=\"%fin\" x2=\"%fin\" y2=\"%fin\" stroke=\"%s\" stroke-width=\"%fin\" opacity=\"%s\"/>\n",
x0f, y0f, x1f, y1f, color_string(color), weightf, alpha_string(color));
}
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)
{
if (!r)
{
mg_rectf_t t;
t.x = t.y = 0;
t.w = width;
t.h = height;
drv_drawFilledRect(&t, color);
}
else
{
fprintf(fout,
"<rect x=\"%fin\" y=\"%fin\" width=\"%fin\" height=\"%fin\" stroke=\"none\" fill=\"%s\" opacity=\"%s\"/>\n",
r->x, r->y, r->w, r->h, color_string(color),
alpha_string(color));
}
}
static void drv_drawEllipse(double xcf, double ycf, double xrf, double yrf, mg_color_t color, double weight)
{
fprintf(fout,
"<ellipse cx=\"%fin\" cy=\"%fin\" rx=\"%fin\" ry=\"%fin\" stroke=\"%s\" opacity=\"%s\" fill=\"none\" stroke-width=\"%fin\"/>\n",
xcf, ycf, xrf, yrf, color_string(color), alpha_string(color), weight);
}
static void drv_drawFilledEllipse(double xcf, double ycf, double xrf, double yrf, mg_color_t color)
{
fprintf(fout,
"<ellipse cx=\"%fin\" cy=\"%fin\" rx=\"%fin\" ry=\"%fin\" fill=\"%s\" opacity=\"%s\"/>\n",
xcf, ycf, xrf, yrf, color_string(color), alpha_string(color));
}
static void drv_drawImage(double xf, double yf, struct mg_image* img)
{
fprintf(fout,
"<image xlink:href=\"%s\" x=\"%fin\" y=\"%fin\" width=\"%fin\" height=\"%fin\"/>\n",
img->filename, xf, yf, img->width, img->height);
}
static void drv_drawText(struct mg_font* fnt, double xf, double yf, const unsigned char* utf8str, mg_color_t color)
{
mg_rectf_t t;
if (!fnt || !utf8str)
return;
drv_getTextSize(fnt, utf8str, &t);
yf += t.h;
fprintf(fout,
"<text x=\"%fin\" y=\"%fin\" font-size=\"%f\" font-family=\"%s\" fill=\"%s\" dominant-baseline=\"text-after-edge\" opacity=\"%s\">\n",
xf, yf, fnt->size*96.0, fnt->name, color_string(color), alpha_string(color));
fprintf(fout, "%s</text>", utf8str);
}
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, (const char*) utf8str, &w, &h);
r->w = (double)w / dpix;
r->h = (double)h / dpiy;
}