/[gzz]/gzz/gfx/libimagecache/ImageCache.cxx
ViewVC logotype

Diff of /gzz/gfx/libimagecache/ImageCache.cxx

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.1 by deetsay, Wed Sep 11 11:16:26 2002 UTC revision 1.2 by deetsay, Fri Sep 13 14:35:37 2002 UTC
# Line 4  namespace ImageCache { Line 4  namespace ImageCache {
4    
5  //---------------------------------------------------------------------------  //---------------------------------------------------------------------------
6    
7      void on_loader_frame_done(GdkPixbufLoader *loader, gpointer arg1,      void on_loader_area_prepared(GdkPixbufLoader *loader, gpointer arg1,
8              gpointer user_data) {              gpointer user_data) {
9    
10          ImageCache *imageCache =          ((CachedImage *)user_data)->loaderPrepared();
             (ImageCache *)gtk_object_get_user_data(GTK_OBJECT(loader));  
         imageCache->loaderImageDone((CachedURX *)user_data);  
11      }      }
12    
13  //---------------------------------------------------------------------------      void on_loader_frame_done(GdkPixbufLoader *loader, gpointer arg1,
14                gpointer user_data) {
     CachedURX::CachedURX() {  
         loader = NULL;  
     }  
   
     CachedURX::~CachedURX() {  
         if (loader != NULL) delete loader;  
     }  
15    
16      CachedLOD *CachedURX::getCachedLOD(int lod) {          ((CachedImage *)user_data)->loaderDone();
         return cachedLODs[lod];  
17      }      }
18    
19      GdkPixbuf *CachedURX::getLoaderPixbuf() {  //---------------------------------------------------------------------------
         return (loader == NULL ? NULL : gdk_pixbuf_loader_get_pixbuf(loader));  
     }  
20    
21      void CachedURX::setCachedLOD(int lod, CachedLOD *cl) {  #define START_PIXBUF_BACKGROUND_LOADER  ((GdkPixbuf *)(-1))
         if (cl == NULL) cachedLODs.erase(lod);  
         else cachedLODs[lod] = cl;  
     }  
22    
23      void CachedURX::write(char *data, int len, ImageCache *imageCache) {      CachedImage::CachedImage() {
24            loader = NULL;
25            requestedLOD = -1;
26            pixbuf = NULL;
27            pixbufLOD = -1;
28            lastSize = 0;
29            currentSize = 0;
30        }
31    
32        CachedImage::~CachedImage() {
33            closeLoader();
34            if (pixbuf != NULL) gdk_pixbuf_unref(pixbuf);
35        }
36    
37        GdkPixbuf *CachedImage::getPixbuf(int lod) {
38            if (lod < 0) lod = 0;
39            if ((pixbuf != NULL) && (lod >= pixbufLOD)) {
40                return pixbuf;
41            }
42          if (loader == NULL) {          if (loader == NULL) {
43                requestedLOD = lod;
44              loader = gdk_pixbuf_loader_new();              loader = gdk_pixbuf_loader_new();
45              gtk_object_set_user_data(GTK_OBJECT(loader), imageCache);              if (loader == NULL) return NULL;
46              gtk_signal_connect(GTK_OBJECT(loader), "frame-done",              gtk_signal_connect(GTK_OBJECT(loader), "frame-done",
47                  GTK_SIGNAL_FUNC(on_loader_frame_done), this);                  GTK_SIGNAL_FUNC(on_loader_frame_done), this);
48          }              gtk_signal_connect(GTK_OBJECT(loader), "area-prepared",
49          gdk_pixbuf_loader_write(loader, (guchar *)data, len);                  GTK_SIGNAL_FUNC(on_loader_area_prepared), this);
     }  
50    
51      void CachedURX::closeLoader() {              return START_PIXBUF_BACKGROUND_LOADER;
         if (loader != NULL) {  
             gdk_pixbuf_loader_close(loader);  
             loader = NULL;  
52          }          }
53            if (lod < requestedLOD) requestedLOD = lod;
54    
55            GdkPixbuf *pb = gdk_pixbuf_loader_get_pixbuf(loader);
56            return (pb == NULL ? pixbuf : pb);
57      }      }
58    
59  //---------------------------------------------------------------------------      int CachedImage::write(char *data, int len) {
60            if (loader == NULL) return -1;
61            gdk_pixbuf_loader_write(loader, (guchar *)data, len);
62            return 0;
63        }
64    
65      void CachedLOD::createScaled(GdkPixbuf *from, double scale) {      void CachedImage::dropLOD() {
66          int orig_width  = gdk_pixbuf_get_width (from);          closeLoader();
67          int orig_height = gdk_pixbuf_get_height(from);          if (pixbuf == NULL) return;
68    
69          int width  = (int)(scale * orig_width ); if (width  < 1) width  = 1;          int dest_width  = gdk_pixbuf_get_width (pixbuf) >> 1;
70          int height = (int)(scale * orig_height); if (height < 1) height = 1;          int dest_height = gdk_pixbuf_get_height(pixbuf) >> 1;
71            if (dest_width  == 0) dest_width  = 1;
72            if (dest_height == 0) dest_height = 1;
73    
74          pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, width, height);          GdkPixbuf *dest = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8,
75          gdk_pixbuf_ref(pixbuf);              dest_width, dest_height);
76    
77          gdk_pixbuf_scale(from, pixbuf, 0, 0, width, height, 0, 0,          gdk_pixbuf_scale(pixbuf, dest, 0, 0, dest_width, dest_height, 0, 0,
78              scale, scale, GDK_INTERP_BILINEAR);              0.5, 0.5, GDK_INTERP_BILINEAR);
79    
80          size = width*height*4;          gdk_pixbuf_unref(pixbuf);
81      }          pixbuf = dest;
82            gdk_pixbuf_ref(pixbuf);
     CachedLOD::CachedLOD(int newLOD, CachedURX *cu, gboolean final) {  
         next = NULL; prev = NULL;  
   
         lod = newLOD;  
         cachedURX = cu;  
83    
84          createScaled(cu->getLoaderPixbuf(), 1.0 / (1 << lod));          --pixbufLOD;
85    
86          fullyLoaded = final;          currentSize = dest_width * dest_height * 4;
87          cachedURX->setCachedLOD(lod, this);          gtk_object_set_user_data(GTK_OBJECT(pixbuf), (gpointer)pixbufLOD);
88      }      }
89    
90      CachedLOD::CachedLOD(int newLOD, CachedLOD *cl) {      void CachedImage::loaderPrepared() {
91          next = NULL; prev = NULL;          if ((pixbuf == NULL) || (loader == NULL)) return;
   
         cachedURX = cl->getCachedURX();  
92    
93          lod = newLOD;          GdkPixbuf *dest = gdk_pixbuf_loader_get_pixbuf(loader);
         int orig_lod = cl->getLOD();  
94    
95          int lod_dif = orig_lod - lod;          double scale = 1 << pixbufLOD;
96    
97          if (lod_dif >= 0) {          gdk_pixbuf_scale(pixbuf, dest, 0, 0,
98              createScaled(cl->pixbuf, 1.0 / (1 << lod_dif));              gdk_pixbuf_get_width(dest), gdk_pixbuf_get_height(dest),
99              fullyLoaded = cl->isFullyLoaded();              0, 0, scale, scale, GDK_INTERP_BILINEAR);
         }  
         else {  
             createScaled(cl->pixbuf, 1 << (-lod_dif));  
             fullyLoaded = false;  
         }  
         cachedURX->setCachedLOD(lod, this);  
     }  
100    
101      CachedLOD::~CachedLOD() {          gtk_object_set_user_data(GTK_OBJECT(dest), (gpointer)0);
         cachedURX->setCachedLOD(lod, NULL);  
         gdk_pixbuf_unref(pixbuf);  
102      }      }
103    
104      CachedLOD *CachedLOD::getNext() { return next; }      void CachedImage::loaderDone() {
105      CachedLOD *CachedLOD::getPrev() { return prev; }          if (loader == NULL) return;
106            if (pixbuf != NULL) gdk_pixbuf_unref(pixbuf);
107    
108      void CachedLOD::setNext(CachedLOD *cl) { next = cl; }          GdkPixbuf *src = gdk_pixbuf_loader_get_pixbuf(loader);
109      void CachedLOD::setPrev(CachedLOD *cl) { prev = cl; }          int dest_width  = gdk_pixbuf_get_width (src) >> requestedLOD;
110            int dest_height = gdk_pixbuf_get_height(src) >> requestedLOD;
111            if (dest_width  == 0) dest_width  = 1;
112            if (dest_height == 0) dest_height = 1;
113            double scale = 1.0 / (1 << requestedLOD);
114    
115      GdkPixbuf *CachedLOD::getPixbuf() { return pixbuf; }          pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8,
116                dest_width, dest_height);
117            gdk_pixbuf_ref(pixbuf);
118    
119      int CachedLOD::getSize() { return size; }          gdk_pixbuf_scale(src, pixbuf, 0, 0, dest_width, dest_height, 0, 0,
120      CachedURX *CachedLOD::getCachedURX() { return cachedURX; }              scale, scale, GDK_INTERP_BILINEAR);
121      int CachedLOD::getLOD() { return lod; }          pixbufLOD = requestedLOD;
     gboolean CachedLOD::isFullyLoaded() { return fullyLoaded; }  
122    
123      void CachedLOD::update(GdkPixbuf *from, gboolean final) {          currentSize = dest_width * dest_height * 4;
         if ((pixbuf == NULL) || fullyLoaded) return;  
124    
125          int width  = gdk_pixbuf_get_width (pixbuf);          gtk_object_set_user_data(GTK_OBJECT(pixbuf), (gpointer)pixbufLOD);
126          int height = gdk_pixbuf_get_height(pixbuf);          closeLoader();
127        }
128    
129          double scale = 1.0 / (1 << lod);      void CachedImage::closeLoader() {
130            if (loader != NULL) {
131                gdk_pixbuf_loader_close(loader);
132                loader = NULL;
133            }
134        }
135    
136          gdk_pixbuf_scale(from, pixbuf, 0, 0, width, height, 0, 0,      int CachedImage::getSizeChange() {
137              scale, scale, GDK_INTERP_BILINEAR);          int change = currentSize - lastSize;
138            lastSize = currentSize;
139            return change;
140        }
141    
142          fullyLoaded = final;      int CachedImage::getCurrentSize() {
143            return currentSize;
144      }      }
145    
146  //---------------------------------------------------------------------------  //---------------------------------------------------------------------------
147    
148      ImageCache::ImageCache() {      ImageCache::ImageCache() {
         recentlyUsedLODs = NULL;  
149          size = 0;          size = 0;
150          maxSize = 10*1024*1024;          loading = gdk_pixbuf_new(GDK_COLORSPACE_RGB, false, 8, 16, 16);
151          loaderPixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, false, 8, 16, 16);          gdk_pixbuf_ref(loading);
         gdk_pixbuf_ref(loaderPixbuf);  
152      }      }
153    
154      ImageCache::~ImageCache() {      ImageCache::~ImageCache() {
155          CachedURX *cu;          imageByUrx.clear();
156          CachedLOD *cl = recentlyUsedLODs;          urxByImage.clear();
157          CachedLOD *oldcl;  
158          while (cl != NULL) {          list<CachedImage *>::iterator iter;
             cu = cl->getCachedURX();  
             cu->closeLoader();  
             oldcl = cl;  
             cl = cl->getNext();  
             delete oldcl;  
         }  
         cachedURXs.clear();  
         gdk_pixbuf_unref(loaderPixbuf);  
     }  
159    
160      /**          for (iter  = recentlyUsedImages.begin();
161       *  Create new level of detail from another level               iter != recentlyUsedImages.end();
162       *  and put it on top of the recentlyUsedLODs list.             ++iter) {
163       */  
164      CachedLOD *ImageCache::createCachedLOD(int lod, CachedLOD *oldcl) {              delete *iter;
165          CachedLOD *cl = new CachedLOD(lod, oldcl);          }
166          size += cl->getSize();          recentlyUsedImages.clear();
167          cl->setNext(recentlyUsedLODs);          gdk_pixbuf_unref(loading);
         cl->getNext()->setPrev(cl);  
         recentlyUsedLODs = cl;  
         return cl;  
     }  
   
     /**  
      *  Create a new level of detail from a (LOD 0) pixbuf  
      *  and put it on top of the recentlyUsedLODs list.  
      */  
     CachedLOD *ImageCache::createCachedLOD(int lod, CachedURX *cu,  
             gboolean final) {  
         CachedLOD *cl = new CachedLOD(lod, cu, final);  
         size += cl->getSize();  
         cl->setNext(recentlyUsedLODs);  
         cl->getNext()->setPrev(cl);  
         recentlyUsedLODs = cl;  
         return cl;  
     }  
   
     /**  
      *  Move a level of detail to the top of the recentlyUsedLODs list.  
      */  
     void ImageCache::useCachedLOD(CachedLOD *cl) {  
         if (cl->getNext() != NULL) cl->getNext()->setPrev(cl->getPrev());  
         if (cl->getPrev() != NULL) cl->getPrev()->setNext(cl->getNext());  
         cl->setPrev(NULL);  
         cl->setNext(recentlyUsedLODs);  
         cl->getNext()->setPrev(cl);  
         recentlyUsedLODs = cl;  
168      }      }
169    
170      GdkPixbuf *ImageCache::getPixbuf(string urx, int lod) {      GdkPixbuf *ImageCache::getPixbuf(string urx, int lod) {
171          CachedLOD *wantedLOD;          CachedImage *ci = imageByUrx[urx];
172          CachedLOD *gotLOD;          if (ci == NULL) {
173          CachedURX *wantedURX = cachedURXs[urx];              ci = new CachedImage();
174                imageByUrx[urx] = ci;
175          //-----------------------------------------------------------------              urxByImage[ci] = urx;
176          // If the wanted URX was not found...          }
177          //-----------------------------------------------------------------          else recentlyUsedImages.remove(ci);
         if (wantedURX == NULL) {  
             // Start loading!  
178    
179              // backgroundLoader.startLoading(urx);     XXXXXXX          recentlyUsedImages.push_front(ci);
180    
181              return loaderPixbuf;          size += ci->getSizeChange();
         }  
         //-----------------------------------------------------------------  
         // The wanted URX was found, how about the Level of Detail?  
         //-----------------------------------------------------------------  
         wantedLOD = wantedURX->getCachedLOD(lod);  
         //-----------------------------------------------------------------  
         // If the wanted LOD was not found...  
         //-----------------------------------------------------------------  
         if (wantedLOD == NULL) {  
             // See if it can be resized from another LOD  
             // Try to find one that is bigger, and fully loaded...  
             for (int tryLOD = lod-1; tryLOD >= 0; tryLOD--) {  
                 gotLOD = wantedURX->getCachedLOD(tryLOD);  
                 if ((gotLOD != NULL) && (gotLOD->isFullyLoaded())) {  
                     wantedLOD = createCachedLOD(lod, gotLOD);  
                     return wantedLOD->getPixbuf();  
                 }  
             }  
             // There was no fully loaded one, so try the pixbufloader:  
             GdkPixbuf *pb = wantedURX->getLoaderPixbuf();  
             if (pb != NULL) {  
                 wantedLOD = createCachedLOD(lod, wantedURX, false);  
                 return wantedLOD->getPixbuf();  
             }  
             // Finally check the few next levels for smaller versions  
             // if one is found, copy it and start loading a better one  
             for (int tryLOD = lod+1; tryLOD < lod+6; tryLOD++) {  
                 gotLOD = wantedURX->getCachedLOD(tryLOD);  
                 if ((gotLOD != NULL) && (gotLOD->isFullyLoaded())) {  
                     wantedLOD = createCachedLOD(lod, gotLOD);  
182    
183                      // backgroundLoader.startLoading(urx);     XXXXXXX          GdkPixbuf *pb = ci->getPixbuf(lod);
184            if (pb == START_PIXBUF_BACKGROUND_LOADER) {
185    
186                      return wantedLOD->getPixbuf();              //backgroundLoader->startLoading(urx);
                 }  
             }  
             return loaderPixbuf;  
         }  
         //-----------------------------------------------------------------  
         // If the wanted LOD is not fully loaded:  
         //-----------------------------------------------------------------  
         if (!wantedLOD->isFullyLoaded()) {  
             // Check if it's being loaded in the pixbufloader:  
             GdkPixbuf *pb = wantedURX->getLoaderPixbuf();  
             if (pb != NULL) {  
                 wantedLOD->update(pb, false);  
                 useCachedLOD(wantedLOD);  
                 return wantedLOD->getPixbuf();  
             }  
             // See if it can be resized from another LOD:  
             for (int tryLOD = lod-1; tryLOD >= 0; tryLOD--) {  
                 gotLOD = wantedURX->getCachedLOD(tryLOD);  
                 if ((gotLOD != NULL) && (gotLOD->isFullyLoaded())) {  
                     wantedLOD->update(gotLOD->getPixbuf(), true);  
                     useCachedLOD(wantedLOD);  
                     return wantedLOD->getPixbuf();  
                 }  
             }  
             // The pixbufloader's area has not been prepared yet?  
             return loaderPixbuf;  
         }  
         //-----------------------------------------------------------------  
         // The wanted LOD was fully loaded:  
         //-----------------------------------------------------------------  
         useCachedLOD(wantedLOD);        // move to top of recentlyUsedLODs  
         return wantedLOD->getPixbuf();  
         //-----------------------------------------------------------------  
     }  
187    
188      int ImageCache::getWidth(string urx, int lod) {              pb = ci->getPixbuf(lod);
189          return gdk_pixbuf_get_width(getPixbuf(urx,lod));          }
190            return (pb == NULL ? loading : pb);
191      }      }
192    
193      int ImageCache::getHeight(string urx, int lod) {      int ImageCache::write(string urx, char *data, int len) {
194          return gdk_pixbuf_get_height(getPixbuf(urx,lod));          CachedImage *ci = imageByUrx[urx];
195            return (ci == NULL ? -1 : ci->write(data, len));
196      }      }
197    
198      int *ImageCache::getPixels(string urx, int lod) {      int ImageCache::cropToSize(int maxSize) {
199          return (int *)gdk_pixbuf_get_pixels(getPixbuf(urx,lod));          CachedImage *ci;
200      }          int sizeChange;
201            while ((size >= maxSize) && (!recentlyUsedImages.empty())) {
202                ci = recentlyUsedImages.back();
203                recentlyUsedImages.pop_back();
204    
205      void ImageCache::write(string urx, char *data, int len) {              ci->dropLOD();
         CachedURX *wantedURX = cachedURXs[urx];  
         if (wantedURX == NULL) {  
             wantedURX = new CachedURX();  
             cachedURXs[urx] = wantedURX;  
         }  
         wantedURX->write(data, len, this);  
     }  
206    
207      void ImageCache::loaderImageDone(CachedURX *cu) {              sizeChange = ci->getSizeChange();
208          CachedLOD *cl = cu->getCachedLOD(0);              if (sizeChange == 0) {
209          if (cl == NULL) {                  string urx = urxByImage[ci];
210              cl = createCachedLOD(0, cu, true);                  urxByImage.erase(ci);
211          }                  imageByUrx.erase(urx);
212          else {                  size -= ci->getCurrentSize();
213              cl->update(cu->getLoaderPixbuf(), true);                  delete ci;
214              useCachedLOD(cl);              }
215                else {
216                    size += sizeChange;
217                    recentlyUsedImages.push_front(ci);
218                }
219          }          }
220          cu->closeLoader();          return size;
221      }      }
222    
223  //---------------------------------------------------------------------------  //---------------------------------------------------------------------------

Legend:
Removed from v.1.1  
changed lines
  Added in v.1.2

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26