Blender V2.61 - r43446

image.cpp

Go to the documentation of this file.
00001 /*
00002  * Copyright 2011, Blender Foundation.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 #include "device.h"
00020 #include "image.h"
00021 #include "scene.h"
00022 
00023 #include "util_foreach.h"
00024 #include "util_image.h"
00025 #include "util_path.h"
00026 #include "util_progress.h"
00027 
00028 #ifdef WITH_OSL
00029 #include <OSL/oslexec.h>
00030 #endif
00031 
00032 CCL_NAMESPACE_BEGIN
00033 
00034 ImageManager::ImageManager()
00035 {
00036     need_update = true;
00037     osl_texture_system = NULL;
00038 }
00039 
00040 ImageManager::~ImageManager()
00041 {
00042     for(size_t slot = 0; slot < images.size(); slot++) {
00043         assert(!images[slot]);
00044     }
00045 }
00046 
00047 void ImageManager::set_osl_texture_system(void *texture_system)
00048 {
00049     osl_texture_system = texture_system;
00050 }
00051 
00052 int ImageManager::add_image(const string& filename)
00053 {
00054     Image *img;
00055     size_t slot;
00056 
00057     /* find existing image */
00058     for(slot = 0; slot < images.size(); slot++) {
00059         if(images[slot] && images[slot]->filename == filename) {
00060             images[slot]->users++;
00061             return slot;
00062         }
00063     }
00064 
00065     /* find free slot */
00066     for(slot = 0; slot < images.size(); slot++)
00067         if(!images[slot])
00068             break;
00069     
00070     if(slot == images.size()) {
00071         /* max images limit reached */
00072         if(images.size() == TEX_IMAGE_MAX)
00073             return -1;
00074 
00075         images.resize(images.size() + 1);
00076     }
00077     
00078     /* add new image */
00079     img = new Image();
00080     img->filename = filename;
00081     img->need_load = true;
00082     img->users = 1;
00083 
00084     images[slot] = img;
00085     need_update = true;
00086 
00087     return slot;
00088 }
00089 
00090 void ImageManager::remove_image(const string& filename)
00091 {
00092     size_t slot;
00093 
00094     for(slot = 0; slot < images.size(); slot++)
00095         if(images[slot] && images[slot]->filename == filename)
00096             break;
00097     
00098     if(slot == images.size())
00099         return;
00100 
00101     assert(images[slot]);
00102 
00103     /* decrement user count */
00104     images[slot]->users--;
00105     assert(images[slot]->users >= 0);
00106     
00107     /* don't remove immediately, rather do it all together later on. one of
00108        the reasons for this is that on shader changes we add and remove nodes
00109        that use them, but we do not want to reload the image all the time. */
00110     if(images[slot]->users == 0)
00111         need_update = true;
00112 }
00113 
00114 bool ImageManager::file_load_image(Image *img, device_vector<uchar4>& tex_img)
00115 {
00116     if(img->filename == "")
00117         return false;
00118 
00119     /* load image from file through OIIO */
00120     ImageInput *in = ImageInput::create(img->filename);
00121 
00122     if(!in)
00123         return false;
00124 
00125     ImageSpec spec;
00126 
00127     if(!in->open(img->filename, spec)) {
00128         delete in;
00129         return false;
00130     }
00131 
00132     /* we only handle certain number of components */
00133     int width = spec.width;
00134     int height = spec.height;
00135     int components = spec.nchannels;
00136 
00137     if(!(components == 1 || components == 3 || components == 4)) {
00138         in->close();
00139         delete in;
00140         return false;
00141     }
00142 
00143     /* read RGBA pixels */
00144     uchar *pixels = (uchar*)tex_img.resize(width, height);
00145     int scanlinesize = width*components*sizeof(uchar);
00146 
00147     in->read_image(TypeDesc::UINT8,
00148         (uchar*)pixels + (height-1)*scanlinesize,
00149         AutoStride,
00150         -scanlinesize,
00151         AutoStride);
00152 
00153     in->close();
00154     delete in;
00155 
00156     if(components == 3) {
00157         for(int i = width*height-1; i >= 0; i--) {
00158             pixels[i*4+3] = 255;
00159             pixels[i*4+2] = pixels[i*3+2];
00160             pixels[i*4+1] = pixels[i*3+1];
00161             pixels[i*4+0] = pixels[i*3+0];
00162         }
00163     }
00164     else if(components == 1) {
00165         for(int i = width*height-1; i >= 0; i--) {
00166             pixels[i*4+3] = 255;
00167             pixels[i*4+2] = pixels[i];
00168             pixels[i*4+1] = pixels[i];
00169             pixels[i*4+0] = pixels[i];
00170         }
00171     }
00172 
00173     return true;
00174 }
00175 
00176 void ImageManager::device_load_image(Device *device, DeviceScene *dscene, int slot)
00177 {
00178     if(osl_texture_system)
00179         return;
00180 
00181     Image *img = images[slot];
00182     device_vector<uchar4>& tex_img = dscene->tex_image[slot];
00183 
00184     if(tex_img.device_pointer)
00185         device->tex_free(tex_img);
00186 
00187     if(!file_load_image(img, tex_img)) {
00188         /* on failure to load, we set a 1x1 pixels black image */
00189         uchar *pixels = (uchar*)tex_img.resize(1, 1);
00190 
00191         pixels[0] = 0;
00192         pixels[1] = 0;
00193         pixels[2] = 0;
00194         pixels[3] = 0;
00195     }
00196 
00197     string name;
00198 
00199     if(slot >= 10) name = string_printf("__tex_image_0%d", slot);
00200     else name = string_printf("__tex_image_00%d", slot);
00201 
00202     device->tex_alloc(name.c_str(), tex_img, true, true);
00203 }
00204 
00205 void ImageManager::device_free_image(Device *device, DeviceScene *dscene, int slot)
00206 {
00207     if(images[slot]) {
00208         if(osl_texture_system) {
00209 #ifdef WITH_OSL
00210             ustring filename(images[slot]->filename);
00211             ((OSL::TextureSystem*)osl_texture_system)->invalidate(filename);
00212 #endif
00213         }
00214         else {
00215             device->tex_free(dscene->tex_image[slot]);
00216             dscene->tex_image[slot].clear();
00217         }
00218 
00219         delete images[slot];
00220         images[slot] = NULL;
00221     }
00222 }
00223 
00224 void ImageManager::device_update(Device *device, DeviceScene *dscene, Progress& progress)
00225 {
00226     if(!need_update)
00227         return;
00228 
00229     for(size_t slot = 0; slot < images.size(); slot++) {
00230         if(images[slot]) {
00231             if(images[slot]->users == 0) {
00232                 device_free_image(device, dscene, slot);
00233             }
00234             else if(images[slot]->need_load) {
00235                 string name = path_filename(images[slot]->filename);
00236                 progress.set_status("Updating Images", "Loading " + name);
00237                 device_load_image(device, dscene, slot);
00238                 images[slot]->need_load = false;
00239             }
00240 
00241             if(progress.get_cancel()) return;
00242         }
00243     }
00244 
00245     need_update = false;
00246 }
00247 
00248 void ImageManager::device_free(Device *device, DeviceScene *dscene)
00249 {
00250     for(size_t slot = 0; slot < images.size(); slot++)
00251         device_free_image(device, dscene, slot);
00252 
00253     images.clear();
00254 }
00255 
00256 CCL_NAMESPACE_END
00257