/** ** fdv_bgi.c -- driver for Borland BGI font file format ** ** Copyright (c) 1995 Csaba Biegl, 820 Stirrup Dr, Nashville, TN 37221 ** [e-mail: csaba@vuse.vanderbilt.edu] ** ** This file is part of the GRX graphics library. ** ** The GRX graphics library is free software; you can redistribute it ** and/or modify it under some conditions; see the "copying.grx" file ** for details. ** ** This library 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. ** ** Contrib by Christian Domp (alma.student.uni-kl.de) See "doc/contrib.doc" ** Contributions by: (See "doc/credits.doc" for details) ** Hartmut Schirmer (hsc@techfak.uni-kiel.de) ** **/ #include #include #include "libgrx.h" #include "grfontdv.h" #include "allocate.h" #include "arith.h" #include "memfill.h" #include "ordswap.h" #include "fonts/fdv_bgi.h" /* This is based on the font code in Hartmut Schirmer's BCC2GRX package */ /* This code requires packed structs. Should be revised for ** ** better portability hsc, 980427 */ #ifndef SEEK_SET #define SEEK_SET 0 #endif #ifndef SEEK_END #define SEEK_END 2 #endif static GR_int8 *fdata = NULL; static GR_int8u *wtable = NULL; static GR_int16u *offsets = NULL; static GR_int8u *vecdata = NULL; static int *realwdt = NULL; static int *xoffset = NULL; static int realhgt = 0; static int yoffset = 0; static BGIfontFileHeader *fhdr = NULL; static BGIfontHeaderType *fhtp = NULL; static void cleanup(void) { if(fdata) farfree(fdata); if(realwdt) farfree(realwdt); fdata = NULL; realwdt = NULL; } /* fix up up sizes to account for out of box characters */ static void fixlimits(void) { int i,ymin = 32000,ymax = -32000; int orighgt = fhtp->org_to_cap - fhtp->org_to_dec; for(i = 0; i < fhtp->nchrs; i++) { int xpos = 0,ypos = 0,xend,yend; int xmin = 32000,xmax = -32000; GR_int16u *vp = (GR_int16u *)(vecdata + offsets[i]); for( ; ; vp++) { switch(SV_COMMAND(*vp)) { case SVC_END: break; case SVC_MOVE: xpos = SV_XCOORD(*vp); ypos = fhtp->org_to_cap - SV_YCOORD(*vp); continue; case SVC_SCAN: /* what to do here ? */ continue; case SVC_DRAW: xend = SV_XCOORD(*vp); yend = fhtp->org_to_cap - SV_YCOORD(*vp); xmin = imin(xmin,imin(xpos,xend)); ymin = imin(ymin,imin(ypos,yend)); xmax = imax(xmax,imax(xpos,xend)); ymax = imax(ymax,imax(ypos,yend)); xpos = xend; ypos = yend; continue; } break; } xoffset[i] = imax(0,(-xmin)); realwdt[i] = imax(1,(imax((xmax + 1),wtable[i]) + xoffset[i])); DBGPRINTF(DBG_FONT,( "character %3d: origwdt=%-3d realwdt=%-3d xoffset=%-3d %c\n", (i + fhtp->firstch), wtable[i], realwdt[i], xoffset[i], (realwdt[i] > wtable[i]) ? '*' : ' ' )); } yoffset = imax(0,(-ymin)); realhgt = imax((ymax + 1),orighgt) + yoffset; DBGPRINTF(DBG_FONT,( "FONT orighgt=%-3d realhgt=%-3d yoffset=%-3d\n", orighgt, realhgt, yoffset )); } static int openfile(char *fname) { GR_int8 *p; FILE *fp; long flen; int res; GRX_ENTER(); res = FALSE; do { cleanup(); fp = fopen(fname,"rb"); if(!fp) break; /* FALSE */ fseek(fp,0L,SEEK_END); flen = ftell(fp); fseek(fp,0L,SEEK_SET); if((flen <= (signed long)(sizeof(*fhdr) + sizeof(*fhtp))) || (flen != (signed long)((size_t)flen))) break; /* FALSE */ fdata = farmalloc((size_t)flen); if (!fdata) break; /* FALSE */ if (fread(fdata,1,(size_t)flen,fp) != (size_t)flen) break; /* FALSE */ fclose(fp); fp = NULL; if (strncmp(fdata,FILEMARKER,strlen(FILEMARKER)) != 0) break; /*FALSE, magic code not found */ p = strchr(fdata,MARKEREND); /* skip copyright text */ if (!p || ((++p) > &fdata[128 - sizeof(*fhdr)])) break; /* FALSE */ fhdr = (BGIfontFileHeader *)p; # if BYTE_ORDER==BIG_ENDIAN _GR_swap16u(&fhdr->header_size); _GR_swap16u(&fhdr->font_size); # endif fhtp = (BGIfontHeaderType *)(fdata + fhdr->header_size); # if BYTE_ORDER==BIG_ENDIAN _GR_swap16u(&fhtp->nchrs); _GR_swap16u(&fhtp->cdefs); # endif if (fhtp->sig != SIGBYTE) break; /* FALSE */ offsets = (GR_int16u *)(fhtp + 1); wtable = (GR_int8u *)(offsets + fhtp->nchrs); vecdata = (GR_int8u *)((GR_int8u *)fhtp + fhtp->cdefs); realwdt = farmalloc(sizeof(int) * fhtp->nchrs * 2); xoffset = realwdt + fhtp->nchrs; if(!realwdt) break; /* FALSE */ fixlimits(); res = TRUE; } while (0); if (!res) { cleanup(); if (fp) fclose(fp); } GRX_RETURN(res); } static unsigned int avgwidth(void) { unsigned int i,total = 0; for(i = 0; i < fhtp->nchrs; i++) total += realwdt[i]; return((total + (fhtp->nchrs >> 1)) / fhtp->nchrs); } static int header(GrFontHeader *hdr) { if(!fdata) return(FALSE); strcpy(hdr->family,"BGI"); memcpy(hdr->name,fhdr->font_name,sizeof(fhdr->font_name)); hdr->name[sizeof(fhdr->font_name)] = '\0'; hdr->proportional = TRUE; hdr->scalable = TRUE; hdr->preloaded = FALSE; hdr->modified = GR_FONTCVT_NONE; hdr->width = avgwidth(); hdr->height = realhgt; hdr->baseline = fhtp->org_to_cap - fhtp->org_to_base + yoffset; hdr->ulheight = imax(1,(hdr->height / 15)); hdr->ulpos = hdr->height - hdr->ulheight; hdr->minchar = fhtp->firstch; hdr->numchars = fhtp->nchrs; hdr->encoding = 0; /* GR_FONTENC_UNKNOWN */ DBGPRINTF(DBG_FONT,( "Font header:\n" " name = %s\n" " family = %s\n" " proportional = %d\n" " scalable = %d\n" " preloaded = %d\n" " modified = %d\n" " width = %d\n" " height = %d\n" " baseline = %d\n" " ulheight = %d\n" " ulpos = %d\n" " minchar = %d\n" " numchars = %d\n", hdr->name, hdr->family, hdr->proportional, hdr->scalable, hdr->preloaded, hdr->modified, hdr->width, hdr->height, hdr->baseline, hdr->ulheight, hdr->ulpos, hdr->minchar, hdr->numchars )); return(TRUE); } static int charwdt(int chr) { chr -= fhtp->firstch; if(!fdata) return(-1); if((unsigned int)chr >= (unsigned int)fhtp->nchrs) return(-1); DBGPRINTF(DBG_FONT,("charwdt for %d is %d\n",(chr + fhtp->firstch),realwdt[chr])); return(realwdt[chr]); } static void bitline(int x1,int y1,int x2,int y2,char *buffer,int pitch) { int dx = x2 - x1; int dy = y2 - y1; int xstep = (dx < 0) ? ((dx = -dx),(-1)) : 1; int ystep = ((dy < 0) ? ((dy = -dy),(-pitch)) : pitch) << 3; unsigned int addr = ((y1 * pitch) << 3) + x1; int count,error,errsub,erradd; unsigned int step1,step2; if(dy > dx) { count = dy + 1; error = dy >> 1; erradd = dy; errsub = dx; step1 = ystep; step2 = xstep + ystep; } else { count = dx + 1; error = dx >> 1; erradd = dx; errsub = dy; step1 = xstep; step2 = xstep + ystep; } do { buffer[addr >> 3] |= (0x80U >> (addr & 7)); if((error -= errsub) < 0) { error += erradd; addr += step2; } else { addr += step1; } } while(--count); } static int bitmap(int chr,int w,int h,char *buffer) { int xmul,xdiv,ymul,ydiv; int xpos,ypos,xend,yend; int offs; GR_int16u *vp; chr -= fhtp->firstch; if(!fdata) return(FALSE); if((unsigned int)chr >= (unsigned int)fhtp->nchrs) return(FALSE); if((w <= 0) || (h <= 0)) return(FALSE); xmul = w - 1; xdiv = realwdt[chr] - 1; ymul = h - 1; ydiv = realhgt - 1; DBGPRINTF(DBG_FONT,( "bitmap for %d, origsize = %d %d, rendered = %d %d\n", (chr + fhtp->firstch), (xdiv + 1),(ydiv + 1), (xmul + 1),(ymul + 1) )); vp = (GR_int16u *)(vecdata + offsets[chr]); offs = (w + 7) >> 3; memfill_b(buffer,0,(offs * h)); if(xdiv <= 0) return(TRUE); for(xpos = ypos = 0; ; vp++) { switch(SV_COMMAND(*vp)) { case SVC_END: break; case SVC_MOVE: xpos = SV_XCOORD(*vp) + xoffset[chr]; ypos = fhtp->org_to_cap - SV_YCOORD(*vp) + yoffset; DBGPRINTF(DBG_FONT,( " cmd=0x%04x, move %-3d %d\n", *vp,xpos,ypos )); continue; case SVC_SCAN: /* what to do here ? */ DBGPRINTF(DBG_FONT,(" cmd=0x%04x **** SCAN COMMAND FOUND ****\n",*vp)); continue; case SVC_DRAW: xend = SV_XCOORD(*vp) + xoffset[chr]; yend = fhtp->org_to_cap - SV_YCOORD(*vp) + yoffset; DBGPRINTF(DBG_FONT,( " cmd=0x%04x, vector %-3d %-3d [ %-3d %-3d ] %c\n", *vp,xend,yend,xpos,ypos, ((((unsigned int)xend > (unsigned int)xdiv) || ((unsigned int)yend > (unsigned int)ydiv) || ((unsigned int)xpos > (unsigned int)xdiv) || ((unsigned int)ypos > (unsigned int)ydiv)) ? '*' : ' ' ) )); bitline( urscale(xpos,xmul,xdiv),urscale(ypos,ymul,ydiv), urscale(xend,xmul,xdiv),urscale(yend,ymul,ydiv), buffer,offs ); xpos = xend; ypos = yend; continue; } break; } return(TRUE); } GrFontDriver _GrFontDriverBGI = { "BGI", /* driver name (doc only) */ ".chr", /* font file extension */ TRUE, /* scalable */ openfile, /* file open and check routine */ header, /* font header reader routine */ charwdt, /* character width reader routine */ bitmap, /* character bitmap reader routine */ cleanup /* cleanup routine */ };