glshape.cc

Go to the documentation of this file.
00001 /*
00002  *  glshape.cc - Paint 2D shapes in OpenGL
00003  *
00004  *  Written: 7/16/02 - JSF
00005  *
00006  *  Copyright (C) 2002  The Exult Team
00007  *
00008  *  This program 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  *  This program 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 this program; if not, write to the Free Software
00020  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00021  */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #  include <config.h>
00025 #endif
00026 
00027 #ifdef HAVE_OPENGL
00028 
00029 #include <GL/gl.h>
00030 
00031 #include "glshape.h"
00032 #include "vgafile.h"
00033 #include "utils.h"
00034 #include "exult_constants.h"
00035 #include "ibuf8.h"
00036 
00037 GL_manager *GL_manager::instance = 0;
00038 
00039 const unsigned char transp = 255; // Transparent pixel.
00040 
00041 /*
00042  *  Create from a given source.  Assumes src is square, with texsize
00043  *  already set to length.
00044  */
00045 
00046 void GL_texshape::create
00047   (
00048   Image_buffer8 *src,   // Source image.
00049   unsigned char *pal,   // 3*256 bytes (rgb).
00050   Xform_palette *xforms,    // Transforms translucent colors if !0.
00051   int xfcnt     // Number of xforms.
00052   )
00053   {
00054   assert(pal != 0);
00055   const int xfstart = 0xff - xfcnt;
00056           // Convert to rgba.
00057   unsigned char *pixels = xforms ? 
00058       src->rgba(pal, transp, xfstart, 0xfe, xforms)
00059       : src->rgba(pal, transp);
00060   GLuint tex;
00061   glGenTextures(1, &tex);   // Generate (empty) texture.
00062   texture = tex;
00063   glBindTexture(GL_TEXTURE_2D, texture);
00064           // +++++Might want GL_RGBA, depending
00065           //   on video card.
00066           // Need translucency?
00067   GLint iformat = xforms ? GL_RGBA4 : GL_RGB5_A1;
00068 //  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texsize, texsize, 0, GL_RGBA,
00069   glTexImage2D(GL_TEXTURE_2D, 0, iformat, texsize, texsize, 0, GL_RGBA,
00070       GL_UNSIGNED_BYTE, pixels);
00071   delete pixels;
00072           // Linear filtering.
00073 #if 0
00074   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00075   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00076 #else /* This looks less blurry, and helps get rid of the lines.  */
00077   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00078   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
00079 #endif
00080   // Enable texture clamping. This will get rid of all the lines everywhere
00081   // -Colourless
00082   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_CLAMP);
00083   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_CLAMP);
00084 
00085   }
00086 
00087 /*
00088  *  Create for a given frame.
00089  */
00090 
00091 GL_texshape::GL_texshape
00092   (
00093   Shape_frame *f,
00094   unsigned char *pal,   // 3*256 bytes (rgb).
00095   Xform_palette *xforms,    // Transforms translucent colors if !0.
00096   int xfcnt     // Number of xforms.
00097   ) : frame(f), lru_next(0), lru_prev(0)
00098   {
00099   int w = frame->get_width(), h = frame->get_height();
00100           // Figure texture size as 2^n, rounding
00101           //   up.
00102   int logw = Log2(2*w - 1), logh = Log2(2*h - 1);
00103   texsize = 1<<(logw > logh ? logw : logh);
00104           // Render frame.
00105   Image_buffer8 buf8(texsize, texsize);
00106   buf8.fill8(transp);   // Fill with transparent value.
00107           // ++++Guessing a bit on the offset:
00108   frame->paint(&buf8, texsize - frame->get_xright() - 1,
00109           texsize - frame->get_ybelow() - 1);
00110   create(&buf8, pal, xforms, xfcnt);
00111   }
00112 
00113 /*
00114  *  Create from a given (square, size 2^n) image.
00115  */
00116 
00117 GL_texshape::GL_texshape
00118   (
00119   Image_buffer8 *src,   // Must be square.
00120   unsigned char *pal    // 3*256 bytes (rgb).
00121   ) : frame(0), lru_next(0), lru_prev(0)
00122   {
00123   int w = src->get_width(), h = src->get_height();
00124   assert (w == h);
00125   assert ((1<<Log2(w)) == w);
00126   texsize = w;
00127   create(src, pal);
00128   }
00129 
00130 /*
00131  *  Free resources.
00132  */
00133 
00134 GL_texshape::~GL_texshape
00135   (
00136   )
00137   {
00138   glDeleteTextures(1, &texture);  // Free the texture.
00139   if (frame)
00140     frame->glshape = 0; // Tell owner.
00141   }
00142 
00143 /*
00144  *  Paint it.
00145  */
00146 
00147 void GL_texshape::paint
00148   (
00149   int px, int py      // Location in 'pixels' from top-left
00150           //   of screen.
00151   )
00152   {
00153   glEnable(GL_TEXTURE_2D);  // Enable texture-mapping.
00154   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
00155   glPushMatrix();
00156   float x = static_cast<float>(px);
00157   float y = static_cast<float>(py) + texsize;
00158   if (frame)
00159     {
00160     x += frame->get_xright() + 1 - (int) texsize;
00161     y += frame->get_ybelow() + 1 - (int) texsize;
00162     }
00163           // Game y-coord goes down from top.
00164   y = -y;
00165   float w = static_cast<float>(texsize), 
00166         h = static_cast<float>(texsize);
00167   glTranslatef(x, y, 0);
00168           // Choose texture.
00169   glBindTexture(GL_TEXTURE_2D, texture);
00170   glBegin(GL_QUADS);
00171     {
00172     glTexCoord2f(0, 0);   glVertex3f(0, h, 0);
00173     glTexCoord2f(0, 1);   glVertex3f(0, 0, 0);
00174     glTexCoord2f(1, 1);   glVertex3f(w, 0, 0);
00175     glTexCoord2f(1, 0);   glVertex3f(w, h, 0);
00176     }
00177   glEnd();
00178   glPopMatrix();
00179   }
00180 
00181 /*
00182  *  Create OpenGL manager.
00183  */
00184 
00185 GL_manager::GL_manager
00186   (
00187   ) : shapes(0), num_shapes(0), palette(0), scale(1)
00188   {
00189   assert (instance == 0);   // Should only be one.
00190   instance = this;
00191   GLint max_size;
00192   glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_size);
00193   max_texsize = max_size;
00194   glShadeModel(GL_SMOOTH);  // Smooth shading.
00195   glClearColor(1, 1, 1, 0); // Background is white.
00196   glClearDepth(1);
00197 /*
00198   glEnable(GL_DEPTH_TEST);  // Enable depth-testing.
00199   glDepthFunc(GL_LEQUAL);
00200 */
00201   // I'm disabling depth buffer because it's not needed, at the moment.
00202   // It's also causing problems. Not being cleared perhaps? or bad depth
00203   // values for each object. Anyway, I'm disabling both testing and writing
00204   // -Colourless
00205   glDisable(GL_DEPTH_TEST);
00206   glDepthMask(GL_FALSE);
00207 
00208   glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);  // ??
00209   glEnable(GL_BLEND);   // !These two calls do the trick.
00210   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00211 
00212   // Just a note for Jeff, You are using Alpha Blending, but you should
00213   // perhaps think about using Alpha Testing. 
00214   // The functions are glAlphaFunc() and glEnable(GL_ALPHA_TEST).
00215   // Normally a glAlphaFunc(GL_GEQUAL, 127) will do the trick for you
00216   // -Colourless
00217   }
00218 
00219 /*
00220  *  Free resources.
00221  */
00222 
00223 GL_manager::~GL_manager
00224   (
00225   )
00226   {
00227   assert (this == instance);
00228   while (shapes)
00229     {
00230     GL_texshape *next = shapes->lru_next;
00231     delete shapes;
00232     shapes = next;
00233     }
00234   delete palette;
00235   instance = 0;
00236   }
00237 
00238 /*
00239  *  Window was resized.
00240  */
00241 void GL_manager::resized
00242   (
00243   int new_width, int new_height,
00244   int new_scale
00245   )
00246   {
00247   scale = new_scale;
00248           // Set viewing area to whole window.
00249   glViewport(0, 0, scale*new_width, scale*new_height);
00250   glMatrixMode(GL_PROJECTION);  // Set up orthogonal volume.
00251   glLoadIdentity();
00252           // Set camera area in 'pixels'.
00253   glOrtho(0, new_width, -new_height, 0, 1, -16);
00254   glMatrixMode(GL_MODELVIEW); // Use model-view matrix from now on.
00255   glLoadIdentity();
00256           // Clear screen & depth buffer.
00257   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00258   }
00259 
00260 /*
00261  *  Paint an image directly.
00262  */
00263 
00264 static void Paint_image
00265   (
00266   Shape_frame *frame,
00267   int px, int py,     // 'Pixel' position from top-left.
00268   unsigned char *pal,   // 3*256 bytes (rgb).
00269   int scale     // Scale factor.
00270   )
00271   {
00272   px -= frame->get_xleft(); // Figure actual from hot-spot.
00273   py += frame->get_ybelow();
00274           // Game y-coord goes down from top.
00275   py = -py;
00276   int w = frame->get_width(), h = frame->get_height();
00277           // Render frame.
00278   Image_buffer8 buf8(w, h);
00279   w = buf8.get_width(); h = buf8.get_height();
00280   buf8.fill8(transp);   // Fill with transparent value.
00281   frame->paint(&buf8, frame->get_xleft(), frame->get_yabove());
00282           // Convert to rgba.
00283   unsigned char *pixels = buf8.rgba(pal, transp);
00284   if (px < 0)     // Doesn't paint if off screen.
00285     {
00286     glPixelStorei(GL_UNPACK_SKIP_PIXELS, -px);
00287     glPixelStorei(GL_UNPACK_ROW_LENGTH, w);
00288     w += px;
00289     px = 0;
00290     }
00291           //++++CHeck py too?
00292 //  float x = static_cast<float>(px);
00293 //  float y = static_cast<float>(py);
00294   glPixelZoom(scale, -scale); // Get right side up.
00295   glRasterPos2f(px, py + h);
00296   glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
00297   glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
00298   glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
00299   delete pixels;
00300   }
00301 
00302 /*
00303  *  Paint a shape.
00304  */
00305 
00306 void GL_manager::paint
00307   (
00308   Shape_frame *frame,
00309   int px, int py,     // 'Pixel' position from top-left.
00310   Xform_palette *xforms,    // Transforms translucent colors if !0.
00311   int xfcnt     // Number of xforms.
00312   )
00313   {
00314   GL_texshape *tex = frame->glshape;
00315   if (!tex)     // Need to create texture?
00316     {
00317     if (frame->get_width() > max_texsize || 
00318         frame->get_height() > max_texsize)
00319       {   // Too big?  Just paint it now.
00320       Paint_image(frame, px, py, palette, scale);
00321       return;
00322       }
00323     frame->glshape = tex = new GL_texshape(frame, palette, 
00324               xforms, xfcnt);
00325     num_shapes++;
00326     //++++++When 'too many', we'll free LRU here.
00327     }
00328   else        // Remove from chain.
00329     {
00330     if (tex->lru_next)
00331       tex->lru_next->lru_prev = tex->lru_prev;
00332     if (tex->lru_prev)
00333       tex->lru_prev->lru_next = tex->lru_next;
00334     tex->lru_prev = 0;  // It will go to the head.
00335     }
00336   tex->lru_next = shapes;   // Add to head of chain.
00337   if (shapes)
00338     shapes->lru_prev = tex;
00339   shapes = tex;
00340   tex->paint(px, py);
00341   }
00342 
00343 #endif  /* HAVE_OPENGL */

Generated on Mon Jul 9 14:42:50 2007 for ExultEngine by  doxygen 1.5.1