Panda3D
dynamicTextPage.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file dynamicTextPage.cxx
10  * @author drose
11  * @date 2002-02-09
12  */
13 
14 #include "dynamicTextPage.h"
15 #include "dynamicTextFont.h"
16 #include "config_text.h"
17 
18 #ifdef HAVE_FREETYPE
19 
20 TypeHandle DynamicTextPage::_type_handle;
21 
22 /**
23  *
24  */
25 DynamicTextPage::
26 DynamicTextPage(DynamicTextFont *font, int page_number) :
27  _font(font)
28 {
29  // Since the texture might change frequently, don't try to compress it by
30  // default.
31  set_compression(CM_off);
32 
33  // It's usually pretty important for text to look its best, and it doesn't
34  // usually have a high fill factor.
35  set_quality_level(text_quality_level);
36 
37  _size = _font->get_page_size();
38 
39  setup_2d_texture(_size[0], _size[1], T_unsigned_byte, font->get_tex_format());
40 
41  // Assign a name to the Texture.
42  std::ostringstream strm;
43  strm << font->get_name() << "_" << page_number;
44  set_name(strm.str());
45 
46  // We'd better never free this image.
47  set_keep_ram_image(true);
48 
49  set_minfilter(_font->get_minfilter());
50  set_magfilter(_font->get_magfilter());
51 
52  set_anisotropic_degree(_font->get_anisotropic_degree());
53 
54  // Clamp to an explicit invisible border, so we don't get bleeding at the
55  // edges at all.
56  set_wrap_u(text_wrap_mode);
57  set_wrap_v(text_wrap_mode);
58  set_border_color(font->get_bg());
59 
60  // Fill the page with the font's background color.
61  fill_region(0, 0, _size[0], _size[1], font->get_bg());
62 }
63 
64 /**
65  * Finds space within the page for a glyph of the indicated size. If space is
66  * found, creates a new glyph object and returns it; otherwise, returns NULL.
67  */
68 DynamicTextGlyph *DynamicTextPage::
69 slot_glyph(int character, int x_size, int y_size, int margin,
70  PN_stdfloat advance) {
71  int x, y;
72  if (!find_hole(x, y, x_size, y_size)) {
73  // No room for the glyph.
74  return nullptr;
75  }
76 
77  // The glyph can be fit at (x, y). Slot it.
78  PT(DynamicTextGlyph) glyph =
79  new DynamicTextGlyph(character, this,
80  x, y, x_size, y_size, margin, advance);
81  _glyphs.push_back(glyph);
82  return glyph;
83 }
84 
85 /**
86  * Fills a rectangular region of the texture with the indicated color.
87  */
88 void DynamicTextPage::
89 fill_region(int x, int y, int x_size, int y_size, const LColor &color) {
90  nassertv(x >= 0 && x + x_size <= _size[0] && y >= 0 && y + y_size <= _size[1]);
91  int num_components = get_num_components();
92  if (num_components == 1) {
93  // Luminance or alpha.
94  int ci = 3;
95  if (get_format() != Texture::F_alpha) {
96  ci = 0;
97  }
98 
99  unsigned char v = (unsigned char)(color[ci] * 255.0f);
100 
101  unsigned char *image = modify_ram_image();
102  for (int yi = y; yi < y + y_size; yi++) {
103  unsigned char *row = image + yi * _size[0];
104  memset(row + x, v, x_size);
105  }
106 
107  } else if (num_components == 2) {
108  // Luminance + alpha.
109 
110  union {
111  unsigned char p[2];
112  uint16_t v;
113  } v;
114 
115  v.p[0] = (unsigned char)(color[0] * 255.0f);
116  v.p[1] = (unsigned char)(color[3] * 255.0f);
117 
118  uint16_t *image = (uint16_t *)modify_ram_image().p();
119  for (int yi = y; yi < y + y_size; yi++) {
120  uint16_t *row = image + yi * _size[0] ;
121  for (int xi = x; xi < x + x_size; xi++) {
122  row[xi] = v.v;
123  }
124  }
125 
126  } else if (num_components == 3) {
127  // RGB.
128 
129  unsigned char p0 = (unsigned char)(color[2] * 255.0f);
130  unsigned char p1 = (unsigned char)(color[1] * 255.0f);
131  unsigned char p2 = (unsigned char)(color[0] * 255.0f);
132 
133  unsigned char *image = modify_ram_image();
134  for (int yi = y; yi < y + y_size; yi++) {
135  unsigned char *row = image + yi * _size[0] * 3;
136  for (int xi = x; xi < x + x_size; xi++) {
137  row[xi * 3] = p0;
138  row[xi * 3 + 1] = p1;
139  row[xi * 3 + 2] = p2;
140  }
141  }
142 
143  } else { // (num_components == 4)
144  // RGBA.
145  union {
146  unsigned char p[4];
147  uint32_t v;
148  } v;
149 
150  v.p[0] = (unsigned char)(color[2] * 255.0f);
151  v.p[1] = (unsigned char)(color[1] * 255.0f);
152  v.p[2] = (unsigned char)(color[0] * 255.0f);
153  v.p[3] = (unsigned char)(color[3] * 255.0f);
154 
155  uint32_t *image = (uint32_t *)modify_ram_image().p();
156  for (int yi = y; yi < y + y_size; yi++) {
157  uint32_t *row = image + yi * _size[0];
158  for (int xi = x; xi < x + x_size; xi++) {
159  row[xi] = v.v;
160  }
161  }
162  }
163 }
164 
165 /**
166  * Removes all of the glyphs from the page that are no longer being used by
167  * any Geoms. This should only be called from
168  * DynamicTextFont::garbage_collect(), since it is important to remove these
169  * glyphs from the font's index first.
170  */
171 int DynamicTextPage::
172 garbage_collect(DynamicTextFont *font) {
173  int removed_count = 0;
174 
175  Glyphs new_glyphs;
176  Glyphs::iterator gi;
177  for (gi = _glyphs.begin(); gi != _glyphs.end(); ++gi) {
178  DynamicTextGlyph *glyph = (*gi);
179  if (glyph->get_ref_count() > 1) {
180  // Keep this one.
181  new_glyphs.insert(new_glyphs.end(), (*gi));
182  } else {
183  // Drop this one.
184  removed_count++;
185  glyph->erase(font);
186  }
187  }
188 
189  _glyphs.swap(new_glyphs);
190  return removed_count;
191 }
192 
193 /**
194  * Searches for a hole of at least x_size by y_size pixels somewhere within
195  * the page. If a suitable hole is found, sets x and y to the top left corner
196  * and returns true; otherwise, returns false.
197  */
198 bool DynamicTextPage::
199 find_hole(int &x, int &y, int x_size, int y_size) const {
200  y = 0;
201  while (y + y_size <= _size[1]) {
202  int next_y = _size[1];
203  // Scan along the row at 'y'.
204  x = 0;
205  while (x + x_size <= _size[0]) {
206  int next_x = x;
207 
208  // Consider the spot at x, y.
209  DynamicTextGlyph *overlap = find_overlap(x, y, x_size, y_size);
210 
211  if (overlap == nullptr) {
212  // Hooray!
213  return true;
214  }
215 
216  next_x = overlap->_x + overlap->_x_size;
217  next_y = std::min(next_y, overlap->_y + overlap->_y_size);
218  nassertr(next_x > x, false);
219  x = next_x;
220  }
221 
222  nassertr(next_y > y, false);
223  y = next_y;
224  }
225 
226  // Nope, wouldn't fit anywhere.
227  return false;
228 }
229 
230 /**
231  * If the rectangle whose top left corner is x, y and whose size is x_size,
232  * y_size describes an empty hole that does not overlap any placed glyphs,
233  * returns NULL; otherwise, returns the first placed glyph that the image does
234  * overlap. It is assumed the rectangle lies completely within the boundaries
235  * of the page itself.
236  */
237 DynamicTextGlyph *DynamicTextPage::
238 find_overlap(int x, int y, int x_size, int y_size) const {
239  Glyphs::const_iterator gi;
240  for (gi = _glyphs.begin(); gi != _glyphs.end(); ++gi) {
241  DynamicTextGlyph *glyph = (*gi);
242  if (glyph->intersects(x, y, x_size, y_size)) {
243  return glyph;
244  }
245  }
246 
247  return nullptr;
248 }
249 
250 
251 #endif // HAVE_FREETYPE
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.