00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "textureMemoryCounter.h"
00016 #include "paletteImage.h"
00017 #include "textureImage.h"
00018 #include "destTextureImage.h"
00019 #include "omitReason.h"
00020 #include "texturePlacement.h"
00021
00022 #include "indent.h"
00023 #include <math.h>
00024
00025
00026
00027
00028
00029
00030 TextureMemoryCounter::
00031 TextureMemoryCounter() {
00032 reset();
00033 }
00034
00035
00036
00037
00038
00039
00040 void TextureMemoryCounter::
00041 reset() {
00042 _num_textures = 0;
00043 _num_unplaced = 0;
00044 _num_placed = 0;
00045 _num_palettes = 0;
00046
00047 _bytes = 0;
00048 _unused_bytes = 0;
00049 _duplicate_bytes = 0;
00050 _coverage_bytes = 0;
00051 _textures.clear();
00052 _palettes.clear();
00053 }
00054
00055
00056
00057
00058
00059
00060 void TextureMemoryCounter::
00061 add_placement(TexturePlacement *placement) {
00062 TextureImage *texture = placement->get_texture();
00063 nassertv(texture != (TextureImage *)NULL);
00064
00065 if (placement->get_omit_reason() == OR_none) {
00066 PaletteImage *image = placement->get_image();
00067 nassertv(image != (PaletteImage *)NULL);
00068 add_palette(image);
00069
00070 int bytes = count_bytes(image, placement->get_placed_x_size(),
00071 placement->get_placed_y_size());
00072 add_texture(texture, bytes);
00073 _num_placed++;
00074
00075 } else {
00076 DestTextureImage *dest = placement->get_dest();
00077 if (dest != (DestTextureImage *)NULL) {
00078 int bytes = count_bytes(dest);
00079 add_texture(texture, bytes);
00080
00081 _bytes += bytes;
00082 _num_unplaced++;
00083 }
00084 }
00085 }
00086
00087
00088
00089
00090
00091
00092 void TextureMemoryCounter::
00093 report(ostream &out, int indent_level) {
00094 indent(out, indent_level)
00095 << _num_placed << " of " << _num_textures << " textures appear on "
00096 << _num_palettes << " palette images with " << _num_unplaced
00097 << " unplaced.\n";
00098
00099 indent(out, indent_level)
00100 << (_bytes + 512) / 1024 << "k estimated texture memory required.\n";
00101
00102 if (_bytes != 0) {
00103 if (_unused_bytes != 0) {
00104 indent(out, indent_level + 2);
00105 format_memory_fraction(out, _unused_bytes, _bytes)
00106 << " is wasted because of unused palette space.\n";
00107 }
00108
00109 if (_coverage_bytes > 0) {
00110 indent(out, indent_level + 2);
00111 format_memory_fraction(out, _coverage_bytes, _bytes)
00112 << " is wasted for repeating textures and margins.\n";
00113
00114 } else if (_coverage_bytes < 0) {
00115 indent(out, indent_level + 2);
00116 format_memory_fraction(out, -_coverage_bytes, _bytes)
00117 << " is *saved* for palettizing partial textures.\n";
00118 }
00119
00120 if (_duplicate_bytes != 0) {
00121 indent(out, indent_level + 2);
00122 format_memory_fraction(out, _duplicate_bytes, _bytes)
00123 << " is wasted because of a texture appearing in multiple groups.\n";
00124 }
00125 }
00126 }
00127
00128
00129
00130
00131
00132
00133
00134
00135 ostream &TextureMemoryCounter::
00136 format_memory_fraction(ostream &out, int fraction_bytes, int palette_bytes) {
00137 out << floor(1000.0 * (double)fraction_bytes / (double)palette_bytes + 0.5) / 10.0
00138 << "% (" << (fraction_bytes + 512) / 1024 << "k)";
00139 return out;
00140 }
00141
00142
00143
00144
00145
00146
00147
00148
00149 void TextureMemoryCounter::
00150 add_palette(PaletteImage *image) {
00151 bool inserted = _palettes.insert(image).second;
00152 if (!inserted) {
00153
00154 return;
00155 }
00156
00157 int bytes = count_bytes(image);
00158 double unused = 1.0 - image->count_utilization();
00159 double coverage = image->count_coverage();
00160
00161 _bytes += bytes;
00162 _unused_bytes += (int)(unused * bytes);
00163 _coverage_bytes += (int)(coverage * bytes);
00164
00165 _num_palettes++;
00166 }
00167
00168
00169
00170
00171
00172
00173
00174
00175 void TextureMemoryCounter::
00176 add_texture(TextureImage *texture, int bytes) {
00177 pair<Textures::iterator, bool> result;
00178 result = _textures.insert(Textures::value_type(texture, bytes));
00179 if (result.second) {
00180
00181 _num_textures++;
00182 return;
00183 }
00184
00185
00186 Textures::iterator ti = result.first;
00187
00188 _duplicate_bytes += min(bytes, (*ti).second);
00189 (*ti).second = max(bytes, (*ti).second);
00190 }
00191
00192
00193
00194
00195
00196
00197
00198 int TextureMemoryCounter::
00199 count_bytes(ImageFile *image) {
00200 return count_bytes(image, image->get_x_size(), image->get_y_size());
00201 }
00202
00203
00204
00205
00206
00207
00208
00209 int TextureMemoryCounter::
00210 count_bytes(ImageFile *image, int x_size, int y_size) {
00211 int pixels = x_size * y_size;
00212
00213
00214
00215
00216
00217 int bpp = 0;
00218 switch (image->get_properties()._format) {
00219 case EggTexture::F_rgba12:
00220 bpp = 6;
00221 break;
00222
00223 case EggTexture::F_rgba:
00224 case EggTexture::F_rgbm:
00225 case EggTexture::F_rgba8:
00226 bpp = 4;
00227 break;
00228
00229 case EggTexture::F_rgb:
00230 case EggTexture::F_rgb12:
00231 bpp = 3;
00232 break;
00233
00234 case EggTexture::F_rgba4:
00235 case EggTexture::F_rgba5:
00236 case EggTexture::F_rgb8:
00237 case EggTexture::F_rgb5:
00238 case EggTexture::F_luminance_alpha:
00239 case EggTexture::F_luminance_alphamask:
00240 bpp = 2;
00241 break;
00242
00243 case EggTexture::F_rgb332:
00244 case EggTexture::F_red:
00245 case EggTexture::F_green:
00246 case EggTexture::F_blue:
00247 case EggTexture::F_alpha:
00248 case EggTexture::F_luminance:
00249 bpp = 1;
00250 break;
00251
00252 default:
00253 bpp = image->get_num_channels();
00254 }
00255
00256 int bytes = pixels * bpp;
00257
00258
00259 switch (image->get_properties()._minfilter) {
00260 case EggTexture::FT_nearest_mipmap_nearest:
00261 case EggTexture::FT_linear_mipmap_nearest:
00262 case EggTexture::FT_nearest_mipmap_linear:
00263 case EggTexture::FT_linear_mipmap_linear:
00264 bytes = (bytes * 4) / 3;
00265 break;
00266
00267 default:
00268 break;
00269 }
00270
00271 return bytes;
00272 }