mirror of
https://github.com/kevinbentley/Descent3.git
synced 2025-01-23 03:58:59 +00:00
a4ab78192c
Join the license header with historical comments using a separator so IDEs can correctly parse the initial header. Also use .gitattributes to ensure all files are LF.
522 lines
12 KiB
C++
522 lines
12 KiB
C++
/*
|
|
* Descent 3
|
|
* Copyright (C) 2024 Parallax Software
|
|
*
|
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
|
|
--- HISTORICAL COMMENTS FOLLOW ---
|
|
|
|
* $Source: /home/kevin/cvsstuff/descent3/descent3/Main/FontEditor/FontKern.cpp,v $
|
|
* $Revision: 1.1.1.1 $
|
|
* $Author: kevinb $
|
|
* $Date: 2003-08-26 03:57:45 $
|
|
*
|
|
* Kerning
|
|
*
|
|
* $Log: not supported by cvs2svn $
|
|
*
|
|
* 4 11/16/99 3:18p Samir
|
|
* updated fonteditor to include tracking.
|
|
*
|
|
* 3 5/19/99 8:48p Samir
|
|
* added kerning dump utilitiy.
|
|
*
|
|
* 2 4/17/99 4:05p Samir
|
|
* complete font editor.
|
|
*
|
|
*/
|
|
|
|
#include "FontEditor.h"
|
|
#include "pserror.h"
|
|
#include "renderer.h"
|
|
#include "ddio.h"
|
|
#include "grtext.h"
|
|
#include "bitmap.h"
|
|
#include "mem.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
|
|
chunked_bitmap Editor_bkg;
|
|
tFontTemplate Font_template;
|
|
|
|
char *SampleText = "This is some sample text that is here to\n" \
|
|
"Show you how the antialiasing will\n" \
|
|
"look over different color backgrounds\n" \
|
|
"KERN PAIRS: VaWaVeWeVAV-LyT.T,TyTvTcYe\n";
|
|
|
|
|
|
// this function determines if a kerning pair exists in the current font template
|
|
// if there is no kerning structure, add it. if no kerning in font, add it to the template
|
|
#define KERNINFO_PAIR_SIZE 3
|
|
|
|
int fonttool_get_kerning( int c1, int c2, int *pairnum=NULL);
|
|
|
|
int fonttool_get_kerning( int c1, int c2, int *pairnum)
|
|
{
|
|
int i;
|
|
ubyte *kern_data;
|
|
|
|
|
|
kern_data= Font_template.kern_data;
|
|
if (kern_data) {
|
|
i=0;
|
|
while (kern_data[i] != 255)
|
|
{
|
|
if (kern_data[i] == (ubyte)c1 && kern_data[i+1] == (ubyte)c2) {
|
|
if (pairnum) *pairnum = i/3;
|
|
return (int)((sbyte)kern_data[i+2]);
|
|
}
|
|
i+=KERNINFO_PAIR_SIZE;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void fonttool_set_kerning( int c1, int c2, int dist )
|
|
{
|
|
int i,j;
|
|
ubyte *kern_data;
|
|
|
|
if (c1 == 255 || c2 == 255) {
|
|
mprintf((0, "seting illegal kerning of 255!\n"));
|
|
return;
|
|
}
|
|
|
|
kern_data= Font_template.kern_data;
|
|
|
|
if (!kern_data) {
|
|
// create a one entry kern table.
|
|
kern_data = (ubyte *)mem_malloc(KERNINFO_PAIR_SIZE*2);
|
|
kern_data[0] = (ubyte)c1;
|
|
kern_data[1] = (ubyte)c2;
|
|
kern_data[2] = (sbyte)dist;
|
|
kern_data[3] = 255;
|
|
kern_data[4] = 255;
|
|
kern_data[5] = 0;
|
|
Font_template.kern_data = kern_data;
|
|
mprintf((0, "adding first kerning pair %d,%d\n", c1,c2));
|
|
return;
|
|
}
|
|
|
|
// check for match in current list.
|
|
i=0;
|
|
while (kern_data[i] != 255)
|
|
{
|
|
if (kern_data[i] == (ubyte)c1 && kern_data[i+1] == (ubyte)c2) {
|
|
kern_data[i+2] = (sbyte)dist;
|
|
if (dist == 0) {
|
|
// remove this kerning pair.
|
|
j = i;
|
|
do
|
|
{
|
|
kern_data[j] = kern_data[j+3];
|
|
kern_data[j+1] = kern_data[j+4];
|
|
kern_data[j+2] = kern_data[j+5];
|
|
j+= KERNINFO_PAIR_SIZE;
|
|
}
|
|
while (kern_data[j] != 255);
|
|
if (i == 0) {
|
|
// last pair, deallocate kern_data and end.
|
|
mprintf((0, "removing last kerning pair\n"));
|
|
mem_free(kern_data);
|
|
kern_data = NULL;
|
|
}
|
|
else {
|
|
mprintf((0, "removing kerning pair %d,%d\n", c1,c2));
|
|
}
|
|
}
|
|
Font_template.kern_data = kern_data;
|
|
return;
|
|
}
|
|
i+=KERNINFO_PAIR_SIZE;
|
|
}
|
|
|
|
// new entry.
|
|
ubyte *new_kern_data;
|
|
int n_pairs = i/KERNINFO_PAIR_SIZE;
|
|
|
|
new_kern_data = (ubyte *)mem_malloc((n_pairs+2)*sizeof(ubyte)*KERNINFO_PAIR_SIZE);
|
|
for (i = 0; i < n_pairs; i++)
|
|
{
|
|
new_kern_data[i*KERNINFO_PAIR_SIZE] = kern_data[i*3];
|
|
new_kern_data[i*KERNINFO_PAIR_SIZE+1] = kern_data[i*3+1];
|
|
new_kern_data[i*KERNINFO_PAIR_SIZE+2] = kern_data[i*3+2];
|
|
}
|
|
new_kern_data[i*KERNINFO_PAIR_SIZE] = (ubyte)c1;
|
|
new_kern_data[i*KERNINFO_PAIR_SIZE+1] = (ubyte)c2;
|
|
new_kern_data[i*KERNINFO_PAIR_SIZE+2] = (sbyte)dist;
|
|
i++;
|
|
new_kern_data[i*KERNINFO_PAIR_SIZE] = 255;
|
|
new_kern_data[i*KERNINFO_PAIR_SIZE+1] = 255;
|
|
new_kern_data[i*KERNINFO_PAIR_SIZE+2] = 0;
|
|
|
|
mem_free(kern_data);
|
|
|
|
Font_template.kern_data = new_kern_data;
|
|
|
|
mprintf((0, "adding first kerning pair %d,%d (total=%d)\n", c1,c2, n_pairs+1));
|
|
}
|
|
|
|
|
|
void fonttool_remove_kerning()
|
|
{
|
|
if (Font_template.kern_data) {
|
|
mem_free(Font_template.kern_data);
|
|
Font_template.kern_data = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
void FontKern(const char *fnt_file_name)
|
|
{
|
|
int bm_handle;
|
|
int font_handle;
|
|
int c1 = 'b', c2 = 'u', d;
|
|
int last_good_pair, current_pair;
|
|
int first_item = 0;
|
|
int current_item = 0;
|
|
int num_items_displayed = 1;
|
|
bool done = false;
|
|
short text_alpha=255;
|
|
int red_comp , green_comp, blue_comp;
|
|
ddgr_color text_color;
|
|
|
|
red_comp = green_comp = blue_comp = 255;
|
|
|
|
bm_handle = bm_AllocLoadFileBitmap("FontTool.ogf",0);
|
|
if (bm_handle <= BAD_BITMAP_HANDLE) {
|
|
Error("Error loading FontEditor art.");
|
|
}
|
|
if (!bm_CreateChunkedBitmap(bm_handle, &Editor_bkg)) {
|
|
Error("Error chunking FontEditor art.");
|
|
}
|
|
bm_FreeBitmap(bm_handle);
|
|
|
|
// load font into memory.
|
|
font_handle = grfont_Load((char *)fnt_file_name);
|
|
if (font_handle < 0) {
|
|
Error("Error loading font %s", fnt_file_name);
|
|
}
|
|
if (!grfont_LoadTemplate((char *)fnt_file_name, &Font_template)) {
|
|
Error("Error loading font template %s", fnt_file_name);
|
|
}
|
|
|
|
if (Font_template.ffi2 == false) {
|
|
Font_template.ffi2 = true;
|
|
Font_template.ch_tracking = 0;
|
|
}
|
|
|
|
if (Font_template.kern_data) {
|
|
current_pair = 0;
|
|
}
|
|
else {
|
|
current_pair = -1;
|
|
}
|
|
|
|
last_good_pair = current_pair;
|
|
|
|
while(!done)
|
|
{
|
|
int key;
|
|
|
|
FontDoIO();
|
|
|
|
key = ddio_KeyInKey();
|
|
switch (key)
|
|
{
|
|
case KEY_ESC:
|
|
done = true;
|
|
break;
|
|
|
|
case KEY_F5:
|
|
grfont_Free(font_handle);
|
|
grfont_FreeTemplate(&Font_template);
|
|
font_handle = grfont_Load((char *)fnt_file_name);
|
|
if (font_handle == -1) {
|
|
Error("Font failed reload test!");
|
|
}
|
|
grfont_LoadTemplate((char *)fnt_file_name, &Font_template);
|
|
break;
|
|
|
|
case KEY_MINUS:
|
|
if (Font_template.ch_tracking > -80) {
|
|
Font_template.ch_tracking--;
|
|
grfont_SetTracking(font_handle, Font_template.ch_tracking);
|
|
}
|
|
break;
|
|
|
|
case KEY_EQUAL:
|
|
if (Font_template.ch_tracking < 80) {
|
|
Font_template.ch_tracking++;
|
|
grfont_SetTracking(font_handle, Font_template.ch_tracking);
|
|
}
|
|
break;
|
|
|
|
case KEY_F10:
|
|
grfont_Free(font_handle);
|
|
if (!grfont_SetTemplate(fnt_file_name, &Font_template)) {
|
|
Error("Failed to save font correctly!");
|
|
}
|
|
grfont_FreeTemplate(&Font_template);
|
|
font_handle = grfont_Load((char *)fnt_file_name);
|
|
if (font_handle == -1) {
|
|
Error("Font failed reload test on save!");
|
|
}
|
|
grfont_LoadTemplate((char *)fnt_file_name, &Font_template);
|
|
mprintf((0, "font saved and reloaded correctly?\n"));
|
|
done = true;
|
|
break;
|
|
|
|
case KEY_F6:
|
|
fonttool_remove_kerning();
|
|
break;
|
|
|
|
case KEY_COMMA:
|
|
text_alpha -= 16;
|
|
if (text_alpha < 0) text_alpha = 0;
|
|
break;
|
|
|
|
case KEY_PERIOD:
|
|
text_alpha += 16;
|
|
if (text_alpha > 255) text_alpha = 255;
|
|
break;
|
|
|
|
case KEY_PAD7:
|
|
c1++;
|
|
if (c1 > Font_template.max_ascii) c1 = Font_template.min_ascii;
|
|
break;
|
|
|
|
case KEY_PAD9:
|
|
c2++;
|
|
if (c2 > Font_template.max_ascii) c2 = Font_template.min_ascii;
|
|
break;
|
|
|
|
case KEY_PAD1:
|
|
c1--;
|
|
if (c1 < Font_template.min_ascii) c1 = Font_template.max_ascii;
|
|
break;
|
|
|
|
case KEY_PAD3:
|
|
c2--;
|
|
if (c2 < Font_template.min_ascii) c2 = Font_template.max_ascii;
|
|
break;
|
|
|
|
case KEY_PAD4:
|
|
d = fonttool_get_kerning(c1,c2);
|
|
fonttool_set_kerning(c1, c2, d-1);
|
|
grfont_SetKerning(font_handle, Font_template.kern_data);
|
|
break;
|
|
|
|
case KEY_PAD5:
|
|
fonttool_set_kerning(c1,c2,0);
|
|
break;
|
|
|
|
case KEY_PAD6:
|
|
d = fonttool_get_kerning(c1,c2);
|
|
fonttool_set_kerning(c1,c2,d+1);
|
|
grfont_SetKerning(font_handle, Font_template.kern_data);
|
|
break;
|
|
|
|
case KEY_PAD2:
|
|
if ( current_pair < 0 ) {
|
|
current_pair = last_good_pair;
|
|
}
|
|
|
|
if (current_pair >= 0) {
|
|
ubyte *kern_data = &Font_template.kern_data[current_pair*3];
|
|
if (kern_data[3] != 255) {
|
|
current_pair++;
|
|
kern_data = &Font_template.kern_data[current_pair*3];
|
|
}
|
|
c1 = kern_data[0];
|
|
c2 = kern_data[1];
|
|
}
|
|
break;
|
|
|
|
case KEY_PAD8:
|
|
if ( current_pair < 0 ) {
|
|
current_pair = last_good_pair;
|
|
}
|
|
|
|
if (current_pair >= 0) {
|
|
ubyte *kern_data = &Font_template.kern_data[current_pair*3];
|
|
if (kern_data != Font_template.kern_data) {
|
|
// gosh, comparing pointers like this may not be the best method...this is shitty code...
|
|
current_pair--;
|
|
kern_data = &Font_template.kern_data[current_pair*3];
|
|
}
|
|
c1 = kern_data[0];
|
|
c2 = kern_data[1];
|
|
}
|
|
break;
|
|
|
|
case KEY_R:
|
|
red_comp = red_comp ? 0 : 255;
|
|
break;
|
|
case KEY_G:
|
|
green_comp = green_comp ? 0 : 255;
|
|
break;
|
|
case KEY_B:
|
|
blue_comp = blue_comp ? 0 : 255;
|
|
break;
|
|
}
|
|
|
|
// draw.
|
|
text_color = GR_RGB(red_comp, green_comp, blue_comp);
|
|
|
|
rend_StartFrame(0,0,FIXED_SCREEN_WIDTH,FIXED_SCREEN_HEIGHT,0);
|
|
grtext_SetParameters(0,0,FIXED_SCREEN_WIDTH,FIXED_SCREEN_HEIGHT);
|
|
grtext_SetFont(font_handle);
|
|
grtext_SetColor(text_color);
|
|
grtext_SetAlpha((ubyte)text_alpha);
|
|
|
|
rend_ClearScreen(GR_BLACK);
|
|
rend_DrawChunkedBitmap(&Editor_bkg, 0, 0, 255);
|
|
|
|
grtext_Printf(240,210,"%c (%d)", c1, c1);
|
|
grtext_Printf(340,210,"%c (%d)", c2, c2);
|
|
|
|
grtext_CenteredPrintf(0, 240, "Ham%c%crger", c1, c2);
|
|
|
|
grtext_CenteredPrintf(0, 270, "HAM%c%cRGER", c1, c2);
|
|
|
|
grtext_CenteredPrintf(0, 300, "Offset: %d pixels", fonttool_get_kerning(c1, c2));
|
|
grtext_CenteredPrintf(0, 320, "Tracking: %d pixels", (int)Font_template.ch_tracking);
|
|
{
|
|
int th;
|
|
th = grtext_GetTextHeight(SampleText);
|
|
|
|
grtext_Printf(10,350,SampleText);
|
|
grtext_Printf(10,350+th+10, SampleText);
|
|
}
|
|
|
|
// display kerned pairs.
|
|
int x = 5, y = 200, i, n, widest=0;
|
|
int n_pairs=0, stop;
|
|
int tmpp=-1;
|
|
char kerntext[16];
|
|
|
|
if (Font_template.kern_data) {
|
|
i=0;
|
|
while (Font_template.kern_data[i] != 255)
|
|
{
|
|
n_pairs++;
|
|
i+=KERNINFO_PAIR_SIZE;
|
|
}
|
|
}
|
|
|
|
// update current pair values
|
|
if ( current_pair >= n_pairs ) {
|
|
current_pair = -1;
|
|
}
|
|
|
|
fonttool_get_kerning(c1, c2, &tmpp );
|
|
|
|
if ( tmpp != -1 ) {
|
|
current_pair = tmpp;
|
|
} else {
|
|
if ( current_pair > -1 )
|
|
last_good_pair = current_pair;
|
|
current_pair = -1;
|
|
}
|
|
if (current_pair > -1) { current_item = current_pair; }
|
|
if (current_item < 0) { current_item = 0; }
|
|
if (current_item >= n_pairs) { current_item = n_pairs-1; }
|
|
if (current_item < first_item) { first_item = current_item; }
|
|
if (current_item >= (first_item+num_items_displayed)) { first_item = current_item-num_items_displayed+1; }
|
|
if (n_pairs <= num_items_displayed) { first_item = 0; }
|
|
stop = first_item+num_items_displayed;
|
|
if (stop>n_pairs) stop = n_pairs;
|
|
|
|
for (i=first_item,n=0; i<stop; i++)
|
|
{
|
|
int tw,th;
|
|
ASSERT(Font_template.kern_data);
|
|
ubyte *kern_data = &Font_template.kern_data[i*3];
|
|
if (i==current_pair) {
|
|
rend_SetFlatColor(GR_RGB(255,0,0));
|
|
rend_DrawLine(x,y,x+6,y+5);
|
|
rend_DrawLine(x+6,y+5,x,y+8);
|
|
rend_DrawLine(x,y+8,x,y);
|
|
}
|
|
sprintf(kerntext, "%c%c", kern_data[0], kern_data[1]);
|
|
grtext_Puts(x+8,y,kerntext);
|
|
n++;
|
|
tw = grtext_GetTextLineWidth(kerntext) + 8;
|
|
th = grtext_GetTextHeight(kerntext);
|
|
if (tw > widest) {widest = tw; }
|
|
y += th;
|
|
if (y > 330) {
|
|
y = 200;
|
|
x += widest+5;
|
|
if (x > 150) {
|
|
num_items_displayed = n;
|
|
break;
|
|
}
|
|
widest = 0;
|
|
}
|
|
}
|
|
if (i == stop) { num_items_displayed++; }
|
|
if (num_items_displayed < 1) {num_items_displayed = 1;}
|
|
if (num_items_displayed > n_pairs) { num_items_displayed = n_pairs; }
|
|
|
|
|
|
grtext_Flush();
|
|
rend_EndFrame();
|
|
rend_Flip();
|
|
}
|
|
|
|
grfont_FreeTemplate(&Font_template);
|
|
grfont_Free(font_handle);
|
|
bm_DestroyChunkedBitmap(&Editor_bkg);
|
|
}
|
|
|
|
|
|
|
|
void FontKernDump(const char *fnt_file_name)
|
|
{
|
|
if (!grfont_LoadTemplate((char *)fnt_file_name, &Font_template)) {
|
|
Error("Error loading font template %s", fnt_file_name);
|
|
}
|
|
|
|
if (Font_template.kern_data) {
|
|
FILE *fp;
|
|
char filename[_MAX_PATH];
|
|
|
|
sprintf(filename, "%s.kern", fnt_file_name);
|
|
fp = fopen(filename, "wt");
|
|
if (fp) {
|
|
ubyte *kern_data = Font_template.kern_data;
|
|
while (kern_data[0] != 255)
|
|
{
|
|
ubyte c1 = kern_data[0];
|
|
ubyte c2 = kern_data[1];
|
|
sbyte delta = (sbyte)kern_data[2];
|
|
|
|
fprintf(fp, "%c %c => %d spacing\n", c1,c2,(int)delta);
|
|
kern_data += 3;
|
|
}
|
|
fclose(fp);
|
|
}
|
|
}
|
|
|
|
grfont_FreeTemplate(&Font_template);
|
|
}
|