GLTexture* TexturesMap::capture (const LoadImageCallback& loader, const std::string& name) { g_debug("textures capture: '%s'\n", name.c_str()); return m_qtextures.capture(TextureKey(loader, name)).get(); }
void TexturesMap::release (GLTexture* texture) { g_debug("textures release: '%s'\n", texture->getName().c_str()); m_qtextures.release(TextureKey(texture->load, texture->getName())); }
void TextureManager::CheckUpdate() { // The images or their lenses have changed. // Find what size we should have the textures. // Note that one image changing does affect the rest, if an image suddenly // takes up more space, the others should take up less. unsigned int num_images = m_pano->getNrOfImages(); if (num_images == 0) { textures.clear(); return; } // if we are doing photometric correction, and someone changed the output // exposure, all of our images are at the wrong exposure. if (photometric_correct && view_state->RequireRecalculatePhotometric()) { textures.clear(); } HuginBase::PanoramaOptions *dest_img = view_state->GetOptions(); // Recalculuate the ideal image density if required // TODO tidy up once it works. DEBUG_INFO("Updating texture sizes."); // find the total of fields of view of the images, in degrees squared // we assume each image has the same density across all it's pixels double total_fov = 0.0; for (unsigned int image_index = 0; image_index < num_images; image_index++) { HuginBase::SrcPanoImage *src = view_state->GetSrcImage(image_index); double aspect = double(src->getSize().height()) / double(src->getSize().width()); total_fov += src->getHFOV() * aspect; }; // now find the ideal density texel_density = double(GetMaxTotalTexels()) / total_fov; // now recalculate the best image sizes // The actual texture size is the biggest one possible withouth scaling the // image up in any direction. We only specifiy mipmap levels we can fit in // a given amount of texture memory, while respecting the image's FOV. int texels_used = 0; double ideal_texels_used = 0.0; for (unsigned int image_index = 0; image_index < num_images; image_index++) { // find this texture // if it has not been created before, it will be created now. std::map<TextureKey, TextureInfo>::iterator it; HuginBase::SrcPanoImage *img_p = view_state->GetSrcImage(image_index); TextureKey key(img_p, &photometric_correct); it = textures.find(key); TextureInfo *texinfo; /* This section would allow us to reuse textures generated when we want * to change the size. It is not used as it causes segmentation faults * under Ubuntu 8.04's "ati" graphics driver. */ #if 0 if (it == textures.end()) { // We haven't seen this image before. // Find a size for it and make its texture. // store the power that 2 is raised to, not the actual size unsigned int max_tex_width_p = int(log2(img_p->getSize().width())), max_tex_height_p = int(log2(img_p->getSize().height())); // check this is hardware supported. { unsigned int biggest = GetMaxTextureSizePower(); if (biggest < max_tex_width_p) max_tex_width_p = biggest; if (biggest < max_tex_height_p) max_tex_height_p = biggest; } std::cout << "Texture size for image " << image_index << " is " << (1 << max_tex_width_p) << " by " << (1 << max_tex_height_p) << "\n"; // create a new texinfo and store the texture details. std::cout << "About to create new TextureInfo for " << img_p->getFilename() << ".\n"; std::pair<std::map<TextureKey, TextureInfo>::iterator, bool> ins; ins = textures.insert(std::pair<TextureKey, TextureInfo> (TextureKey(img_p, &photometric_correct), // the key is used to identify the image with (or without) // photometric correction parameters. TextureInfo(max_tex_width_p, max_tex_height_p) )); texinfo = &((ins.first)->second); } else { texinfo = &(it->second); } // find the highest mipmap we want to use. double hfov = img_p->getHFOV(), aspect = double (texinfo->height) / double (texinfo->width), ideal_texels = texel_density * hfov * aspect, // we would like a mipmap with this size: ideal_tex_width = sqrt(ideal_texels / aspect), ideal_tex_height = aspect * ideal_tex_width; // Ideally this mipmap would bring us up to this many texels ideal_texels_used += ideal_texels; std::cout << "Ideal mip size: " << ideal_tex_width << " by " << ideal_tex_height << "\n"; // Find the smallest mipmap level that is at least this size. int max_mip_level = (texinfo->width_p > texinfo->height_p) ? texinfo->width_p : texinfo->height_p; int mip_level = max_mip_level - ceil((ideal_tex_width > ideal_tex_height) ? log2(ideal_tex_width) : log2(ideal_tex_height)); // move to the next mipmap level if we are over budget. if ((texels_used + (1 << (texinfo->width_p + texinfo->height_p - mip_level * 2))) > ideal_texels_used) { // scale down mip_level ++; } // don't allow any mipmaps smaller than the 1 by 1 pixel one. if (mip_level > max_mip_level) mip_level = max_mip_level; // don't allow any mipmaps with a negative level of detail (scales up) if (mip_level < 0) mip_level = 0; // find the size of this level int mip_width_p = texinfo->width_p - mip_level, mip_height_p = texinfo->height_p - mip_level; // check if we have scaled down to a single line, and make sure we // limit the line's width to 1 pixel. if (mip_width_p < 0) mip_width_p = 0; if (mip_height_p < 0) mip_height_p = 0; // now count these texels as used- we are ignoring the smaller mip // levels, they add 1/3 on to the size. texels_used += 1 << (mip_width_p + mip_height_p); std::cout << "biggest mipmap of image " << image_index << " is " << (1 << mip_width_p) << " by " << (1 << mip_height_p) << " (level " << mip_level <<").\n"; std::cout << "Ideal texels used " << int(ideal_texels_used) << ", actually used " << texels_used << ".\n\n"; if (texinfo->min_lod != mip_level) { // maximum level required changed. if (texinfo->min_lod > mip_level) { // generate more levels texinfo->DefineLevels(mip_level, (texinfo->min_lod > max_mip_level) ? max_mip_level : texinfo->min_lod - 1, photometric_correct, dest_img, view_state->GetSrcImage(image_index)); } texinfo->SetMaxLevel(mip_level); texinfo->min_lod = mip_level; } } #endif /* Instead of the above section, replace the whole texture when appropriate: */ // Find a size for it double hfov = img_p->getHFOV(), aspect = double (img_p->getSize().height()) / double (img_p->getSize().width()), ideal_texels = texel_density * hfov * aspect, // we would like a texture this size: ideal_tex_width = sqrt(ideal_texels / aspect), ideal_tex_height = aspect * ideal_tex_width; // shrink if bigger than the original, avoids scaling up excessively. if (ideal_tex_width > img_p->getSize().width()) ideal_tex_width = img_p->getSize().width(); if (ideal_tex_height > img_p->getSize().height()) ideal_tex_height = img_p->getSize().height(); // we will need to round up/down to a power of two // round up first, then shrink if over budget. // store the power that 2 is raised to, not the actual size unsigned int tex_width_p = int(log2(ideal_tex_width)) + 1, tex_height_p = int(log2(ideal_tex_height)) + 1; // check this is hardware supported. { unsigned int biggest = GetMaxTextureSizePower(); if (biggest < tex_width_p) tex_width_p = biggest; if (biggest < tex_height_p) tex_height_p = biggest; } // check if this is over budget. ideal_texels_used += ideal_texels; // while the texture is over budget, shrink it while ( (texels_used + (1 << (tex_width_p + tex_height_p))) > ideal_texels_used) { // smaller aspect means the texture is wider. if ((double) (1 << tex_height_p) / (double) (1 << tex_width_p) < aspect) { tex_width_p--; } else { tex_height_p--; } } // we have a nice size texels_used += 1 << (tex_width_p + tex_height_p); if ( it == textures.end() || (it->second).width_p != tex_width_p || (it->second).height_p != tex_height_p) { // Either: 1. We haven't seen this image before // or: 2. Our texture for this is image is the wrong size // ...therefore we make a new one the right size: // // remove duplicate key if exists TextureKey checkKey (img_p, &photometric_correct); if (textures.find(checkKey) != textures.end()) { // Already exists in map, remove it first before adding a new one textures.erase(checkKey); } std::pair<std::map<TextureKey, TextureInfo>::iterator, bool> ins; ins = textures.insert(std::pair<TextureKey, TextureInfo> (TextureKey(img_p, &photometric_correct), // the key is used to identify the image with (or without) // photometric correction parameters. TextureInfo(view_state, tex_width_p, tex_height_p) )); // create and upload the texture image texinfo = &((ins.first)->second); texinfo->DefineLevels(0, // minimum mip level // maximum mip level tex_width_p > tex_height_p ? tex_width_p : tex_height_p, photometric_correct, *dest_img, *view_state->GetSrcImage(image_index)); texinfo->DefineMaskTexture(*view_state->GetSrcImage(image_index)); } else { if(view_state->RequireRecalculateMasks(image_index)) { //mask for this image has changed, also update only mask (*it).second.UpdateMask(*view_state->GetSrcImage(image_index)); }; } }