Blender  V2.59
GPC_Canvas.cpp
Go to the documentation of this file.
00001 /*
00002  * $Id: GPC_Canvas.cpp 35170 2011-02-25 13:35:11Z jesterking $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00021  * All rights reserved.
00022  *
00023  * The Original Code is: all of this file.
00024  *
00025  * Contributor(s): none yet.
00026  *
00027  * ***** END GPL LICENSE BLOCK *****
00028  */
00029 
00035 #ifndef NOPNG
00036 #ifdef WIN32
00037 #include "png.h"
00038 #else
00039 #include <png.h>
00040 #endif
00041 #endif // NOPNG
00042 
00043 #include "RAS_IPolygonMaterial.h"
00044 #include "GPC_Canvas.h"
00045 
00046 GPC_Canvas::TBannerId GPC_Canvas::s_bannerId = 0;
00047 
00048 
00049 GPC_Canvas::GPC_Canvas(
00050         int width,
00051         int height
00052 ) : 
00053         m_width(width),
00054         m_height(height),
00055         m_bannersEnabled(false)
00056 {
00057 }
00058 
00059 
00060 GPC_Canvas::~GPC_Canvas()
00061 {
00062         DisposeAllBanners();
00063 }
00064 
00065 
00066 //  void GPC_Canvas::InitPostRenderingContext(void)
00067 //  {
00068 //      glViewport(0, 0, m_width, m_height);
00069 //      glMatrixMode(GL_PROJECTION);
00070 //      glLoadIdentity();
00071         
00072 //      glOrtho(-2.0, 2.0, -2.0, 2.0, -20.0, 20.0);
00073 
00074 //      glMatrixMode(GL_MODELVIEW);
00075 //      glLoadIdentity();
00076 
00077 //      glEnable(GL_DEPTH_TEST);
00078 
00079 //      glDepthFunc(GL_LESS);
00080 
00081 //      glShadeModel(GL_SMOOTH);
00082 //  }
00083 
00084 void GPC_Canvas::Resize(int width, int height)
00085 {
00086         m_width = width;
00087         m_height = height;
00088 }
00089 
00090 void GPC_Canvas::EndFrame()
00091 {
00092         if (m_bannersEnabled)
00093                 DrawAllBanners();       
00094 }
00095 
00096 
00097 void GPC_Canvas::ClearColor(float r, float g, float b, float a)
00098 {
00099         ::glClearColor(r,g,b,a);
00100 }
00101 
00102 void GPC_Canvas::SetViewPort(int x1, int y1, int x2, int y2)
00103 {
00104                 /*      x1 and y1 are the min pixel coordinate (e.g. 0)
00105                         x2 and y2 are the max pixel coordinate
00106                         the width,height is calculated including both pixels
00107                         therefore: max - min + 1
00108                 */
00109                 
00110                 /* XXX, nasty, this needs to go somewhere else,
00111                  * but where... definitly need to clean up this
00112                  * whole canvas/rendertools mess.
00113                  */
00114         glEnable(GL_SCISSOR_TEST);
00115 
00116         glViewport(x1,y1,x2-x1 + 1,y2-y1 + 1);
00117         glScissor(x1,y1,x2-x1 + 1,y2-y1 + 1);
00118 };
00119 
00120 
00121 void GPC_Canvas::ClearBuffer(
00122         int type
00123 ){
00124 
00125         int ogltype = 0;
00126         if (type & RAS_ICanvas::COLOR_BUFFER )
00127                 ogltype |= GL_COLOR_BUFFER_BIT;
00128         if (type & RAS_ICanvas::DEPTH_BUFFER )
00129                 ogltype |= GL_DEPTH_BUFFER_BIT;
00130 
00131         ::glClear(ogltype);
00132 }
00133 
00134 
00135 GPC_Canvas::TBannerId GPC_Canvas::AddBanner(
00136         unsigned int bannerWidth, unsigned int bannerHeight,
00137         unsigned int imageWidth, unsigned int imageHeight,
00138         unsigned char* imageData, 
00139         TBannerAlignment alignment, bool enabled)
00140 {
00141         TBannerData banner;
00142 
00143         banner.alignment = alignment;
00144         banner.enabled = enabled;
00145         banner.displayWidth = bannerWidth;
00146         banner.displayHeight = bannerHeight;
00147         banner.imageWidth = imageWidth;
00148         banner.imageHeight = imageHeight;
00149         unsigned int bannerDataSize = imageWidth*imageHeight*4;
00150         banner.imageData = new unsigned char [bannerDataSize];
00151         ::memcpy(banner.imageData, imageData, bannerDataSize);
00152         banner.textureName = 0;
00153 
00154         m_banners.insert(TBannerMap::value_type(++s_bannerId, banner));
00155         return s_bannerId;
00156 }
00157 
00158 
00159 void GPC_Canvas::DisposeBanner(TBannerId id)
00160 {
00161         TBannerMap::iterator it = m_banners.find(id);
00162         if (it != m_banners.end()) {
00163                 DisposeBanner(it->second);
00164                 m_banners.erase(it);
00165         }
00166 }
00167 
00168 void GPC_Canvas::DisposeAllBanners()
00169 {
00170         TBannerMap::iterator it = m_banners.begin();
00171         while (it != m_banners.end()) {
00172                 DisposeBanner(it->second);
00173                 it++;
00174         }
00175 }
00176 
00177 void GPC_Canvas::SetBannerEnabled(TBannerId id, bool enabled)
00178 {
00179         TBannerMap::iterator it = m_banners.find(id);
00180         if (it != m_banners.end()) {
00181                 it->second.enabled = enabled;
00182         }
00183 }
00184 
00185 
00186 void GPC_Canvas::SetBannerDisplayEnabled(bool enabled)
00187 {
00188         m_bannersEnabled = enabled;
00189 }
00190 
00191 
00192 void GPC_Canvas::DisposeBanner(TBannerData& banner)
00193 {
00194         if (banner.imageData) {
00195                 delete [] banner.imageData;
00196                 banner.imageData = 0;
00197         }
00198         if (banner.textureName) {
00199                 ::glDeleteTextures(1, (GLuint*)&banner.textureName);
00200         }
00201 }
00202 
00203 void GPC_Canvas::DrawAllBanners(void)
00204 {
00205         if(!m_bannersEnabled || (m_banners.size() < 1))
00206                 return;
00207         
00208         // Save the old rendering parameters.
00209 
00210         CanvasRenderState render_state;
00211         PushRenderState(render_state);
00212 
00213         // Set up everything for banner display.
00214         
00215         // Set up OpenGL matrices 
00216         SetOrthoProjection();
00217         // Activate OpenGL settings needed for display of the texture
00218         ::glDisable(GL_LIGHTING);
00219         ::glDisable(GL_DEPTH_TEST);
00220         ::glDisable(GL_FOG);
00221         ::glEnable(GL_TEXTURE_2D);
00222         ::glEnable(GL_BLEND);
00223         ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00224 
00225         TBannerMap::iterator it = m_banners.begin();
00226         while (it != m_banners.end()) {
00227                 if (it->second.enabled) {
00228                         DrawBanner(it->second);
00229                 }
00230                 it++;
00231         }
00232 
00233         PopRenderState(render_state);
00234 }
00235 
00236 
00237 void GPC_Canvas::DrawBanner(TBannerData& banner)
00238 {
00239         if(!banner.enabled)
00240                 return;
00241 
00242         // Set up coordinates
00243         int coords[4][2];
00244         if (banner.alignment == alignTopLeft) {
00245                 // Upper left
00246                 coords[0][0] = 0;
00247                 coords[0][1] = ((int)m_height)-banner.displayHeight;
00248                 coords[1][0] = banner.displayWidth;
00249                 coords[1][1] = ((int)m_height)-banner.displayHeight;
00250                 coords[2][0] = banner.displayWidth;
00251                 coords[2][1] = ((int)m_height);
00252                 coords[3][0] = 0;
00253                 coords[3][1] = ((int)m_height);
00254         }
00255         else {
00256                 // Lower right
00257                 coords[0][0] = (int)m_width - banner.displayWidth;
00258                 coords[0][1] = 0;
00259                 coords[1][0] = m_width;
00260                 coords[1][1] = 0;
00261                 coords[2][0] = m_width;
00262                 coords[2][1] = banner.displayHeight;
00263                 coords[3][0] = (int)m_width - banner.displayWidth;
00264                 coords[3][1] = banner.displayHeight;
00265         }
00266         // Set up uvs
00267         int uvs[4][2] = {
00268                 { 0, 1},
00269                 { 1, 1},
00270                 { 1, 0},
00271                 { 0, 0}
00272         };
00273 
00274         if (!banner.textureName) {
00275                 ::glGenTextures(1, (GLuint*)&banner.textureName);
00276                 ::glBindTexture(GL_TEXTURE_2D, banner.textureName);
00277                 ::glTexImage2D(
00278                         GL_TEXTURE_2D,                  // target
00279                         0,                                              // level
00280                         4,                                              // components
00281                         banner.imageWidth,              // width
00282                         banner.displayHeight,   // height
00283                         0,                                              // border
00284                         GL_RGBA,                                // format
00285                         GL_UNSIGNED_BYTE,               // type
00286                         banner.imageData);              // image data
00287                 ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00288                 ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00289         }
00290         else {
00291                 ::glBindTexture(GL_TEXTURE_2D, banner.textureName);
00292         }
00293 
00294         // Draw the rectangle with the texture on it
00295         ::glBegin(GL_QUADS);
00296         ::glColor4f(1.f, 1.f, 1.f, 1.f);
00297         ::glTexCoord2iv((GLint*)uvs[0]);
00298         ::glVertex2iv((GLint*)coords[0]);
00299         ::glTexCoord2iv((GLint*)uvs[1]);
00300         ::glVertex2iv((GLint*)coords[1]);
00301         ::glTexCoord2iv((GLint*)uvs[2]);
00302         ::glVertex2iv((GLint*)coords[2]);
00303         ::glTexCoord2iv((GLint*)uvs[3]);
00304         ::glVertex2iv((GLint*)coords[3]);
00305         ::glEnd();
00306 }
00307 
00308         void
00309 GPC_Canvas::
00310 PushRenderState(
00311         CanvasRenderState & render_state
00312 ){
00313 #if 0
00314 
00315         ::glMatrixMode(GL_PROJECTION);
00316         ::glPushMatrix();
00317         ::glMatrixMode(GL_MODELVIEW);
00318         ::glPushMatrix();
00319         ::glMatrixMode(GL_TEXTURE);
00320         ::glPushMatrix();
00321         // Save old OpenGL settings
00322         ::glGetIntegerv(GL_LIGHTING, (GLint*)&(render_state.oldLighting));
00323         ::glGetIntegerv(GL_DEPTH_TEST, (GLint*)&(render_state.oldDepthTest));
00324         ::glGetIntegerv(GL_FOG, (GLint*)&(render_state.oldFog));
00325         ::glGetIntegerv(GL_TEXTURE_2D, (GLint*)&(render_state.oldTexture2D));
00326         ::glGetIntegerv(GL_BLEND, (GLint*)&(render_state.oldBlend));
00327         ::glGetIntegerv(GL_BLEND_SRC, (GLint*)&(render_state.oldBlendSrc));
00328         ::glGetIntegerv(GL_BLEND_DST, (GLint*)&(render_state.oldBlendDst));
00329         ::glGetFloatv(GL_CURRENT_COLOR, render_state.oldColor);
00330         ::glGetIntegerv(GL_DEPTH_WRITEMASK,(GLint*)&(render_state.oldWriteMask));
00331 #else
00332 
00333         glPushAttrib(GL_ALL_ATTRIB_BITS);
00334 
00335 #endif
00336 }
00337 
00338         void
00339 GPC_Canvas::
00340 PopRenderState(
00341         const CanvasRenderState & render_state
00342 ){
00343 #if 0
00344         // Restore OpenGL settings
00345         render_state.oldLighting ? ::glEnable(GL_LIGHTING) : glDisable(GL_LIGHTING);
00346         render_state.oldDepthTest ? ::glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST);
00347         render_state.oldFog ? ::glEnable(GL_FOG) : ::glDisable(GL_FOG);
00348         render_state.oldTexture2D ? ::glEnable(GL_TEXTURE_2D) : glDisable(GL_TEXTURE_2D);
00349         render_state.oldBlend ? glEnable(GL_BLEND) : ::glDisable(GL_BLEND);
00350         ::glBlendFunc((GLenum)render_state.oldBlendSrc, (GLenum)render_state.oldBlendDst);
00351         render_state.oldWriteMask ? ::glEnable(GL_DEPTH_WRITEMASK) : glDisable(GL_DEPTH_WRITEMASK);
00352 
00353         ::glColor4fv(render_state.oldColor);
00354         // Restore OpenGL matrices
00355         ::glMatrixMode(GL_TEXTURE);
00356         ::glPopMatrix();
00357         ::glMatrixMode(GL_PROJECTION);
00358         ::glPopMatrix();
00359         ::glMatrixMode(GL_MODELVIEW);
00360         ::glPopMatrix();
00361 
00362 #else
00363 
00364         glPopAttrib();
00365 #endif
00366 }
00367 
00368         void
00369 GPC_Canvas::
00370 SetOrthoProjection(
00371 ){
00372         // Set up OpenGL matrices 
00373         ::glViewport(0, 0, m_width, m_height);
00374         ::glScissor(0, 0, m_width, m_height);
00375         ::glMatrixMode(GL_PROJECTION);
00376         ::glLoadIdentity();
00377         ::glOrtho(0, m_width, 0, m_height, -1, 1);
00378         ::glMatrixMode(GL_MODELVIEW);
00379         ::glLoadIdentity();
00380         ::glMatrixMode(GL_TEXTURE);
00381         ::glLoadIdentity();
00382 }
00383 
00384         void
00385 GPC_Canvas::
00386 MakeScreenShot(
00387         const char* filename
00388 ){
00389         png_structp png_ptr;
00390         png_infop info_ptr;
00391         unsigned char *pixels = 0;
00392         png_bytepp row_pointers = 0;
00393         int i, bytesperpixel = 3, color_type = PNG_COLOR_TYPE_RGB;
00394         FILE *fp = 0;
00395 
00396         png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
00397         if (!png_ptr) 
00398         {
00399                 std::cout << "Cannot png_create_write_struct." << std::endl;
00400                 return;
00401         }
00402 
00403         info_ptr = png_create_info_struct(png_ptr);
00404         if (!info_ptr) 
00405         {
00406                 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
00407                 std::cout << "Cannot png_create_info_struct." << std::endl;
00408                 return;
00409         }
00410 
00411         if (setjmp(png_jmpbuf(png_ptr))) {
00412                 png_destroy_write_struct(&png_ptr, &info_ptr);
00413                 delete [] pixels;
00414                 delete [] row_pointers;
00415                 // printf("Aborting\n");
00416                 if (fp) {
00417                         fflush(fp);
00418                         fclose(fp);
00419                 }
00420                 return;
00421         }
00422 
00423         // copy image data
00424 
00425         pixels = new unsigned char[GetWidth() * GetHeight() * bytesperpixel * sizeof(unsigned char)];
00426         if (!pixels) {
00427                 std::cout << "Cannot allocate pixels array" << std::endl;
00428                 return;
00429         }
00430 
00431         glReadPixels(0, 0, GetWidth(), GetHeight(), GL_RGB, GL_UNSIGNED_BYTE, pixels);
00432 
00433         fp = fopen(filename, "wb");
00434         if (!fp)
00435         {
00436                 std::cout << "Couldn't open " << filename << " for writing." << std::endl;
00437                 longjmp(png_jmpbuf(png_ptr), 1);
00438         }
00439 
00440         png_init_io(png_ptr, fp);
00441 
00442         /*
00443         png_set_filter(png_ptr, 0,
00444                 PNG_FILTER_NONE  | PNG_FILTER_VALUE_NONE |
00445                 PNG_FILTER_SUB   | PNG_FILTER_VALUE_SUB  |
00446                 PNG_FILTER_UP    | PNG_FILTER_VALUE_UP   |
00447                 PNG_FILTER_AVG   | PNG_FILTER_VALUE_AVG  |
00448                 PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH|
00449                 PNG_ALL_FILTERS);
00450 
00451         png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
00452         */
00453 
00454         // png image settings
00455         png_set_IHDR(png_ptr,
00456                  info_ptr,
00457                  GetWidth(),
00458                  GetHeight(),
00459                  8,
00460                  color_type,
00461                  PNG_INTERLACE_NONE,
00462                  PNG_COMPRESSION_TYPE_DEFAULT,
00463                  PNG_FILTER_TYPE_DEFAULT);
00464 
00465         // write the file header information
00466         png_write_info(png_ptr, info_ptr);
00467 
00468         // allocate memory for an array of row-pointers
00469         row_pointers = new png_bytep [(GetHeight() * sizeof(png_bytep))];
00470         if (!row_pointers) 
00471         {
00472                 std::cout << "Cannot allocate row-pointers array" << std::endl;
00473                 longjmp(png_jmpbuf(png_ptr), 1);
00474         }
00475 
00476         // set the individual row-pointers to point at the correct offsets
00477         for (i = 0; i < GetHeight(); i++) {
00478                 row_pointers[GetHeight()-1-i] = (png_bytep)
00479                         ((unsigned char *)pixels + (i * GetWidth()) * bytesperpixel * sizeof(unsigned char));
00480         }
00481 
00482         // write out the entire image data in one call
00483         png_write_image(png_ptr, row_pointers);
00484 
00485         // write the additional chunks to the PNG file (not really needed)
00486         png_write_end(png_ptr, info_ptr);
00487 
00488         // clean up
00489         delete [] (pixels);
00490         delete [] (row_pointers);
00491         png_destroy_write_struct(&png_ptr, &info_ptr);
00492 
00493         if (fp) 
00494         {
00495                 fflush(fp);
00496                 fclose(fp);
00497         }
00498 }
00499