open_toontown_panda3d/panda/src/text/dynamicTextGlyph.cxx

210 lines
7.7 KiB
C++

// Filename: dynamicTextGlyph.cxx
// Created by: drose (09Feb02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "dynamicTextGlyph.h"
#ifdef HAVE_FREETYPE
#include "dynamicTextPage.h"
#include "geomTextGlyph.h"
#include "geomVertexData.h"
#include "geomVertexFormat.h"
#include "geomTriangles.h"
#include "geomVertexWriter.h"
#include "textureAttrib.h"
#include "transparencyAttrib.h"
#include "colorAttrib.h"
#include "renderState.h"
#include "config_gobj.h"
////////////////////////////////////////////////////////////////////
// Function: DynamicTextGlyph::Destructor
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
DynamicTextGlyph::
~DynamicTextGlyph() {
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextGlyph::get_row
// Access: Public
// Description: Returns a pointer to the first byte in the pixel
// buffer associated with the leftmost pixel in the
// indicated row, where 0 is the topmost row and _y_size
// - _margin * 2 - 1 is the bottommost row.
////////////////////////////////////////////////////////////////////
unsigned char *DynamicTextGlyph::
get_row(int y) {
nassertr(y >= 0 && y < _y_size - _margin * 2, (unsigned char *)NULL);
nassertr(_page != (DynamicTextPage *)NULL, (unsigned char *)NULL);
// First, offset y by the glyph's start.
y += _y + _margin;
// Also, get the x start.
int x = _x + _margin;
// Invert y.
y = _page->get_y_size() - 1 - y;
int offset = (y * _page->get_x_size()) + x;
int pixel_width = _page->get_num_components() * _page->get_component_width();
return _page->modify_ram_image() + offset * pixel_width;
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextGlyph::erase
// Access: Public
// Description: Erases the glyph from the texture map.
////////////////////////////////////////////////////////////////////
void DynamicTextGlyph::
erase(DynamicTextFont *font) {
nassertv(_page != (DynamicTextPage *)NULL);
nassertv(_page->has_ram_image());
// The glyph covers the pixels from (_x, _y) over the rectangle
// (_x_size, _y_size), but it doesn't include _margin pixels around
// the interior of the rectangle. Erase all the pixels that the
// glyph covers.
_page->fill_region(_x + _margin,
_page->get_y_size() - (_y + _y_size - _margin),
_x_size - _margin * 2, _y_size - _margin * 2,
font->get_bg());
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextGlyph::make_geom
// Access: Public
// Description: Creates the actual geometry for the glyph. The
// parameters bitmap_top and bitmap_left are from
// FreeType, and indicate the position of the top left
// corner of the bitmap relative to the glyph's origin.
// The advance number represents the number of pixels
// the pen should be advanced after drawing this glyph.
////////////////////////////////////////////////////////////////////
void DynamicTextGlyph::
make_geom(int bitmap_top, int bitmap_left, float advance, float poly_margin,
float tex_x_size, float tex_y_size,
float font_pixels_per_unit, float tex_pixels_per_unit) {
nassertv(_page != (DynamicTextPage *)NULL);
// This function should not be called twice.
nassertv(_geom_count == 0);
tex_x_size += _margin * 2;
tex_y_size += _margin * 2;
// Determine the corners of the rectangle in geometric units.
float tex_poly_margin = poly_margin / tex_pixels_per_unit;
float origin_y = bitmap_top / font_pixels_per_unit;
float origin_x = bitmap_left / font_pixels_per_unit;
float top = origin_y + tex_poly_margin;
float left = origin_x - tex_poly_margin;
float bottom = origin_y - tex_y_size / tex_pixels_per_unit - tex_poly_margin;
float right = origin_x + tex_x_size / tex_pixels_per_unit + tex_poly_margin;
// And the corresponding corners in UV units. We add 0.5f to center
// the UV in the middle of its texel, to minimize roundoff errors
// when we are close to 1-to-1 pixel size.
float uv_top = 1.0f - ((float)(_y - poly_margin) + 0.5f) / _page->get_y_size();
float uv_left = ((float)(_x - poly_margin) + 0.5f) / _page->get_x_size();
float uv_bottom = 1.0f - ((float)(_y + poly_margin + tex_y_size) + 0.5f) / _page->get_y_size();
float uv_right = ((float)(_x + poly_margin + tex_x_size) + 0.5f) / _page->get_x_size();
// Create a corresponding triangle pair. We use a pair of indexed
// triangles rather than a single triangle strip, to avoid the bad
// vertex duplication behavior with lots of two-triangle strips.
PT(GeomVertexData) vdata = new GeomVertexData
(string(), GeomVertexFormat::get_v3t2(),
Geom::UH_static);
GeomVertexWriter vertex(vdata, InternalName::get_vertex());
GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
vertex.add_data3f(left, 0, top);
vertex.add_data3f(left, 0, bottom);
vertex.add_data3f(right, 0, top);
vertex.add_data3f(right, 0, bottom);
texcoord.add_data2f(uv_left, uv_top);
texcoord.add_data2f(uv_left, uv_bottom);
texcoord.add_data2f(uv_right, uv_top);
texcoord.add_data2f(uv_right, uv_bottom);
PT(GeomTriangles) tris = new GeomTriangles(Geom::UH_static);
tris->add_vertex(0);
tris->add_vertex(1);
tris->add_vertex(2);
tris->close_primitive();
tris->add_vertex(2);
tris->add_vertex(1);
tris->add_vertex(3);
tris->close_primitive();
PT(Geom) geom = new GeomTextGlyph(this, vdata);
geom->add_primitive(tris);
_geom = geom;
// The above will increment our _geom_count to 1. Reset it back
// down to 0, since our own internal Geom doesn't count.
nassertv(_geom_count == 1);
_geom_count--;
_state = RenderState::make(TextureAttrib::make(_page),
TransparencyAttrib::make(TransparencyAttrib::M_alpha));
_state = _state->add_attrib(ColorAttrib::make_flat(Colorf(1.0f, 1.0f, 1.0f, 1.0f)), -1);
_advance = advance / font_pixels_per_unit;
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextGlyph::set_geom
// Access: Public
// Description: Sets the geom from a pre-built object.
////////////////////////////////////////////////////////////////////
void DynamicTextGlyph::
set_geom(GeomVertexData *vdata, GeomPrimitive *prim,
const RenderState *state) {
// This function is called when _geom_count = 1, because it was
// constructed via the empty Glyph constructor.
nassertv(_geom_count == 1);
_geom_count--;
PT(Geom) geom = new GeomTextGlyph(this, vdata);
geom->add_primitive(prim);
_geom = geom;
// The above will increment our _geom_count to 1. Reset it back
// down to 0, since our own internal Geom doesn't count.
nassertv(_geom_count == 1);
_geom_count--;
_state = state;
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextGlyph::is_whitespace
// Access: Public, Virtual
// Description: Returns true if this glyph represents invisible
// whitespace, or false if it corresponds to some
// visible character.
////////////////////////////////////////////////////////////////////
bool DynamicTextGlyph::
is_whitespace() const {
return (_page == (DynamicTextPage *)NULL);
}
#endif // HAVE_FREETYPE