Blender V2.61 - r43446
|
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