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 TARGET indexify
|
||||||
#define OTHER_LIBS \
|
#define OTHER_LIBS \
|
||||||
progbase pandatoolbase \
|
progbase pandatoolbase \
|
||||||
pnmimage:c pnmimagetypes:c panda:m pandaexpress:m \
|
pnmtext:c pnmimage:c pnmimagetypes:c panda:m pandaexpress:m \
|
||||||
dtool:m dtoolconfig:m \
|
dtool:m dtoolconfig:m \
|
||||||
pystub
|
pystub
|
||||||
|
|
||||||
@ -17,9 +17,7 @@
|
|||||||
indexParameters.cxx indexParameters.h \
|
indexParameters.cxx indexParameters.h \
|
||||||
indexify.cxx indexify.h \
|
indexify.cxx indexify.h \
|
||||||
photo.cxx photo.h \
|
photo.cxx photo.h \
|
||||||
rollDirectory.cxx rollDirectory.h \
|
rollDirectory.cxx rollDirectory.h
|
||||||
pnmTextGlyph.cxx pnmTextGlyph.h \
|
|
||||||
pnmTextMaker.cxx pnmTextMaker.h
|
|
||||||
|
|
||||||
#end bin_target
|
#end bin_target
|
||||||
|
|
||||||
@ -29,14 +27,12 @@
|
|||||||
#define TARGET font-samples
|
#define TARGET font-samples
|
||||||
#define OTHER_LIBS \
|
#define OTHER_LIBS \
|
||||||
progbase pandatoolbase \
|
progbase pandatoolbase \
|
||||||
pnmimage:c pnmimagetypes:c panda:m pandaexpress:m \
|
pnmtext:c pnmimage:c pnmimagetypes:c panda:m pandaexpress:m \
|
||||||
dtool:m dtoolconfig:m \
|
dtool:m dtoolconfig:m \
|
||||||
pystub
|
pystub
|
||||||
|
|
||||||
#define SOURCES \
|
#define SOURCES \
|
||||||
default_font.cxx default_font.h \
|
default_font.cxx default_font.h \
|
||||||
fontSamples.cxx fontSamples.h \
|
fontSamples.cxx fontSamples.h
|
||||||
pnmTextGlyph.cxx pnmTextGlyph.h \
|
|
||||||
pnmTextMaker.cxx pnmTextMaker.h
|
|
||||||
|
|
||||||
#end bin_target
|
#end bin_target
|
||||||
|
@ -181,7 +181,8 @@ post_command_line() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (_name_text_maker != (PNMTextMaker *)NULL) {
|
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 {
|
} else {
|
||||||
_name_height = 0;
|
_name_height = 0;
|
||||||
}
|
}
|
||||||
@ -229,7 +230,8 @@ run() {
|
|||||||
if (!text_maker->is_valid()) {
|
if (!text_maker->is_valid()) {
|
||||||
all_ok = false;
|
all_ok = false;
|
||||||
} else {
|
} 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,
|
text_maker->generate_into(_sample_text, output_image,
|
||||||
16, y + _sample_height);
|
16, y + _sample_height);
|
||||||
if (_name_text_maker != (PNMTextMaker *)NULL) {
|
if (_name_text_maker != (PNMTextMaker *)NULL) {
|
||||||
@ -243,10 +245,6 @@ run() {
|
|||||||
delete text_maker;
|
delete text_maker;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!all_ok) {
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf(output_filename, output_filename_size,
|
snprintf(output_filename, output_filename_size,
|
||||||
_output_filename.c_str(), output_index);
|
_output_filename.c_str(), output_index);
|
||||||
nout << "Writing " << output_filename << "\n";
|
nout << "Writing " << output_filename << "\n";
|
||||||
@ -254,6 +252,11 @@ run() {
|
|||||||
nout << "Unable to write to " << output_filename << "\n";
|
nout << "Unable to write to " << output_filename << "\n";
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!all_ok) {
|
||||||
|
nout << "Problem loading fonts.\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -386,7 +386,8 @@ post_command_line() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (_text_maker != (PNMTextMaker *)NULL) {
|
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);
|
_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