PLIB 1.8.5+ r2173 from http://plib.svn.sourceforge.net/svnroot/plib/trunk
This commit is contained in:
10
tools/src/Makefile.am
Normal file
10
tools/src/Makefile.am
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
SUBDIRS = af2rgb
|
||||
|
||||
bin_PROGRAMS = plibconvert
|
||||
|
||||
plibconvert_SOURCES = plibconvert.cxx
|
||||
|
||||
plibconvert_LDADD = -lplibssg -lplibsg -lplibul
|
||||
|
||||
|
||||
8
tools/src/af2rgb/Makefile.am
Normal file
8
tools/src/af2rgb/Makefile.am
Normal file
@@ -0,0 +1,8 @@
|
||||
noinst_PROGRAMS = af2rgb
|
||||
|
||||
af2rgb_SOURCES = af2rgb.cxx
|
||||
|
||||
af2rgb_LDADD = -lplibssg -lplibsg -lplibul
|
||||
|
||||
EXTRA_DIST = af2rgb.dsp
|
||||
|
||||
206
tools/src/af2rgb/af2rgb.cxx
Normal file
206
tools/src/af2rgb/af2rgb.cxx
Normal file
@@ -0,0 +1,206 @@
|
||||
// Convert textures made for MSFS to rgb textures.
|
||||
|
||||
|
||||
// Written by Wolfram Kuss (w_kus@rz-online.de) in dec 2000 / jan 2001
|
||||
// with some help by Marten Str<74>mberg.
|
||||
//
|
||||
// Published as part of Steve Baker's PLIB
|
||||
// License is GPL
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <plib/ul.h>
|
||||
#include <plib/ssgMSFSPalette.h>
|
||||
|
||||
|
||||
// *.?af textures are always 256 x 256:
|
||||
#define XSIZE 256
|
||||
#define YSIZE 256
|
||||
#define ZSIZE 4
|
||||
|
||||
static unsigned char texelsR [ XSIZE * YSIZE ];
|
||||
static unsigned char texelsG [ XSIZE * YSIZE ];
|
||||
static unsigned char texelsB [ XSIZE * YSIZE ];
|
||||
static unsigned char texelsA [ XSIZE * YSIZE ];
|
||||
|
||||
static FILE *fd;
|
||||
|
||||
static size_t writeByte (unsigned char x )
|
||||
{
|
||||
return fwrite ( & x, sizeof(unsigned char), 1, fd ) ;
|
||||
}
|
||||
|
||||
static size_t writeShort (unsigned short x )
|
||||
{
|
||||
|
||||
if (ulIsLittleEndian) // this is the other way round compared to normally.
|
||||
// obviously, this is because the .rgb format comes from SGI.
|
||||
ulEndianSwap(&x);
|
||||
|
||||
|
||||
return fwrite( & x, sizeof(unsigned short), 1, fd ) ;
|
||||
}
|
||||
|
||||
static size_t writeInt (unsigned int x)
|
||||
{
|
||||
if (ulIsLittleEndian) // this is the other way round compared to normally.
|
||||
// obviously, this is because the .rgb format comes from SGI.
|
||||
ulEndianSwap(&x);
|
||||
|
||||
return fwrite( & x, sizeof(unsigned int), 1, fd ) ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#define SGI_IMG_MAGIC 0x01DA
|
||||
|
||||
static int writeTexelsIntoSGI ( const char *fname )
|
||||
{
|
||||
|
||||
fd = fopen ( fname, "wb" ) ;
|
||||
size_t NoWritten = 0;
|
||||
|
||||
if ( fd == NULL )
|
||||
{
|
||||
ulSetError(UL_WARNING, "ssgLoadTexture: Failed to open '%s' for writing.", fname ) ;
|
||||
return false;
|
||||
}
|
||||
|
||||
// ******* write the header *****************
|
||||
|
||||
NoWritten += writeShort (SGI_IMG_MAGIC) ;
|
||||
|
||||
NoWritten += writeByte (0) ; // don't use RLE
|
||||
NoWritten += writeByte (1) ; // bpp
|
||||
NoWritten += writeShort (3) ; // dimension
|
||||
|
||||
NoWritten += writeShort ( XSIZE ) ;
|
||||
NoWritten += writeShort ( YSIZE ) ;
|
||||
NoWritten += writeShort ( ZSIZE ) ;
|
||||
NoWritten += writeInt ( 0 ) ;
|
||||
NoWritten += writeInt ( 255 ) ;
|
||||
NoWritten += writeInt ( 0 ) ; /* Dummy field */
|
||||
|
||||
int i ;
|
||||
|
||||
for ( i = 0 ; i < 80 ; i++ )
|
||||
NoWritten += writeByte ( 0 ) ; /* Name field */
|
||||
|
||||
NoWritten += writeInt ( 0 ) ; // colormap
|
||||
|
||||
for ( i = 0 ; i < 404 ; i++ )
|
||||
NoWritten += writeByte ( 0 ) ; /* Dummy field */
|
||||
|
||||
// ************ write the body ****************
|
||||
|
||||
NoWritten += fwrite ( texelsR, XSIZE, YSIZE, fd ) ;
|
||||
NoWritten += fwrite ( texelsG, XSIZE, YSIZE, fd ) ;
|
||||
NoWritten += fwrite ( texelsB, XSIZE, YSIZE, fd ) ;
|
||||
NoWritten += fwrite ( texelsA, XSIZE, YSIZE, fd ) ;
|
||||
|
||||
if(NoWritten!=91+404+4*YSIZE)
|
||||
{ ulSetError(UL_WARNING, "Only %ld records written instead of %d. Proceed at your own risc\n",
|
||||
(long)NoWritten, 91+404+4*YSIZE);
|
||||
|
||||
return false;
|
||||
}
|
||||
fclose ( fd ) ;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int loadMDLIntoTexels ( const char *fname )
|
||||
// returns TRUE on success
|
||||
{
|
||||
FILE *tfile;
|
||||
if ( (tfile = fopen(fname, "rb")) == NULL) {
|
||||
ulSetError(UL_WARNING, "ssgLoadTexture: Failed to load '%s'.", fname );
|
||||
return false;
|
||||
}
|
||||
|
||||
fseek(tfile, 0, SEEK_END);
|
||||
unsigned long file_length = ftell(tfile);
|
||||
|
||||
if (file_length != 65536) {
|
||||
ulSetError(UL_WARNING, "ssgLoadTexture: Wrong size of '%s'.", fname );
|
||||
return false;
|
||||
} else {
|
||||
fseek(tfile, 0, SEEK_SET);
|
||||
|
||||
int c = 0;
|
||||
for (int y = 0; y < 256; y++) {
|
||||
for (int x = 0; x < 256; x++) {
|
||||
unsigned char b;
|
||||
if ( fread(&b, 1, 1, tfile) != 1)
|
||||
return false;
|
||||
texelsR[c] = ssgFsTexPalette[b*4 ];
|
||||
texelsG[c] = ssgFsTexPalette[b*4 + 1];
|
||||
texelsB[c] = ssgFsTexPalette[b*4 + 2];
|
||||
texelsA[c] = ssgFsTexPalette[b*4 + 3];
|
||||
c++;
|
||||
}
|
||||
}
|
||||
fclose(tfile);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void DoAllFiles( char *sDirectoryP )
|
||||
{ char newname [ 1024 ], sDirectory[1024], sFullPath[1024]; // todo fixme
|
||||
|
||||
strcpy( sDirectory, sDirectoryP);
|
||||
if ( ( sDirectoryP[ strlen(sDirectoryP)-1 ] != '\\') &&
|
||||
( sDirectoryP[ strlen(sDirectoryP)-1 ] != '/') )
|
||||
strcat( sDirectory, "/");
|
||||
// ************** For all *.?af files in the current dir ************
|
||||
ulDir* dirp = ulOpenDir(".");
|
||||
if ( dirp != NULL )
|
||||
{
|
||||
ulDirEnt* dp;
|
||||
while ( (dp = ulReadDir(dirp)) != NULL )
|
||||
{
|
||||
if ( !dp->d_isdir )
|
||||
{ size_t len = strlen(dp->d_name );
|
||||
if ( len >4 )
|
||||
if ((dp->d_name[len-1] == 'f') || (dp->d_name[len-1] == 'F'))
|
||||
if ((dp->d_name[len-2] == 'a') || (dp->d_name[len-2] == 'A'))
|
||||
if ((dp->d_name[len-4] == '.') || (dp->d_name[len-4] == '.'))
|
||||
{ strcpy( newname, dp->d_name );
|
||||
unsigned int i;
|
||||
for (i=0; i<len; i++)
|
||||
newname [i] = tolower ( newname [i] );
|
||||
|
||||
newname[len-4] = newname[len-3];
|
||||
newname[len-3] = '.';
|
||||
newname[len-2] = 'r';
|
||||
newname[len-1] = 'g';
|
||||
newname[len] = 'b';
|
||||
newname[len+1] = 0;
|
||||
ulSetError(UL_DEBUG, "%s %s\n",dp->d_name, newname);
|
||||
// ********** convert it **************
|
||||
if ( loadMDLIntoTexels ( dp->d_name ))
|
||||
{ strcpy(sFullPath, sDirectory);
|
||||
strcat(sFullPath, newname);
|
||||
writeTexelsIntoSGI ( sFullPath ); //lint !e534
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ulCloseDir(dirp);
|
||||
}
|
||||
}
|
||||
|
||||
// converts all *.?af files from the current dir to *.rgb in the dir givven in the argument
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if ( argc > 2 )
|
||||
ulSetError(UL_WARNING, "All arguments after the first are ignored!" );
|
||||
if ( argc >= 2 )
|
||||
DoAllFiles( argv[1] );
|
||||
else
|
||||
DoAllFiles(".");
|
||||
return 0;
|
||||
}
|
||||
|
||||
102
tools/src/af2rgb/af2rgb.dsp
Normal file
102
tools/src/af2rgb/af2rgb.dsp
Normal file
@@ -0,0 +1,102 @@
|
||||
# Microsoft Developer Studio Project File - Name="af2rgb" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
||||
|
||||
CFG=af2rgb - 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 "af2rgb.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 "af2rgb.mak" CFG="af2rgb - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "af2rgb - Win32 Release" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE "af2rgb - Win32 Debug" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "af2rgb - 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" /Yu"stdafx.h" /FD /c
|
||||
# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\..\\" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c
|
||||
# SUBTRACT CPP /YX /Yc /Yu
|
||||
# ADD BASE RSC /l 0x407 /d "NDEBUG"
|
||||
# ADD RSC /l 0x407 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
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 gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib sg.lib ssg.lib ul.lib opengl32.lib /nologo /subsystem:console /machine:I386 /libpath:"..\..\..\\"
|
||||
|
||||
!ELSEIF "$(CFG)" == "af2rgb - 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" /Yu"stdafx.h" /FD /GZ /c
|
||||
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\..\..\..\\" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c
|
||||
# SUBTRACT CPP /YX /Yc /Yu
|
||||
# ADD BASE RSC /l 0x407 /d "_DEBUG"
|
||||
# ADD RSC /l 0x407 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
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 gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib sg_d.lib ssg_d.lib ul_d.lib opengl32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\..\\"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "af2rgb - Win32 Release"
|
||||
# Name "af2rgb - Win32 Debug"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\af2rgb.cxx
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# End Group
|
||||
# Begin Group "Resource Files"
|
||||
|
||||
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
||||
# End Group
|
||||
# End Target
|
||||
# End Project
|
||||
18
tools/src/afm2txf/README
Normal file
18
tools/src/afm2txf/README
Normal file
@@ -0,0 +1,18 @@
|
||||
It's definitely a tool of the "duct tape and fishing line" variety. :)
|
||||
It expects to find a ghostscript interpreter and ImageMagick's "mogrify"
|
||||
program on the command line, takes a .afm font metrics file as its sole
|
||||
argument, and expects that the font therein is accessible to ghostscript.
|
||||
Basically, it should work out of the box on most linux distributions,
|
||||
and nowhere else without a lot of work.
|
||||
|
||||
If you have a TrueType font that you want to generate:
|
||||
|
||||
export GS_FONTPATH=<wherever the font is>
|
||||
ttf2afm yourfont.ttf > whatever.afm
|
||||
font.pl whatever.afm
|
||||
|
||||
Wait for a while (at 16x downsampling, this takes 1-2 minutes on my
|
||||
Athlon 1800+), and the .txf file will appear in the current directory.
|
||||
It will have the Postscript language name of the font.
|
||||
|
||||
Andy
|
||||
283
tools/src/afm2txf/afm2txf.pl
Executable file
283
tools/src/afm2txf/afm2txf.pl
Executable file
@@ -0,0 +1,283 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
# afm2txf.pl 0.2
|
||||
#
|
||||
# Generates .txf font textures from Type 1 fonts
|
||||
# Requirements: Ghostscript, ImageMagick
|
||||
#
|
||||
# Usage:
|
||||
# afm2txf.pl whatever.afm
|
||||
#
|
||||
# Changelog:
|
||||
# 0.2 (06/28/2002): Generate fonts with proper padding
|
||||
# 0.1 (06/28/2002): Initial version
|
||||
#
|
||||
# Copyright (C) 2002 Andrew James Ross
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
|
||||
use strict;
|
||||
|
||||
my $METRICS = shift or die; # AFM file
|
||||
|
||||
# Texture size
|
||||
my $TEXSIZ = 256;
|
||||
|
||||
# Padding around each character, for mipmap separation
|
||||
my $PADDING = 4;
|
||||
|
||||
# Antialiasing multiplier. Should be 16 for production work. As low
|
||||
# as 4 works well for testing.
|
||||
my $DOWNSAMPLE = 16;
|
||||
|
||||
# The 94 printable ASCII characters (and the space) and their
|
||||
# postscript glyph names. We use names because not all postscript
|
||||
# fonts are encoded using ASCII. AFM metrics generated by ttf2afm, in
|
||||
# fact, don't have any numerical character IDs at all. In principle,
|
||||
# this mechanism will work for any 8 bit font encoding, you just have
|
||||
# to do the legwork of figuring out the name to ID mapping.
|
||||
my %CHARS = ('space'=>32, 'exclam'=>33, 'quotedbl'=>34,
|
||||
'numbersign'=>35, 'dollar'=>36, 'percent'=>37,
|
||||
'ampersand'=>38, 'quotesingle'=>39, 'parenleft'=>40,
|
||||
'parenright'=>41, 'asterisk'=>42, 'plus'=>43,
|
||||
'comma'=>44, 'hyphen'=>45, 'period'=>46, 'slash'=>47,
|
||||
'zero'=>48, 'one'=>49, 'two'=>50, 'three'=>51,
|
||||
'four'=>52, 'five'=>53, 'six'=>54, 'seven'=>55,
|
||||
'eight'=>56, 'nine'=>57, 'colon'=>58, 'semicolon'=>59,
|
||||
'less'=>60, 'equal'=>61, 'greater'=>62, 'question'=>63,
|
||||
'at'=>64, 'A'=>65, 'B'=>66, 'C'=>67, 'D'=>68, 'E'=>69,
|
||||
'F'=>70, 'G'=>71, 'H'=>72, 'I'=>73, 'J'=>74, 'K'=>75,
|
||||
'L'=>76, 'M'=>77, 'N'=>78, 'O'=>79, 'P'=>80, 'Q'=>81,
|
||||
'R'=>82, 'S'=>83, 'T'=>84, 'U'=>85, 'V'=>86, 'W'=>87,
|
||||
'X'=>88, 'Y'=>89, 'Z'=>90, 'bracketleft'=>91,
|
||||
'backslash'=>92, 'bracketright'=>93, 'asciicircum'=>94,
|
||||
'underscore'=>95, 'grave'=>96, 'a'=>97, 'b'=>98, 'c'=>99,
|
||||
'd'=>100, 'e'=>101, 'f'=>102, 'g'=>103, 'h'=>104,
|
||||
'i'=>105, 'j'=>106, 'k'=>107, 'l'=>108, 'm'=>109,
|
||||
'n'=>110, 'o'=>111, 'p'=>112, 'q'=>113, 'r'=>114,
|
||||
's'=>115, 't'=>116, 'u'=>117, 'v'=>118, 'w'=>119,
|
||||
'x'=>120, 'y'=>121, 'z'=>122, 'braceleft'=>123,
|
||||
'bar'=>124, 'braceright'=>125, 'asciitilde'=>126);
|
||||
|
||||
my %metrics = ();
|
||||
my %positions = ();
|
||||
|
||||
#
|
||||
# Parse the font metrics. This is a 5 element array. All numbers are
|
||||
# expressed as a fraction of the line spacing.
|
||||
# 0: nominal width (distance to the next character)
|
||||
# 1, 2: Coordinates of the lower left corner of the bounding box,
|
||||
# relative to the nominal position.
|
||||
# 3, 4: Size of the bounding box
|
||||
#
|
||||
print STDERR "Reading font metrics...\n";
|
||||
my $FONT;
|
||||
my @lines = `cat $METRICS`
|
||||
or die "Couldn't read metrics";
|
||||
foreach my $m (grep {/^(C|FontName) /} @lines) {
|
||||
chomp $m;
|
||||
if($m =~ /^FontName ([^\s]*)/) { $FONT = $1; next; }
|
||||
|
||||
die "No name: $m" if $m !~ /N\s+([^\s]+)\s+;/;
|
||||
my $name = $1;
|
||||
|
||||
die "No box: $m"
|
||||
if $m !~ /B\s+([-0-9]+)\s+([-0-9]+)\s+([-0-9]+)\s+([-0-9]+)\s+;/;
|
||||
my ($left, $bottom, $right, $top) = ($1/1000, $2/1000, $3/1000, $4/1000);
|
||||
|
||||
die "No width: $m" if $m !~ /WX\s+([-0-9]+)/;
|
||||
my $nomwid = $1/1000; # nominal, not physical width!
|
||||
|
||||
# The coordinates of the corner relative to the character
|
||||
# "position"
|
||||
my ($x, $y) = (-$left, -$bottom);
|
||||
my ($w, $h) = ($right-$left, $top-$bottom);
|
||||
|
||||
$metrics{$name} = [$nomwid, $x, $y, $w, $h];
|
||||
}
|
||||
|
||||
die "No FontName found in metrics" if not defined $FONT;
|
||||
|
||||
#
|
||||
# Find the height of the tallest character, and print some warnings
|
||||
#
|
||||
my $maxhgt = 0;
|
||||
foreach my $c (keys %CHARS) {
|
||||
if(!defined $metrics{$c}) {
|
||||
print STDERR "% WARNING: no metrics for char $c. Skipping.\n";
|
||||
next;
|
||||
}
|
||||
if($metrics{$c}->[4] > $maxhgt) { $maxhgt = $metrics{$c}->[4]; }
|
||||
}
|
||||
if($maxhgt == 0) {
|
||||
print STDERR "No usable characters found. Bailing out.\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
#
|
||||
# Do the layout. Keep increasing the row count until the characters
|
||||
# just fit. This isn't terribly elegant, but it's simple.
|
||||
#
|
||||
print STDERR "Laying out";
|
||||
my $rows = 1;
|
||||
my $PS;
|
||||
my $LINEHGT;
|
||||
while(!defined ($PS = genPostscript($rows))) { $rows++; }
|
||||
print STDERR " ($rows rows)\n";
|
||||
|
||||
#
|
||||
# Call ghostscript to render
|
||||
#
|
||||
print STDERR "Rendering Postscript...\n";
|
||||
my $res = $TEXSIZ * $DOWNSAMPLE;
|
||||
my $pid = open PS, "|gs -r$res -g${res}x${res} -sDEVICE=ppm -sOutputFile=$FONT.ppm > /dev/null";
|
||||
die "Couldn't spawn ghostscript interpreter" if !defined $pid;
|
||||
print PS join("\n", @$PS), "\n";
|
||||
close PS;
|
||||
waitpid($pid, 0);
|
||||
|
||||
#
|
||||
# Downsample with ImageMagick
|
||||
#
|
||||
print STDERR "Antialiasing image...\n";
|
||||
system("mogrify -geometry ${TEXSIZ}x${TEXSIZ} $FONT.ppm") == 0
|
||||
or die "Couldn't rescale $FONT.ppm";
|
||||
|
||||
#
|
||||
# Generate the .txf file
|
||||
#
|
||||
print STDERR "Generating textured font file...\n";
|
||||
|
||||
# Prune undefined glyphs
|
||||
foreach my $c (keys %metrics) {
|
||||
delete $metrics{$c} if !defined $CHARS{$c};
|
||||
}
|
||||
|
||||
sub round { sprintf "%.0f", $_[0] }
|
||||
open TXF, ">$FONT.txf" or die;
|
||||
print TXF pack "V", 0x667874ff;
|
||||
print TXF pack "V", 0x12345678;
|
||||
print TXF pack "V", 0;
|
||||
print TXF pack "V", $TEXSIZ;
|
||||
print TXF pack "V", $TEXSIZ;
|
||||
print TXF pack "V", round($TEXSIZ * $LINEHGT);
|
||||
print TXF pack "V", 0;
|
||||
print TXF pack "V", scalar(keys(%metrics));
|
||||
my @chars = sort { $CHARS{$a} <=> $CHARS{$b} } (keys %metrics);
|
||||
foreach my $c (@chars) {
|
||||
my $m = $metrics{$c};
|
||||
my $p = $positions{$c};
|
||||
my $step = round($m->[0] * $LINEHGT * $TEXSIZ);
|
||||
|
||||
# Pad the bounding box, to handle areas that outside. This can
|
||||
# happen due to thick lines in the font path, or be an artifact of
|
||||
# the downsampling.
|
||||
my $w = round($m->[3] * $LINEHGT * $TEXSIZ + 2*$PADDING);
|
||||
my $h = round($m->[4] * $LINEHGT * $TEXSIZ + 2*$PADDING);
|
||||
my $xoff = -round($m->[1] * $LINEHGT * $TEXSIZ - $PADDING);
|
||||
my $yoff = -round($m->[2] * $LINEHGT * $TEXSIZ - $PADDING);
|
||||
my $x = round($p->[0] * $TEXSIZ - $PADDING);
|
||||
my $y = round($p->[1] * $TEXSIZ - $PADDING);
|
||||
|
||||
print TXF pack "v", $CHARS{$c};
|
||||
print TXF pack "C", $w;
|
||||
print TXF pack "C", $h;
|
||||
print TXF pack "c", $xoff;
|
||||
print TXF pack "c", $yoff;
|
||||
print TXF pack "C", $step;
|
||||
print TXF pack "C", 0;
|
||||
print TXF pack "v", $x;
|
||||
print TXF pack "v", $y;
|
||||
}
|
||||
|
||||
# Read in the .ppm file, dump the duplicate color values (ghostscript
|
||||
# won't generate pgm's) and write to the end of the .txf. Remember to
|
||||
# swap the order of the rows; OpenGL textures are bottom-up.
|
||||
open PPM, "$FONT.ppm" or die;
|
||||
seek PPM, -3*$TEXSIZ*$TEXSIZ, 2 or die;
|
||||
my @rows = ();
|
||||
my $pixel;
|
||||
for(my $r=0; $r<$TEXSIZ; $r++) {
|
||||
my @row = ();
|
||||
for(my $c=0; $c<$TEXSIZ; $c++) {
|
||||
read PPM, $pixel, 3 or die;
|
||||
push @row, substr($pixel, 0, 1);
|
||||
}
|
||||
push @rows, \@row;
|
||||
}
|
||||
close PPM;
|
||||
for(my $r=(@rows - 1); $r>=0; $r--) {
|
||||
print TXF join('', @{$rows[$r]});
|
||||
}
|
||||
close TXF;
|
||||
|
||||
# Clean up
|
||||
#system("rm $FONT.ppm");
|
||||
|
||||
########################################################################
|
||||
########################################################################
|
||||
########################################################################
|
||||
|
||||
sub genPostscript {
|
||||
my $rows = shift;
|
||||
my $rowhgt = 1/$rows;
|
||||
|
||||
my @PS = ();
|
||||
|
||||
# The canonical "point size" number, in texture space
|
||||
$LINEHGT = ($rowhgt - 2*$PADDING/$TEXSIZ) / $maxhgt;
|
||||
|
||||
# Get to where we want. Draw the whole thing in a 1 inch square at
|
||||
# the bottom left of the "page".
|
||||
push @PS, "72 72 scale";
|
||||
|
||||
# Fill the square with black
|
||||
push @PS, "0 setgray";
|
||||
push @PS, "-1 -1 moveto";
|
||||
push @PS, "-1 1 lineto 1 1 lineto 1 -1 lineto";
|
||||
push @PS, "closepath";
|
||||
push @PS, "fill";
|
||||
|
||||
# Draw in white
|
||||
push @PS, "1 setgray";
|
||||
|
||||
# Generate our PUSH @PS, font
|
||||
push @PS, "/$FONT findfont $LINEHGT scalefont setfont";
|
||||
|
||||
my $x = $PADDING/$TEXSIZ;
|
||||
my $y = 1 - $rowhgt + $PADDING/$TEXSIZ;
|
||||
my @chars = sort { $CHARS{$a} <=> $CHARS{$b} } (keys %CHARS);
|
||||
foreach my $c (@chars) {
|
||||
my $m = $metrics{$c};
|
||||
next if !defined $m;
|
||||
|
||||
my $id = sprintf "%2.2x", $CHARS{$c};
|
||||
|
||||
# No space?
|
||||
my $w = $m->[3]*$LINEHGT;
|
||||
if($x + $w + $PADDING/$TEXSIZ > 1) {
|
||||
$x = $PADDING/$TEXSIZ;
|
||||
$y -= $rowhgt;
|
||||
return undef if $y < 0;
|
||||
}
|
||||
|
||||
# Record where in the texture the box ended up
|
||||
$positions{$c} = [$x, $y];
|
||||
|
||||
my $vx = $x + $m->[1]*$LINEHGT;
|
||||
my $vy = $y + $m->[2]*$LINEHGT;
|
||||
|
||||
push @PS, "$vx $vy moveto";
|
||||
push @PS, "<$id> show";
|
||||
|
||||
# Next box...
|
||||
$x += $w + 2*$PADDING/$TEXSIZ;
|
||||
}
|
||||
|
||||
push @PS, "showpage";
|
||||
|
||||
return \@PS;
|
||||
}
|
||||
|
||||
99
tools/src/plibconvert.cxx
Normal file
99
tools/src/plibconvert.cxx
Normal file
@@ -0,0 +1,99 @@
|
||||
// plibconvert.cxx
|
||||
//
|
||||
// Written by Bram Stolk
|
||||
// Published as part of Steve Baker's PLIB under GPL
|
||||
//
|
||||
// Build with :
|
||||
// g++ -o plibconvert plibconvert.cxx -lplibssg -lplibsg -lplibul -lGL
|
||||
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <GL/glx.h>
|
||||
|
||||
#include <plib/ssg.h>
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc!=3)
|
||||
{
|
||||
fprintf(stderr,"Usage: %s source destination\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
assert(strcmp(argv[1], argv[2]));
|
||||
|
||||
#ifdef GLX_VERSION_1_3
|
||||
// Although we will not be doing any rendering, we must create
|
||||
// a valid rendering context before we can call ssgInit()
|
||||
Display *dpy = XOpenDisplay(0);
|
||||
int scn=DefaultScreen(dpy);
|
||||
int cnt;
|
||||
GLXFBConfig *configs = glXGetFBConfigs(dpy, scn, &cnt);
|
||||
if (!configs)
|
||||
{
|
||||
perror("glXGetFBConfigs");
|
||||
exit(1);
|
||||
}
|
||||
fprintf(stderr,"glXGetFBConfigs returned %p (%d matches)\n", configs, cnt);
|
||||
assert(cnt);
|
||||
GLXFBConfig fbc = configs[0];
|
||||
XVisualInfo *vinf = glXGetVisualFromFBConfig(dpy, fbc);
|
||||
if (!vinf)
|
||||
{
|
||||
perror("glXGetVisualFromFBConfig");
|
||||
exit(1);
|
||||
}
|
||||
fprintf
|
||||
(
|
||||
stderr,
|
||||
"visualid=0x%lx (depth=%d,R/G/B=%lx/%lx/%lx)\n",
|
||||
vinf->visualid,
|
||||
vinf->depth,
|
||||
vinf->red_mask,
|
||||
vinf->green_mask,
|
||||
vinf->blue_mask
|
||||
);
|
||||
GLXContext cx = glXCreateNewContext(dpy, fbc, GLX_RGBA_TYPE, 0, GL_TRUE);
|
||||
if (!cx)
|
||||
{
|
||||
perror("glXCreateNewContext");
|
||||
exit(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr,"glX context created\n");
|
||||
}
|
||||
int attrlist[] =
|
||||
{
|
||||
GLX_PBUFFER_WIDTH, 1,
|
||||
GLX_PBUFFER_HEIGHT, 1,
|
||||
0
|
||||
};
|
||||
GLXPbuffer pBuffer = glXCreatePbuffer(dpy, fbc, attrlist);
|
||||
fprintf(stderr,"pBuffer = %lx\n", pBuffer);
|
||||
|
||||
bool ok=glXMakeContextCurrent(dpy, pBuffer, pBuffer, cx);
|
||||
if (!ok)
|
||||
{
|
||||
perror("glXMakeContextCurrent");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Initialize plib
|
||||
fprintf(stderr,"Initializing plib...\n");
|
||||
ssgInit();
|
||||
ssgTexturePath ( "." ) ;
|
||||
ssgModelPath ( "." ) ;
|
||||
|
||||
ssgEntity *e = ssgLoad(argv[1]); // Load
|
||||
e->print(stdout); // Inform
|
||||
ssgSave(argv[2], e); // Store
|
||||
#else
|
||||
fprintf(stderr,"This util uses a pbuffer as context for plib. To build the source, you need glx protocol 1.3 or higher.\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
93
tools/src/txfdump/txfdump.pl
Executable file
93
tools/src/txfdump/txfdump.pl
Executable file
@@ -0,0 +1,93 @@
|
||||
#!/usr/bin/perl -w
|
||||
use strict;
|
||||
|
||||
## txfdump.pl - A .txf font file parser and image extractor
|
||||
##
|
||||
## Usage: txfdump.pl blahblah.txf
|
||||
##
|
||||
## Human readable font metric information will be printed to stdout,
|
||||
## and a blahblah.pgm file will be written containing the texture
|
||||
## image from the file. Note that the resulting image will be
|
||||
## vertically reflected, owing to the difference between cartesian x/y
|
||||
## coordinates used by .txf and the screen raster convention of the
|
||||
## .pgm format (well, and the author's laziness). Load it up in your
|
||||
## favorite viewer and flip it if you care.
|
||||
##
|
||||
## Copyright (C) 2002 Andrew James Ross
|
||||
##
|
||||
## This program is free software; you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License version 2 as
|
||||
## published by the Free Software Foundation.
|
||||
|
||||
my $file = shift or die;
|
||||
open TXF, $file or die;
|
||||
|
||||
# Start out assuming intel byte order
|
||||
# These get used in the getshort/getint functions below
|
||||
my $shortType = "v";
|
||||
my $longType = "V";
|
||||
|
||||
sub getsbyte { my $v=getbyte(); if($v>127) { $v-=256; } return $v; }
|
||||
sub getbyte { my $val; read TXF, $val, 1 or die; return ord $val; }
|
||||
sub getshort { my $val; read TXF, $val, 2 or die; return unpack $shortType, $val; }
|
||||
sub getint { my $val; read TXF, $val, 4 or die; return unpack $longType, $val; }
|
||||
|
||||
# Check the magic number; it is endian-independant
|
||||
my $magic = sprintf "0x%8.8x", getint();
|
||||
die "Bad magic number ($magic)" if $magic ne "0x667874ff";
|
||||
|
||||
# Read the next four bytes to determine endianness
|
||||
my $endian = sprintf "0x%8.8x", getint();
|
||||
if($endian eq "0x12345678") {
|
||||
} elsif($endian eq "0x78563412") {
|
||||
# Network byte order
|
||||
$shortType = "n";
|
||||
$longType = "N";
|
||||
} else {
|
||||
die "Bad endianness tag ($endian)";
|
||||
}
|
||||
|
||||
# Read the rest of the header
|
||||
my $format = getint();
|
||||
my $texwid = getint();
|
||||
my $texhgt = getint();
|
||||
my $linehgt = getint();
|
||||
my $unk = getint();
|
||||
my $nglyph = getint();
|
||||
|
||||
printf "Magic $magic Endian $endian Format 0x%8.8x\n", $format;
|
||||
print "Texture: ${texwid}x$texhgt Line: $linehgt Glyphs: $nglyph Unk: $unk\n";
|
||||
|
||||
# Read each glyph's metadata
|
||||
for(my $i=0; $i<$nglyph; $i++) {
|
||||
print "Glyph $i\n";
|
||||
my $c = getshort();
|
||||
print " char: $c ('", chr($c), "')\n";
|
||||
print " width: ", getbyte(), "\n";
|
||||
print " height: ", getbyte(), "\n";
|
||||
print " xoff: ", getsbyte(), "\n";
|
||||
print " yoff: ", getsbyte(), "\n";
|
||||
print " step: ", getbyte(), "\n";
|
||||
print " unk: ", getbyte(), "\n";
|
||||
print " X: ", getshort(), "\n";
|
||||
print " Y: ", getshort(), "\n";
|
||||
}
|
||||
|
||||
# The rest of the file is an image. Write it out as a .pgm file with
|
||||
# the same name as the font file.
|
||||
|
||||
$file =~ s/\.txf$/.pgm/;
|
||||
open PGM, ">$file" or die;
|
||||
print PGM "P2\n$texwid $texhgt\n255\n";
|
||||
|
||||
if($format == 0) {
|
||||
for(my $i=0; $i<($texwid*$texhgt); $i++) { print PGM getbyte(), " "; }
|
||||
} else {
|
||||
for(my $i=0; $i<($texwid*$texhgt/8); $i++) {
|
||||
my $byte = getbyte();
|
||||
for(my $j=0; $j<8; $j++) {
|
||||
print PGM ($byte & (1<<$j)) ? "255 " : "0 ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user