Exemplo n.º 1
0
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();
}
Exemplo n.º 2
0
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));
            };
        }
    }