Panda3D
|
00001 // Filename: dynamicTextPage.cxx 00002 // Created by: drose (09Feb02) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "dynamicTextPage.h" 00016 #include "dynamicTextFont.h" 00017 00018 #ifdef HAVE_FREETYPE 00019 00020 00021 TypeHandle DynamicTextPage::_type_handle; 00022 00023 //////////////////////////////////////////////////////////////////// 00024 // Function: DynamicTextPage::Constructor 00025 // Access: Publiic 00026 // Description: 00027 //////////////////////////////////////////////////////////////////// 00028 DynamicTextPage:: 00029 DynamicTextPage(DynamicTextFont *font, int page_number) : 00030 _font(font) 00031 { 00032 // Since the texture might change frequently, don't try to compress 00033 // it by default. 00034 set_compression(CM_off); 00035 00036 // It's usually pretty important for text to look its best, and it 00037 // doesn't usually have a high fill factor. 00038 set_quality_level(text_quality_level); 00039 00040 _x_size = _font->get_page_x_size(); 00041 _y_size = _font->get_page_y_size(); 00042 00043 setup_2d_texture(_x_size, _y_size, T_unsigned_byte, font->get_tex_format()); 00044 00045 // Assign a name to the Texture. 00046 ostringstream strm; 00047 strm << font->get_name() << "_" << page_number; 00048 set_name(strm.str()); 00049 00050 // We'd better never free this image. 00051 set_keep_ram_image(true); 00052 00053 set_minfilter(_font->get_minfilter()); 00054 set_magfilter(_font->get_magfilter()); 00055 00056 set_anisotropic_degree(_font->get_anisotropic_degree()); 00057 00058 // Clamp to an explicit invisible border, so we don't get bleeding 00059 // at the edges at all. 00060 set_wrap_u(text_wrap_mode); 00061 set_wrap_v(text_wrap_mode); 00062 set_border_color(font->get_bg()); 00063 00064 // Fill the page with the font's background color. 00065 fill_region(0, 0, _x_size, _y_size, font->get_bg()); 00066 } 00067 00068 //////////////////////////////////////////////////////////////////// 00069 // Function: DynamicTextPage::slot_glyph 00070 // Access: Public 00071 // Description: Finds space within the page for a glyph of the 00072 // indicated size. If space is found, creates a new 00073 // glyph object and returns it; otherwise, returns NULL. 00074 //////////////////////////////////////////////////////////////////// 00075 DynamicTextGlyph *DynamicTextPage:: 00076 slot_glyph(int character, int x_size, int y_size, int margin) { 00077 int x, y; 00078 if (!find_hole(x, y, x_size, y_size)) { 00079 // No room for the glyph. 00080 return (DynamicTextGlyph *)NULL; 00081 } 00082 00083 // The glyph can be fit at (x, y). Slot it. 00084 PT(DynamicTextGlyph) glyph = 00085 new DynamicTextGlyph(character, this, 00086 x, y, x_size, y_size, margin); 00087 _glyphs.push_back(glyph); 00088 return glyph; 00089 } 00090 00091 //////////////////////////////////////////////////////////////////// 00092 // Function: DynamicTextPage::fill_region 00093 // Access: Private 00094 // Description: Fills a rectangular region of the texture with the 00095 // indicated color. 00096 //////////////////////////////////////////////////////////////////// 00097 void DynamicTextPage:: 00098 fill_region(int x, int y, int x_size, int y_size, const LColor &color) { 00099 nassertv(x >= 0 && x + x_size <= _x_size && y >= 0 && y + y_size <= _y_size); 00100 int num_components = get_num_components(); 00101 if (num_components == 1) { 00102 // Luminance or alpha. 00103 int ci = 3; 00104 if (get_format() != Texture::F_alpha) { 00105 ci = 0; 00106 } 00107 00108 unsigned char v = (unsigned char)(color[ci] * 255.0f); 00109 00110 unsigned char *image = modify_ram_image(); 00111 for (int yi = y; yi < y + y_size; yi++) { 00112 unsigned char *row = image + yi * _x_size; 00113 memset(row + x, v, x_size); 00114 } 00115 00116 } else if (num_components == 2) { 00117 // Luminance + alpha. 00118 00119 union { 00120 unsigned char p[2]; 00121 PN_uint16 v; 00122 } v; 00123 00124 v.p[0] = (unsigned char)(color[0] * 255.0f); 00125 v.p[1] = (unsigned char)(color[3] * 255.0f); 00126 00127 PN_uint16 *image = (PN_uint16 *)modify_ram_image().p(); 00128 for (int yi = y; yi < y + y_size; yi++) { 00129 PN_uint16 *row = image + yi * _x_size ; 00130 for (int xi = x; xi < x + x_size; xi++) { 00131 row[xi] = v.v; 00132 } 00133 } 00134 00135 } else if (num_components == 3) { 00136 // RGB. 00137 00138 unsigned char p0 = (unsigned char)(color[2] * 255.0f); 00139 unsigned char p1 = (unsigned char)(color[1] * 255.0f); 00140 unsigned char p2 = (unsigned char)(color[0] * 255.0f); 00141 00142 unsigned char *image = modify_ram_image(); 00143 for (int yi = y; yi < y + y_size; yi++) { 00144 unsigned char *row = image + yi * _x_size * 3; 00145 for (int xi = x; xi < x + x_size; xi++) { 00146 row[xi * 3] = p0; 00147 row[xi * 3 + 1] = p1; 00148 row[xi * 3 + 2] = p2; 00149 } 00150 } 00151 00152 } else { // (num_components == 4) 00153 // RGBA. 00154 union { 00155 unsigned char p[4]; 00156 PN_uint32 v; 00157 } v; 00158 00159 v.p[0] = (unsigned char)(color[2] * 255.0f); 00160 v.p[1] = (unsigned char)(color[1] * 255.0f); 00161 v.p[2] = (unsigned char)(color[0] * 255.0f); 00162 v.p[3] = (unsigned char)(color[3] * 255.0f); 00163 00164 PN_uint32 *image = (PN_uint32 *)modify_ram_image().p(); 00165 for (int yi = y; yi < y + y_size; yi++) { 00166 PN_uint32 *row = image + yi * _x_size; 00167 for (int xi = x; xi < x + x_size; xi++) { 00168 row[xi] = v.v; 00169 } 00170 } 00171 } 00172 } 00173 00174 //////////////////////////////////////////////////////////////////// 00175 // Function: DynamicTextPage::garbage_collect 00176 // Access: Private 00177 // Description: Removes all of the glyphs from the page that are no 00178 // longer being used by any Geoms. This should only be 00179 // called from DynamicTextFont::garbage_collect(), since 00180 // it is important to remove these glyphs from the 00181 // font's index first. 00182 //////////////////////////////////////////////////////////////////// 00183 int DynamicTextPage:: 00184 garbage_collect(DynamicTextFont *font) { 00185 int removed_count = 0; 00186 00187 Glyphs new_glyphs; 00188 Glyphs::iterator gi; 00189 for (gi = _glyphs.begin(); gi != _glyphs.end(); ++gi) { 00190 DynamicTextGlyph *glyph = (*gi); 00191 if (glyph->_geom_count != 0) { 00192 // Keep this one. 00193 new_glyphs.insert(new_glyphs.end(), (*gi)); 00194 } else { 00195 // Drop this one. 00196 removed_count++; 00197 glyph->erase(font); 00198 } 00199 } 00200 00201 _glyphs.swap(new_glyphs); 00202 return removed_count; 00203 } 00204 00205 //////////////////////////////////////////////////////////////////// 00206 // Function: DynamicTextPage::find_hole 00207 // Access: Private 00208 // Description: Searches for a hole of at least x_size by y_size 00209 // pixels somewhere within the page. If a suitable hole 00210 // is found, sets x and y to the top left corner and 00211 // returns true; otherwise, returns false. 00212 //////////////////////////////////////////////////////////////////// 00213 bool DynamicTextPage:: 00214 find_hole(int &x, int &y, int x_size, int y_size) const { 00215 y = 0; 00216 while (y + y_size <= _y_size) { 00217 int next_y = _y_size; 00218 // Scan along the row at 'y'. 00219 x = 0; 00220 while (x + x_size <= _x_size) { 00221 int next_x = x; 00222 00223 // Consider the spot at x, y. 00224 DynamicTextGlyph *overlap = find_overlap(x, y, x_size, y_size); 00225 00226 if (overlap == (DynamicTextGlyph *)NULL) { 00227 // Hooray! 00228 return true; 00229 } 00230 00231 next_x = overlap->_x + overlap->_x_size; 00232 next_y = min(next_y, overlap->_y + overlap->_y_size); 00233 nassertr(next_x > x, false); 00234 x = next_x; 00235 } 00236 00237 nassertr(next_y > y, false); 00238 y = next_y; 00239 } 00240 00241 // Nope, wouldn't fit anywhere. 00242 return false; 00243 } 00244 00245 //////////////////////////////////////////////////////////////////// 00246 // Function: DynamicTextPage::find_overlap 00247 // Access: Private 00248 // Description: If the rectangle whose top left corner is x, y and 00249 // whose size is x_size, y_size describes an empty hole 00250 // that does not overlap any placed glyphs, returns 00251 // NULL; otherwise, returns the first placed glyph 00252 // that the image does overlap. It is assumed the 00253 // rectangle lies completely within the boundaries of 00254 // the page itself. 00255 //////////////////////////////////////////////////////////////////// 00256 DynamicTextGlyph *DynamicTextPage:: 00257 find_overlap(int x, int y, int x_size, int y_size) const { 00258 Glyphs::const_iterator gi; 00259 for (gi = _glyphs.begin(); gi != _glyphs.end(); ++gi) { 00260 DynamicTextGlyph *glyph = (*gi); 00261 if (glyph->intersects(x, y, x_size, y_size)) { 00262 return glyph; 00263 } 00264 } 00265 00266 return (DynamicTextGlyph *)NULL; 00267 } 00268 00269 00270 #endif // HAVE_FREETYPE