Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Problems.GaussianProcessTuning/ILNumerics.2.14.4735.573/Drawing/Labeling/ILTextureStorage.cs @ 12448

Last change on this file since 12448 was 9102, checked in by gkronber, 12 years ago

#1967: ILNumerics source for experimentation

File size: 15.3 KB
Line 
1///
2///    This file is part of ILNumerics Community Edition.
3///
4///    ILNumerics Community Edition - high performance computing for applications.
5///    Copyright (C) 2006 - 2012 Haymo Kutschbach, http://ilnumerics.net
6///
7///    ILNumerics Community Edition is free software: you can redistribute it and/or modify
8///    it under the terms of the GNU General Public License version 3 as published by
9///    the Free Software Foundation.
10///
11///    ILNumerics Community Edition is distributed in the hope that it will be useful,
12///    but WITHOUT ANY WARRANTY; without even the implied warranty of
13///    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14///    GNU General Public License for more details.
15///
16///    You should have received a copy of the GNU General Public License
17///    along with ILNumerics Community Edition. See the file License.txt in the root
18///    of your distribution package. If not, see <http://www.gnu.org/licenses/>.
19///
20///    In addition this software uses the following components and/or licenses:
21///
22///    =================================================================================
23///    The Open Toolkit Library License
24///   
25///    Copyright (c) 2006 - 2009 the Open Toolkit library.
26///   
27///    Permission is hereby granted, free of charge, to any person obtaining a copy
28///    of this software and associated documentation files (the "Software"), to deal
29///    in the Software without restriction, including without limitation the rights to
30///    use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
31///    the Software, and to permit persons to whom the Software is furnished to do
32///    so, subject to the following conditions:
33///
34///    The above copyright notice and this permission notice shall be included in all
35///    copies or substantial portions of the Software.
36///
37///    =================================================================================
38///   
39
40using System;
41using System.Collections.Generic;
42using System.Text;
43using System.Drawing;
44using System.Drawing.Imaging;
45
46namespace ILNumerics.Drawing.Labeling {
47    /// <summary>
48    /// The class provides texture storage for a single class of texures (e.g. one font)
49    /// </summary>
50    /// <remarks>The texture items are stored in a single texture sheet
51    /// and organized via a simple binary tree.</remarks>
52    public abstract class ILTextureStorage {
53
54        #region attributes / properties
55        protected Dictionary<string,ILTextureData> m_items;
56        protected int m_height;
57        protected int m_width;
58        protected int m_textureId;
59        /// <summary>
60        ///  cache, which texture has been bound at last
61        /// </summary>
62        protected bool m_disposed = true;
63        protected static int[] m_tmpData;
64        protected Node m_root;
65
66        /// <summary>
67        /// overall height of the internal texture sheet
68        /// </summary>
69        public int Height {
70            get { return m_height; }
71        }
72
73        /// <summary>
74        /// current width of the internal texture sheet
75        /// </summary>
76        public int Width {
77            get { return m_width; }
78        }
79        /// <summary>
80        /// Key used to identify the texure in the graphic system
81        /// </summary>
82        public int TextureID {
83            get {
84                return m_textureId;
85            }
86        }
87        #endregion
88
89        #region constructor
90        /// <summary>
91        /// construct new storage
92        /// </summary>
93        /// <param name="height">absolute height (permanent)</param>
94        /// <param name="width">absolute width (permanent)</param>
95        /// <remarks>Suggested size parameter will be increased to the next power of two.</remarks>
96        public ILTextureStorage(int height, int width) {
97            m_items = new Dictionary<string,ILTextureData>();
98            if (width <= 0 || height <= 0)
99                throw new ArgumentOutOfRangeException("width & height ", width, "Must be greater than zero.");
100            // make size a power of 2
101            m_height = (int)Math.Pow(2,Math.Ceiling(Math.Log(height,2)));
102            m_width = (int)Math.Pow(2,Math.Ceiling(Math.Log(width,2)));
103            if (m_height > 1024) m_height = 1024; // limit to 1024 for compatibility reasons
104            if (m_width > 1024) m_width = 1024;
105            m_root = new Node();
106            m_root.Rect = new Rectangle(0,0,m_width,m_height);
107            InitTexture();
108            m_disposed = false;
109            //System.Diagnostics.Debug.WriteLine("ILTextureStorage (constr) ThreadID:"
110            //    + System.Threading.Thread.CurrentThread.ManagedThreadId);
111        }
112        #endregion
113
114        #region public / abstract interface
115        /// <summary>
116        /// fetch texture item from storage
117        /// </summary>
118        /// <param name="key"></param>
119        /// <returns></returns>
120        public virtual ILTextureData Get (string key) {
121            ILTextureData ret = null;
122            if (!m_items.TryGetValue(key,out ret)) {
123                return null; //throw new ArgumentException("no texture item has been found for key: " + key);
124            }
125            return ret;
126        }
127        /// <summary>
128        /// try to fetch item by key
129        /// </summary>
130        /// <param name="key">unique key</param>
131        /// <param name="item">[output] item found</param>
132        /// <returns>true: item was found, false otherwise</returns>
133        public virtual bool TryGetTextureItem(string key, out ILTextureData item) {
134            if (m_items.ContainsKey(key)) {
135                item = m_items[key];
136                return true;
137            }
138            item = null;
139            return false;
140        }
141        /// <summary>
142        /// test, if a key exists in the texture storage
143        /// </summary>
144        /// <param name="key">unique key to be tested for</param>
145        /// <returns>true if a texture item associated with that key exists, false otherwise</returns>
146        public bool Exists (string key) {
147            return m_items.ContainsKey(key);
148        }
149        /// <summary>
150        /// store bitmap into texture sheet
151        /// </summary>
152        /// <param name="key">unique key for item</param>
153        /// <param name="data">item bitmap data</param>
154        /// <param name="rect">rectangle used in data bitmap</param>
155        /// <returns>true on success</returns>
156        public virtual bool Store (string key, Bitmap data, Rectangle rect) {
157            if (data.Height > m_height || data.Width > m_width)
158                throw new ArgumentException("texture size is too large for this packer!");
159            // add to packer 
160            ILTextureData item;
161            if (m_items.TryGetValue(key,out item)) {
162                item.Height = data.Height;
163                item.Width = data.Width;
164                // todo: remove item from packer & from texture sheet (somehow...[?])
165            } else {
166                item = new ILTextureData(rect.Height,rect.Width);
167                m_items.Add(key, item);
168            }
169            Node node = m_root.Insert(item);
170            if (node == null)
171                return false;
172            item.TextureRectangle = RectangleF.FromLTRB( (0.5f + node.Rect.Left) / m_width,
173                                                    (0.5f + node.Rect.Top) / m_height,
174                                                    (node.Rect.Right - 0.5f) / m_width,
175                                                    (node.Rect.Bottom - 0.5f) /m_height);
176            Store(data,rect, node.Rect);
177            return true;
178        }
179        /// <summary>
180        /// store bitmap into texture sheet
181        /// </summary>
182        /// <param name="key">unique key for item</param>
183        /// <param name="data">item bitmap data</param>
184        /// <param name="bmpRect">used rectangle in data bitmap</param>
185        public virtual bool Store (string key, Bitmap data, RectangleF bmpRect) {
186            if (bmpRect.Height > m_height || bmpRect.Width > m_width)
187                throw new ArgumentException("texture size is too large for this packer!");
188            // add to packer 
189            ILTextureData item; Node node;
190            Rectangle itemRect = Rectangle.Ceiling(bmpRect);
191            if (m_items.TryGetValue(key,out item)) {
192                item.Height = itemRect.Height;
193                item.Width = itemRect.Width;
194                // todo: remove item from packer & from texture sheet (somehow...[?])
195                node = m_root.Insert(item);
196                if (node == null)
197                    return false;
198            } else {
199                item = new ILTextureData(itemRect.Height, itemRect.Width);
200                node = m_root.Insert(item);
201                if (node == null)
202                    return false;
203                m_items.Add(key, item);
204            }
205            item.TextureRectangle = RectangleF.FromLTRB( (0.5f + node.Rect.Left) / m_width,
206                                                    (0.5f + node.Rect.Top) / m_height,
207                                                    (node.Rect.Right - 0.5f) / m_width,
208                                                    (node.Rect.Bottom - 0.5f) /m_height);
209            //item.TextureRectangle = RectangleF.FromLTRB( (0f + node.Rect.Left) / m_width,
210            //                                        (0f + node.Rect.Top) / m_height,
211            //                                        (node.Rect.Right - 0f) / m_width,
212            //                                        (node.Rect.Bottom - 0f) /m_height);           
213            Store(data,bmpRect,node.Rect);
214            return true;
215        }
216        /// <summary>
217        /// initialize texture sheet
218        /// </summary>
219        protected abstract void InitTexture();
220        /// <summary>
221        /// store item in texture sheet in GL
222        /// </summary>
223        /// <param name="data">new item bitmap data</param>
224        /// <param name="location">area in bitmap data to be stored</param>
225        /// <param name="rect">rectangle specifying area to store the data into,
226        /// texture coords: range from 0...1.0</param>
227        protected abstract void Store(Bitmap data, RectangleF location, RectangleF rect);
228        /// <summary>
229        /// select the texture storage as current in the GL
230        /// </summary>
231        /// <remarks>Calling this function before an storage / render operation is
232        /// obligatory in specific rendering machines (e.g. OpenGL). For GL's, where
233        /// it is not neccessary, the implementation must ignore any calls to this function.</remarks>
234        public abstract void MakeCurrent();
235        /// <summary>
236        /// Dispose off any texture storage's ressources
237        /// </summary>
238        public void Dispose() {
239            GC.SuppressFinalize(this);
240            Dispose(true);
241        }
242        /// <summary>
243        /// Dispose off manually
244        /// </summary>
245        /// <param name="manual"></param>
246        /// <remarks>The true disposing is done in the concrete implementation.</remarks>
247        public virtual void Dispose(bool manual) {
248            if (!m_disposed) {
249                if (manual) {
250                    // free texture from GL
251                }
252                m_disposed = true;
253            }
254        }
255        /// <summary>
256        /// Finalizer, disposing ressources
257        /// </summary>
258        ~ILTextureStorage() {
259            Dispose(false);
260        }
261
262        #endregion
263
264        #region helper functions
265
266        #endregion
267
268        #region Node - binary tree
269        /// <summary>
270        /// class representing a binary tree, used to manage the items on the texture sheet
271        /// </summary>
272        /// <remarks>This code is a slightly modified version of the OpenTK.Utilities framework
273        /// TextPrinter/TextureStorage classes. See http://opentk.com for details.</remarks>
274        protected class Node
275        {
276            public Node()
277            {
278            }
279
280            Node left, right;
281            Rectangle rect;
282            int use_count;
283
284            public Rectangle Rect { get { return rect; } set { rect = value; } }
285            public Node Left { get { return left; } set { left = value; } }
286            public Node Right { get { return right; } set { right = value; } }
287
288            #region --- Constructor ---
289
290            public bool Leaf
291            {
292                get { return left == null && right == null; }
293            }
294
295            #endregion
296
297            #region public Node Insert(ILTextureData item)
298
299            public Node Insert(ILTextureData item)
300            {
301                if (!this.Leaf)
302                {
303                    // Recurse towards left child, and if that fails, towards the right.
304                    Node new_node = left.Insert(item);
305                    return new_node ?? right.Insert(item);
306                }
307                else
308                {
309                    // We have recursed to a leaf.
310
311                    // If it is not empty go back.
312                    if (use_count != 0)
313                        return null;
314
315                    // If this leaf is too small go back.
316                    if (rect.Width < item.Width || rect.Height < item.Height)
317                        return null;
318
319                    // If this leaf is the right size, insert here.
320                    if (rect.Width == item.Width && rect.Height == item.Height)
321                    {
322                        use_count = 1;
323                        return this;
324                    }
325
326                    // This leaf is too large, split it up. We'll decide which way to split
327                    // by checking the width and height difference between this rectangle and
328                    // out item's bounding box. If the width difference is larger, we'll split
329                    // horizontaly, else verticaly.
330                    left = new Node();
331                    right = new Node();
332
333                    int dw = this.rect.Width - item.Width + 1;
334                    int dh = this.rect.Height - item.Height + 1;
335
336                    if (dw > dh)
337                    {
338                        left.rect = new Rectangle(rect.Left, rect.Top, item.Width, rect.Height);
339                        right.rect = new Rectangle(rect.Left + item.Width, rect.Top, rect.Width - item.Width, rect.Height);
340                    }
341                    else
342                    {
343                        left.rect = new Rectangle(rect.Left, rect.Top, rect.Width, item.Height);
344                        right.rect = new Rectangle(rect.Left, rect.Top + item.Height, rect.Width, rect.Height - item.Height);
345                    }
346
347                    return left.Insert(item);
348                }
349            }
350
351            #endregion
352
353            #region public void Clear()
354           
355            public void Clear()
356            {
357                if (left != null)
358                    left.Clear();
359                if (right != null)
360                    right.Clear();
361
362                left = right = null;
363            }
364
365            #endregion
366        }
367
368        #endregion
369
370    }
371}
Note: See TracBrowser for help on using the repository browser.