Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

framebuffer.cpp

Go to the documentation of this file.
00001 /*
00002     toxic - A Global Illumination Renderer
00003     Copyright (C) 2003-2004 Francois Beaune
00004     Contact: http://toxicengine.sourceforge.net/
00005 
00006     This file is part of toxic.
00007 
00008     toxic is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 2 of the License, or
00011     (at your option) any later version.
00012 
00013     toxic is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016     GNU General Public License for more details.
00017 
00018     You should have received a copy of the GNU General Public License
00019     along with toxic; if not, write to the Free Software
00020     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021 */
00022 
00023 #include "framebuffer.h"    // include first
00024 
00025 #include <cmath>    // std::powf()
00026 #include <IL/il.h>
00027 #include <IL/ilu.h>
00028 #include <limits>
00029 
00030 using namespace sheep;
00031 using namespace std;
00032 using namespace toxic;
00033 
00034 Framebuffer::Framebuffer(int width, int height, Format format) :
00035     m_width(width), m_height(height),
00036     m_pixels(width * height),
00037     m_format(format)
00038 {
00039     assert(m_width > 0);
00040     assert(m_height > 0);
00041     assert(m_pixels > 0);
00042 
00043     switch(m_format) {
00044     case RGB_FLOAT_32:
00045         m_bits.m_rgb_float_32 = new pixel_rgb_float_32[m_pixels];
00046         assert(m_bits.m_rgb_float_32);  //!\todo Throw an exception if memory allocation failed.
00047         break;
00048     default:
00049         assert(!"Unknown framebuffer format.");
00050     }
00051 
00052     m_inv_width = 1.0 / m_width;
00053     m_inv_height = 1.0 / m_height;
00054     m_half_inv_width = 1.0 / (2.0 * m_width);
00055     m_half_inv_height = 1.0 / (2.0 * m_height);
00056 }
00057 
00058 Framebuffer::~Framebuffer() {
00059     switch(m_format) {
00060     case RGB_FLOAT_32:
00061         delete [] m_bits.m_rgb_float_32;
00062         break;
00063     default:
00064         assert(!"Unknown framebuffer format.");
00065     }
00066 }
00067 
00068 int Framebuffer::GetSizeInMemory() const {
00069     switch(m_format) {
00070     case RGB_FLOAT_32:
00071         return
00072             sizeof(Framebuffer) +
00073             sizeof(pixel_rgb_float_32) * m_pixels;
00074         break;
00075     default:
00076         assert(!"Unknown framebuffer format.");
00077     }
00078 
00079     return 0;   // keep the compiler happy
00080 }
00081 
00082 void Framebuffer::Clear(Color3 color /*= Color3(0.0)*/) {
00083     switch(m_format) {
00084     case RGB_FLOAT_32:
00085         {
00086             pixel_rgb_float_32 *p = m_bits.m_rgb_float_32;
00087             for(int i = 0; i < m_pixels; ++i, ++p) {
00088                 p->m_r = static_cast<float32>(color.m_r);
00089                 p->m_g = static_cast<float32>(color.m_g);
00090                 p->m_b = static_cast<float32>(color.m_b);
00091             }
00092         }
00093         break;
00094     default:
00095         assert(!"Unknown framebuffer format.");
00096     }
00097 }
00098 
00099 void Framebuffer::PlotLine(int x1, int y1, int x2, int y2, const Color3 &color) {
00100     const int dx = x2 - x1;
00101     const int ax = 2 * (dx < 0 ? -dx : dx);
00102     const int sx = dx < 0 ? -1 : 1;
00103 
00104     const int dy = y2 - y1;
00105     const int ay = 2 * (dy < 0 ? -dy : dy);
00106     const int sy = dy < 0 ? -1 : 1;
00107 
00108     if(ax > ay) {
00109         int d = ay - ax / 2;
00110 
00111         while(true) {
00112             SetPixel(x1, y1, color);
00113 
00114             if(x1 == x2)
00115                 return;
00116 
00117             if(d >= 0) {
00118                 y1 += sy;
00119                 d -= ax;
00120             }
00121 
00122             x1 += sx;
00123             d += ay;
00124         }
00125     } else {
00126         int d = ax - ay / 2;
00127 
00128         while(true) {
00129             SetPixel(x1, y1, color);
00130 
00131             if(y1 == y2)
00132                 return;
00133 
00134             if(d >= 0) {
00135                 x1 += sx;
00136                 d -= ay;
00137             }
00138 
00139             y1 += sy;
00140             d += ax;
00141         }
00142     }
00143 }
00144 
00145 void Framebuffer::Normalize() {
00146     switch(m_format) {
00147     case RGB_FLOAT_32:
00148         {
00149             Real smallest = numeric_limits<Real>::max();
00150             Real largest = -numeric_limits<Real>::max();
00151 
00152             pixel_rgb_float_32 *p = m_bits.m_rgb_float_32;
00153 
00154             for(int i = 0; i < m_pixels; ++i, ++p) {
00155                 if(p->m_r > largest) largest = p->m_r;
00156                 if(p->m_g > largest) largest = p->m_g;
00157                 if(p->m_b > largest) largest = p->m_b;
00158 
00159                 if(p->m_r < smallest) smallest = p->m_r;
00160                 if(p->m_g < smallest) smallest = p->m_g;
00161                 if(p->m_b < smallest) smallest = p->m_b;
00162             }
00163 
00164             const Real delta = largest - smallest;
00165 
00166             assert(delta >= 0.0);
00167 
00168             if(delta > 0.0) {
00169                 const Real scale = 1.0 / delta;
00170 
00171                 p = m_bits.m_rgb_float_32;
00172 
00173                 for(int i = 0; i < m_pixels; ++i, ++p) {
00174                     p->m_r = (p->m_r - smallest) * scale;
00175                     p->m_g = (p->m_g - smallest) * scale;
00176                     p->m_b = (p->m_b - smallest) * scale;
00177 
00178                     if(p->m_r < 0.0) p->m_r = 0.0;
00179                     if(p->m_g < 0.0) p->m_g = 0.0;
00180                     if(p->m_b < 0.0) p->m_b = 0.0;
00181 
00182                     if(p->m_r > 1.0) p->m_r = 1.0;
00183                     if(p->m_g > 1.0) p->m_g = 1.0;
00184                     if(p->m_b > 1.0) p->m_b = 1.0;
00185                 }
00186             } else {
00187                 p = m_bits.m_rgb_float_32;
00188 
00189                 for(int i = 0; i < m_pixels; ++i, ++p) {
00190                     p->m_r = p->m_g = p->m_b = 0.5;
00191                 }
00192             }
00193         }
00194         break;
00195     default:
00196         assert(!"Unknown framebuffer format.");
00197     }
00198 }
00199 
00200 void Framebuffer::CorrectGamma(Real target_gamma) {
00201     assert(target_gamma > 0.0);
00202 
00203     switch(m_format) {
00204     case RGB_FLOAT_32:
00205         {
00206             const float32 inv_target_gamma = static_cast<float32>(1.0 / target_gamma);
00207             pixel_rgb_float_32 *p = m_bits.m_rgb_float_32;
00208             for(int i = 0; i < m_pixels; ++i, ++p) {
00209                 p->m_r = powf(p->m_r, inv_target_gamma);
00210                 p->m_g = powf(p->m_g, inv_target_gamma);
00211                 p->m_b = powf(p->m_b, inv_target_gamma);
00212             }
00213         }
00214         break;
00215     default:
00216         assert(!"Unknown framebuffer format.");
00217     }
00218 }
00219 
00220 namespace {
00221     inline
00222     uint8 convert_float32_to_uint8(float32 x) {
00223         assert(x >= 0.0f);
00224 
00225         int n = static_cast<int>(x * 256.0f);   // discarding the fractional part
00226 
00227         if(n > 255)
00228             return 255;
00229         else return static_cast<uint8>(n);
00230     }
00231 }
00232 
00233 bool Framebuffer::WriteToDisk(const std::string &filename) const {
00234     uint8 *buffer;
00235 
00236     switch(m_format) {
00237     case RGB_FLOAT_32:
00238         {
00239             uint8 *buf = buffer = new uint8[3 * m_pixels];
00240             const pixel_rgb_float_32 *p = m_bits.m_rgb_float_32 + m_pixels - m_width;
00241             // We have to flip the image vertically because DevIL seems to
00242             // place the origin at the bottom left corner of the image.
00243             //!\todo Use ilEnable(IL_ORIGIN_SET) followed by ilOriginFunc(IL_ORIGIN_UPPER_LEFT)
00244             //! to place the origin at the upper left corner.
00245             for(int y = 0; y < m_height; ++y) {
00246                 for(int x = 0; x < m_width; ++x, ++p) {
00247                     *buf++ = convert_float32_to_uint8(p->m_r);
00248                     *buf++ = convert_float32_to_uint8(p->m_g);
00249                     *buf++ = convert_float32_to_uint8(p->m_b);
00250                 }
00251                 p -= 2 * m_width;
00252             }
00253         }
00254         break;
00255     default:
00256         assert(!"Unknown framebuffer format.");
00257     }
00258 
00259     ILuint image_id;
00260     ilGenImages(1, &image_id);
00261     ilBindImage(image_id);
00262 
00263     switch(m_format) {
00264     case RGB_FLOAT_32:
00265         ilTexImage(m_width, m_height, 1, 3, IL_RGB, IL_UNSIGNED_BYTE, buffer);
00266         break;
00267     default:
00268         assert(!"Unknown framebuffer format.");
00269     }
00270 
00271     delete [] buffer;
00272 
00273     ilEnable(IL_FILE_OVERWRITE);
00274     ilSaveImage(const_cast<ILstring>(filename.c_str()));
00275 
00276     ilDeleteImages(1, &image_id);
00277 
00278     return ilGetError() == IL_NO_ERROR;
00279 }

Generated on Tue May 11 01:31:50 2004 for toxic by doxygen 1.3.6