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