mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 10:54:24 -04:00
pnmtext is moved to panda
This commit is contained in:
parent
abb0c97f85
commit
22266d04a2
@ -6,7 +6,7 @@
|
||||
#define TARGET indexify
|
||||
#define OTHER_LIBS \
|
||||
progbase pandatoolbase \
|
||||
pnmimage:c pnmimagetypes:c panda:m pandaexpress:m \
|
||||
pnmtext:c pnmimage:c pnmimagetypes:c panda:m pandaexpress:m \
|
||||
dtool:m dtoolconfig:m \
|
||||
pystub
|
||||
|
||||
@ -17,9 +17,7 @@
|
||||
indexParameters.cxx indexParameters.h \
|
||||
indexify.cxx indexify.h \
|
||||
photo.cxx photo.h \
|
||||
rollDirectory.cxx rollDirectory.h \
|
||||
pnmTextGlyph.cxx pnmTextGlyph.h \
|
||||
pnmTextMaker.cxx pnmTextMaker.h
|
||||
rollDirectory.cxx rollDirectory.h
|
||||
|
||||
#end bin_target
|
||||
|
||||
@ -29,14 +27,12 @@
|
||||
#define TARGET font-samples
|
||||
#define OTHER_LIBS \
|
||||
progbase pandatoolbase \
|
||||
pnmimage:c pnmimagetypes:c panda:m pandaexpress:m \
|
||||
pnmtext:c pnmimage:c pnmimagetypes:c panda:m pandaexpress:m \
|
||||
dtool:m dtoolconfig:m \
|
||||
pystub
|
||||
|
||||
#define SOURCES \
|
||||
default_font.cxx default_font.h \
|
||||
fontSamples.cxx fontSamples.h \
|
||||
pnmTextGlyph.cxx pnmTextGlyph.h \
|
||||
pnmTextMaker.cxx pnmTextMaker.h
|
||||
fontSamples.cxx fontSamples.h
|
||||
|
||||
#end bin_target
|
||||
|
@ -181,7 +181,8 @@ post_command_line() {
|
||||
}
|
||||
|
||||
if (_name_text_maker != (PNMTextMaker *)NULL) {
|
||||
_name_text_maker->set_pixel_size(_name_height, _font_aa_factor);
|
||||
_name_text_maker->set_scale_factor(_font_aa_factor);
|
||||
_name_text_maker->set_pixel_size(_name_height);
|
||||
} else {
|
||||
_name_height = 0;
|
||||
}
|
||||
@ -229,7 +230,8 @@ run() {
|
||||
if (!text_maker->is_valid()) {
|
||||
all_ok = false;
|
||||
} else {
|
||||
text_maker->set_pixel_size(_sample_height, _font_aa_factor);
|
||||
text_maker->set_scale_factor(_font_aa_factor);
|
||||
text_maker->set_pixel_size(_sample_height);
|
||||
text_maker->generate_into(_sample_text, output_image,
|
||||
16, y + _sample_height);
|
||||
if (_name_text_maker != (PNMTextMaker *)NULL) {
|
||||
@ -243,10 +245,6 @@ run() {
|
||||
delete text_maker;
|
||||
}
|
||||
|
||||
if (!all_ok) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
snprintf(output_filename, output_filename_size,
|
||||
_output_filename.c_str(), output_index);
|
||||
nout << "Writing " << output_filename << "\n";
|
||||
@ -254,6 +252,11 @@ run() {
|
||||
nout << "Unable to write to " << output_filename << "\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!all_ok) {
|
||||
nout << "Problem loading fonts.\n";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -386,7 +386,8 @@ post_command_line() {
|
||||
}
|
||||
|
||||
if (_text_maker != (PNMTextMaker *)NULL) {
|
||||
_text_maker->set_pixel_size(caption_font_size, _font_aa_factor);
|
||||
_text_maker->set_scale_factor(_font_aa_factor);
|
||||
_text_maker->set_pixel_size(caption_font_size);
|
||||
_text_maker->set_align(PNMTextMaker::A_center);
|
||||
}
|
||||
}
|
||||
|
@ -1,145 +0,0 @@
|
||||
// Filename: pnmTextGlyph.cxx
|
||||
// Created by: drose (03Apr02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://www.panda3d.org/license.txt .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d@yahoogroups.com .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "pnmTextGlyph.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PNMTextGlyph::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PNMTextGlyph::
|
||||
PNMTextGlyph(double advance) :
|
||||
_advance(advance)
|
||||
{
|
||||
_left = 0;
|
||||
_top = 0;
|
||||
_int_advance = (int)floor(_advance + 0.5);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PNMTextGlyph::Destructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PNMTextGlyph::
|
||||
~PNMTextGlyph() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PNMTextGlyph::rescale
|
||||
// Access: Public
|
||||
// Description: After the image has been rendered large by FreeType,
|
||||
// scales it small again for placing.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PNMTextGlyph::
|
||||
rescale(double scale_factor) {
|
||||
if (scale_factor == 1.0) {
|
||||
return;
|
||||
}
|
||||
nassertv(scale_factor != 0.0);
|
||||
_advance /= scale_factor;
|
||||
_int_advance = (int)floor(_advance + 0.5);
|
||||
|
||||
if (_image.is_valid()) {
|
||||
int orig_x_size = _image.get_x_size();
|
||||
int orig_y_size = _image.get_y_size();
|
||||
int orig_left = _left;
|
||||
int orig_top = _top;
|
||||
|
||||
// Pad the image by a few pixels all around to allow for
|
||||
// antialiasing at the edges.
|
||||
int extra_pad = (int)ceil(scale_factor);
|
||||
orig_x_size += 2*extra_pad;
|
||||
orig_y_size += 2*extra_pad;
|
||||
orig_left -= extra_pad;
|
||||
orig_top += extra_pad;
|
||||
|
||||
// Now compute the reduced size.
|
||||
int new_x_size = (int)ceil(orig_x_size / scale_factor);
|
||||
int new_y_size = (int)ceil(orig_y_size / scale_factor);
|
||||
int new_left = (int)floor(orig_left / scale_factor);
|
||||
int new_top = (int)ceil(orig_top / scale_factor);
|
||||
|
||||
// And scale those back up so we can determine the amount of
|
||||
// additional padding we need to make the pixels remain in the
|
||||
// right place after the integer reduction.
|
||||
int old_x_size = (int)(new_x_size * scale_factor + 0.5);
|
||||
int old_y_size = (int)(new_y_size * scale_factor + 0.5);
|
||||
int old_left = (int)(new_left * scale_factor + 0.5);
|
||||
int old_top = (int)(new_top * scale_factor + 0.5);
|
||||
|
||||
int pad_left = orig_left - old_left;
|
||||
int pad_top = old_top - orig_top;
|
||||
|
||||
// These shouldn't go negative.
|
||||
nassertv(extra_pad + pad_left >= 0 && extra_pad + pad_top >= 0);
|
||||
|
||||
PNMImage enlarged(old_x_size, old_y_size, 1);
|
||||
enlarged.fill(1, 1, 1);
|
||||
enlarged.copy_sub_image(_image, pad_left + extra_pad, pad_top + extra_pad);
|
||||
|
||||
_image.clear(new_x_size, new_y_size, 1);
|
||||
_image.quick_filter_from(enlarged);
|
||||
|
||||
_left = new_left;
|
||||
_top = new_top;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PNMTextGlyph::get_advance
|
||||
// Access: Public
|
||||
// Description: Returns the number of pixels by which the pen should
|
||||
// be advanced after rendering this glyph.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int PNMTextGlyph::
|
||||
get_advance() const {
|
||||
return _int_advance;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PNMTextGlyph::place
|
||||
// Access: Public
|
||||
// Description: Copies the glyph to the indicated destination image
|
||||
// at the indicated origin.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PNMTextGlyph::
|
||||
place(PNMImage &dest_image, int xp, int yp) {
|
||||
if (!_image.is_valid()) {
|
||||
// If we have no image, do nothing.
|
||||
return;
|
||||
}
|
||||
int left = xp + _left;
|
||||
int top = yp - _top;
|
||||
int right = left + _image.get_x_size();
|
||||
int bottom = top + _image.get_y_size();
|
||||
|
||||
// Clip the glyph to the destination image.
|
||||
int cleft = max(left, 0);
|
||||
int ctop = max(top, 0);
|
||||
int cright = min(right, dest_image.get_x_size());
|
||||
int cbottom = min(bottom, dest_image.get_y_size());
|
||||
|
||||
for (int y = ctop; y < cbottom; y++) {
|
||||
for (int x = cleft; x < cright; x++) {
|
||||
double gval = _image.get_gray(x - left, y - top);
|
||||
dest_image.set_xel(x, y, dest_image.get_xel(x, y) * gval);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
// Filename: pnmTextGlyph.h
|
||||
// Created by: drose (03Apr02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://www.panda3d.org/license.txt .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d@yahoogroups.com .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef PNMTEXTGLYPH_H
|
||||
#define PNMTEXTGLYPH_H
|
||||
|
||||
#include "pandatoolbase.h"
|
||||
|
||||
#include "pnmImage.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : PNMTextGlyph
|
||||
// Description : A single glyph in a PNMTextMaker.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class PNMTextGlyph {
|
||||
public:
|
||||
PNMTextGlyph(double advance);
|
||||
~PNMTextGlyph();
|
||||
|
||||
void rescale(double scale_factor);
|
||||
int get_advance() const;
|
||||
|
||||
void place(PNMImage &dest_image, int xp, int yp);
|
||||
|
||||
private:
|
||||
PNMImage _image;
|
||||
int _top;
|
||||
int _left;
|
||||
double _advance;
|
||||
int _int_advance;
|
||||
|
||||
friend class PNMTextMaker;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,444 +0,0 @@
|
||||
// Filename: textMaker.cxx
|
||||
// Created by: drose (03Apr02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://www.panda3d.org/license.txt .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d@yahoogroups.com .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "pnmTextMaker.h"
|
||||
#include "pnmTextGlyph.h"
|
||||
#include "filename.h"
|
||||
#include "pnmImage.h"
|
||||
|
||||
FT_Library PNMTextMaker::_ft_library;
|
||||
bool PNMTextMaker::_ft_initialized = false;
|
||||
bool PNMTextMaker::_ft_ok = false;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PNMTextMaker::Constructor
|
||||
// Access: Public
|
||||
// Description: The constructor expects the name of some font file
|
||||
// that FreeType can read, along with face_index,
|
||||
// indicating which font within the file to load
|
||||
// (usually 0).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PNMTextMaker::
|
||||
PNMTextMaker(const Filename &font_filename, int face_index) {
|
||||
_is_valid = false;
|
||||
|
||||
if (!_ft_initialized) {
|
||||
initialize_ft_library();
|
||||
}
|
||||
if (!_ft_ok) {
|
||||
nout
|
||||
<< "Unable to read font " << font_filename
|
||||
<< ": FreeType library not initialized properly.\n";
|
||||
return;
|
||||
}
|
||||
|
||||
Filename path(font_filename);
|
||||
if (!path.exists()) {
|
||||
nout << "Unable to find font file " << font_filename << "\n";
|
||||
} else {
|
||||
string os_specific = path.to_os_specific();
|
||||
|
||||
int error = FT_New_Face(_ft_library,
|
||||
os_specific.c_str(),
|
||||
face_index,
|
||||
&_face);
|
||||
if (error == FT_Err_Unknown_File_Format) {
|
||||
nout << "Unable to read font " << font_filename << ": unknown file format.\n";
|
||||
} else if (error) {
|
||||
nout << "Unable to read font " << font_filename << ": invalid.\n";
|
||||
|
||||
} else {
|
||||
string name = _face->family_name;
|
||||
if (_face->style_name != NULL) {
|
||||
name += " ";
|
||||
name += _face->style_name;
|
||||
}
|
||||
set_name(name);
|
||||
|
||||
// Maybe we don't care about enforcing this. It doesn't work
|
||||
// with older versions of FreeType anyway.
|
||||
/*
|
||||
error = FT_Select_Charmap(_face, ft_encoding_unicode);
|
||||
if (error) {
|
||||
error = FT_Select_Charmap(_face, ft_encoding_latin_2);
|
||||
}
|
||||
if (error) {
|
||||
nout << "Unable to select ISO encoding for " << get_name() << ".\n";
|
||||
FT_Done_Face(_face);
|
||||
|
||||
} else */
|
||||
{
|
||||
nout << "Loaded font " << get_name() << "\n";
|
||||
_is_valid = true;
|
||||
_scale_factor = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_align = A_left;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PNMTextMaker::Constructor
|
||||
// Access: Public
|
||||
// Description: This constructor works as above, but it takes the
|
||||
// font data from an in-memory buffer instead of from a
|
||||
// named file.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PNMTextMaker::
|
||||
PNMTextMaker(const char *font_data, int font_data_size, int face_index) {
|
||||
_is_valid = false;
|
||||
|
||||
if (!_ft_initialized) {
|
||||
initialize_ft_library();
|
||||
}
|
||||
if (!_ft_ok) {
|
||||
nout
|
||||
<< "Unable to read internal font: FreeType library not initialized properly.\n";
|
||||
return;
|
||||
}
|
||||
|
||||
int error = FT_New_Memory_Face(_ft_library,
|
||||
(FT_Byte *)font_data, font_data_size,
|
||||
face_index,
|
||||
&_face);
|
||||
if (error == FT_Err_Unknown_File_Format) {
|
||||
nout << "Unable to read internal font: unknown file format.\n";
|
||||
} else if (error) {
|
||||
nout << "Unable to read internal font: invalid.\n";
|
||||
|
||||
} else {
|
||||
string name = _face->family_name;
|
||||
if (_face->style_name != NULL) {
|
||||
name += " ";
|
||||
name += _face->style_name;
|
||||
}
|
||||
set_name(name);
|
||||
|
||||
error = FT_Select_Charmap(_face, ft_encoding_unicode);
|
||||
if (error) {
|
||||
error = FT_Select_Charmap(_face, ft_encoding_latin_2);
|
||||
}
|
||||
if (error) {
|
||||
nout << "Unable to select ISO encoding for " << get_name() << ".\n";
|
||||
FT_Done_Face(_face);
|
||||
|
||||
} else {
|
||||
_is_valid = true;
|
||||
_scale_factor = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
_align = A_left;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PNMTextMaker::Destructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PNMTextMaker::
|
||||
~PNMTextMaker() {
|
||||
empty_cache();
|
||||
|
||||
if (_is_valid) {
|
||||
FT_Done_Face(_face);
|
||||
_is_valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PNMTextMaker::is_valid
|
||||
// Access: Public
|
||||
// Description: Returns true if the PNMTextMaker is valid and ready to
|
||||
// generate text, false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool PNMTextMaker::
|
||||
is_valid() const {
|
||||
return _is_valid;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PNMTextMaker::set_pixel_size
|
||||
// Access: Public
|
||||
// Description: Specifies the pixel size of the font to use to
|
||||
// generate future text. If the scale_factor is
|
||||
// specified, it is the factor by which to scale up the
|
||||
// font glyphs internally before reducing them to the
|
||||
// final output pixel_size; this works around problems
|
||||
// FreeType has with antialiasing small pixel sizes.
|
||||
//
|
||||
// If the font contains one or more fixed-size fonts
|
||||
// instead of a scalable font, this will ignore the
|
||||
// supplied scale_factor and automatically choose the
|
||||
// scale_factor to produce the requested pixel_size
|
||||
// output from the closest matching input size.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PNMTextMaker::
|
||||
set_pixel_size(int pixel_size, double scale_factor) {
|
||||
nassertv(_is_valid);
|
||||
reset_scale(pixel_size, scale_factor);
|
||||
empty_cache();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PNMTextMaker::set_align
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PNMTextMaker::
|
||||
set_align(PNMTextMaker::Alignment align_type) {
|
||||
if (_align != align_type) {
|
||||
_align = align_type;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PNMTextMaker::get_align
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PNMTextMaker::Alignment PNMTextMaker::
|
||||
get_align() const {
|
||||
return _align;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PNMTextMaker::generate_into
|
||||
// Access: Public
|
||||
// Description: Generates text into the indicated image at the
|
||||
// indicated position.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PNMTextMaker::
|
||||
generate_into(const string &text, PNMImage &dest_image, int x, int y) {
|
||||
// First, measure the total width in pixels.
|
||||
int width = 0;
|
||||
string::const_iterator ti;
|
||||
for (ti = text.begin(); ti != text.end(); ++ti) {
|
||||
int ch = (unsigned char)(*ti);
|
||||
PNMTextGlyph *glyph = get_glyph(ch);
|
||||
width += glyph->get_advance();
|
||||
}
|
||||
|
||||
int xp;
|
||||
int yp = y;
|
||||
|
||||
switch (_align) {
|
||||
case A_left:
|
||||
xp = x;
|
||||
break;
|
||||
|
||||
case A_center:
|
||||
xp = x - (width / 2);
|
||||
break;
|
||||
|
||||
case A_right:
|
||||
xp = x - width;
|
||||
break;
|
||||
}
|
||||
|
||||
// Now place the text.
|
||||
for (ti = text.begin(); ti != text.end(); ++ti) {
|
||||
int ch = (unsigned char)(*ti);
|
||||
PNMTextGlyph *glyph = get_glyph(ch);
|
||||
glyph->place(dest_image, xp, yp);
|
||||
xp += glyph->get_advance();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PNMTextMaker::get_glyph
|
||||
// Access: Private
|
||||
// Description: Returns the glyph for the indicated index, or NULL if
|
||||
// it is not defined in the font.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PNMTextGlyph *PNMTextMaker::
|
||||
get_glyph(int character) {
|
||||
int glyph_index = FT_Get_Char_Index(_face, character);
|
||||
|
||||
Glyphs::iterator gi;
|
||||
gi = _glyphs.find(glyph_index);
|
||||
if (gi != _glyphs.end()) {
|
||||
return (*gi).second;
|
||||
}
|
||||
|
||||
PNMTextGlyph *glyph = make_glyph(glyph_index);
|
||||
_glyphs.insert(Glyphs::value_type(glyph_index, glyph));
|
||||
return glyph;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PNMTextMaker::make_glyph
|
||||
// Access: Private
|
||||
// Description: Creates a new PNMTextGlyph object for the indicated
|
||||
// index, if possible.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PNMTextGlyph *PNMTextMaker::
|
||||
make_glyph(int glyph_index) {
|
||||
int error = FT_Load_Glyph(_face, glyph_index, FT_LOAD_RENDER);
|
||||
if (error) {
|
||||
nout << "Unable to render glyph " << glyph_index << "\n";
|
||||
return (PNMTextGlyph *)NULL;
|
||||
}
|
||||
|
||||
FT_GlyphSlot slot = _face->glyph;
|
||||
FT_Bitmap &bitmap = slot->bitmap;
|
||||
|
||||
double advance = slot->advance.x / 64.0;
|
||||
|
||||
if (bitmap.width == 0 || bitmap.rows == 0) {
|
||||
// If we got an empty bitmap, it's a special case.
|
||||
PNMTextGlyph *glyph = new PNMTextGlyph(advance);
|
||||
glyph->rescale(_scale_factor);
|
||||
return glyph;
|
||||
|
||||
} else {
|
||||
PNMTextGlyph *glyph = new PNMTextGlyph(advance);
|
||||
PNMImage &glyph_image = glyph->_image;
|
||||
glyph_image.clear(bitmap.width, bitmap.rows, 1);
|
||||
|
||||
if (bitmap.pixel_mode == ft_pixel_mode_mono) {
|
||||
// This is a little bit more work: we have to expand the
|
||||
// one-bit-per-pixel bitmap into a one-byte-per-pixel texture.
|
||||
unsigned char *buffer_row = bitmap.buffer;
|
||||
for (int yi = 0; yi < bitmap.rows; yi++) {
|
||||
int bit = 0x80;
|
||||
unsigned char *b = buffer_row;
|
||||
for (int xi = 0; xi < bitmap.width; xi++) {
|
||||
if (*b & bit) {
|
||||
glyph_image.set_gray(xi, yi, 0.0);
|
||||
} else {
|
||||
glyph_image.set_gray(xi, yi, 1.0);
|
||||
}
|
||||
bit >>= 1;
|
||||
if (bit == 0) {
|
||||
++b;
|
||||
bit = 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
buffer_row += bitmap.pitch;
|
||||
}
|
||||
|
||||
} else if (bitmap.pixel_mode == ft_pixel_mode_grays) {
|
||||
// Here we must expand a grayscale pixmap with n levels of gray
|
||||
// into our 256-level texture.
|
||||
unsigned char *buffer_row = bitmap.buffer;
|
||||
for (int yi = 0; yi < bitmap.rows; yi++) {
|
||||
for (int xi = 0; xi < bitmap.width; xi++) {
|
||||
double value =
|
||||
(double)buffer_row[xi] / (double)(bitmap.num_grays - 1);
|
||||
glyph_image.set_gray(xi, yi, 1.0 - value);
|
||||
}
|
||||
buffer_row += bitmap.pitch;
|
||||
}
|
||||
|
||||
} else {
|
||||
nout << "Unexpected pixel mode in bitmap: " << (int)bitmap.pixel_mode << "\n";
|
||||
}
|
||||
|
||||
glyph->_top = slot->bitmap_top;
|
||||
glyph->_left = slot->bitmap_left;
|
||||
|
||||
glyph->rescale(_scale_factor);
|
||||
return glyph;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PNMTextMaker::reset_scale
|
||||
// Access: Private
|
||||
// Description: Sets the font to use the appropriate scale pixels,
|
||||
// and sets _scale_factor accordingly.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool PNMTextMaker::
|
||||
reset_scale(int pixel_size, double scale_factor) {
|
||||
_scale_factor = scale_factor;
|
||||
int want_pixel_size = (int)(pixel_size * _scale_factor + 0.5);
|
||||
|
||||
int error = FT_Set_Pixel_Sizes(_face, want_pixel_size, want_pixel_size);
|
||||
if (error) {
|
||||
// If we were unable to set a particular char size, perhaps we
|
||||
// have a non-scalable font. Try to figure out the closest
|
||||
// available size.
|
||||
int best_size = -1;
|
||||
if (_face->num_fixed_sizes > 0) {
|
||||
best_size = 0;
|
||||
int best_diff = abs(want_pixel_size - _face->available_sizes[0].height);
|
||||
for (int i = 1; i < _face->num_fixed_sizes; i++) {
|
||||
int diff = abs(want_pixel_size - _face->available_sizes[i].height);
|
||||
if (diff < best_diff) {
|
||||
best_size = i;
|
||||
best_diff = diff;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (best_size >= 0) {
|
||||
int pixel_height = _face->available_sizes[best_size].height;
|
||||
int pixel_width = _face->available_sizes[best_size].width;
|
||||
error = FT_Set_Pixel_Sizes(_face, pixel_width, pixel_height);
|
||||
if (!error) {
|
||||
_scale_factor = (double)pixel_height / (double)pixel_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (error) {
|
||||
nout
|
||||
<< "Unable to set " << get_name()
|
||||
<< " to " << pixel_size << " pixels.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
_line_height = _face->size->metrics.height / 64.0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PNMTextMaker::empty_cache
|
||||
// Access: Private
|
||||
// Description: Empties the cache of previously-generated glyphs.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PNMTextMaker::
|
||||
empty_cache() {
|
||||
Glyphs::iterator gi;
|
||||
for (gi = _glyphs.begin(); gi != _glyphs.end(); ++gi) {
|
||||
PNMTextGlyph *glyph = (*gi).second;
|
||||
delete glyph;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PNMTextMaker::initialize_ft_library
|
||||
// Access: Private, Static
|
||||
// Description: Should be called exactly once to initialize the
|
||||
// FreeType library.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PNMTextMaker::
|
||||
initialize_ft_library() {
|
||||
if (!_ft_initialized) {
|
||||
int error = FT_Init_FreeType(&_ft_library);
|
||||
_ft_initialized = true;
|
||||
if (error) {
|
||||
nout << "Unable to initialize FreeType.\n";
|
||||
} else {
|
||||
_ft_ok = true;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,83 +0,0 @@
|
||||
// Filename: pnmTextMaker.h
|
||||
// Created by: drose (03Apr02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://www.panda3d.org/license.txt .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d@yahoogroups.com .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef PNMTEXTMAKER_H
|
||||
#define PNMTEXTMAKER_H
|
||||
|
||||
#include "pandatoolbase.h"
|
||||
#include "pmap.h"
|
||||
#include "namable.h"
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
class Filename;
|
||||
class PNMImage;
|
||||
class PNMTextGlyph;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : PNMTextMaker
|
||||
// Description : An object that uses Freetype to generate text at a
|
||||
// fixed pixel size into a PNMImage.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class PNMTextMaker : public Namable {
|
||||
public:
|
||||
PNMTextMaker(const Filename &font_filename, int face_index);
|
||||
PNMTextMaker(const char *font_data, int font_data_size, int face_index);
|
||||
~PNMTextMaker();
|
||||
|
||||
enum Alignment {
|
||||
A_left,
|
||||
A_right,
|
||||
A_center,
|
||||
};
|
||||
|
||||
bool is_valid() const;
|
||||
|
||||
void set_pixel_size(int pixel_size, double scale_factor = 1.0);
|
||||
|
||||
void set_align(Alignment align_type);
|
||||
Alignment get_align() const;
|
||||
|
||||
void generate_into(const string &text,
|
||||
PNMImage &dest_image, int x, int y);
|
||||
|
||||
private:
|
||||
PNMTextGlyph *get_glyph(int character);
|
||||
PNMTextGlyph *make_glyph(int glyph_index);
|
||||
bool reset_scale(int pixel_size, double scale_factor);
|
||||
void empty_cache();
|
||||
|
||||
static void initialize_ft_library();
|
||||
|
||||
bool _is_valid;
|
||||
|
||||
typedef pmap<int, PNMTextGlyph *> Glyphs;
|
||||
Glyphs _glyphs;
|
||||
|
||||
FT_Face _face;
|
||||
double _scale_factor;
|
||||
double _line_height;
|
||||
Alignment _align;
|
||||
|
||||
static FT_Library _ft_library;
|
||||
static bool _ft_initialized;
|
||||
static bool _ft_ok;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user