Hi,
I'm working on a program to display 2D map data derived from the World
Data Bank, and have run across a couple of problems that look to me like
Mesa bugs.

I'm running Mesa 3.1 from Ryan Weaver's RPMs on a Red Hat 5.1 Linux
system and XFree86 3.3.2. I've displayed locally in 24 bit truecolor,
and remotely to an OpenVMS display that I believe is 24 bit direct
color.

The program reads a map data file and builds a display list consisting
of line strips, which can be quite lengthy.

I sometimes see extra lines appear on the display.  This seems to happen
at about the time the last point of some line strip gets clipped out of
the display.  I have a GLUT-based program and dataset that can reproduce
the problem.  Controls in the program use the middle mouse button and
drag action to pan/zoom the map.  Control-drag to zoom, drag to pan,
escape to quit.

The second problem is that when I use double buffering, after
panning/zooming for a little while (under 30 seconds of use) I get a
segmentation fault.  This hasn't happened when I don't double-buffer.

The program's a little over 200 lines, so I've included that.  The
smallest dataset I have which reproduces the problem is about 80K, so I
thought I should ask before emailing it.  The 80K dataset is apparently
insufficient to cause the seg fault, but I have one that's 916K that
will do it.  Please let me know if you'd like me to send either or both
datasets.

Joe Bronkema
Senior Member Engineering Staff
Lockheed Martin NE&SS - Moorestown
[EMAIL PROTECTED]
extern "C" {
#include <GL/glut.h>
}
#include <math.h>
#include <fstream>
#include <iostream.h>

const float RAD_PER_DEG = 0.017453293;
const float EARTH_RADIUS_KM = 6378.137;        // earth radius in km
float world_x_min;
float world_x_max;
float world_y_min;
float world_y_max;

void cxsr_ll_xy (float longitude, float latitude, float &x, float &y)
{
   y = EARTH_RADIUS_KM * 
     log(tan(0.785398163 + (latitude * RAD_PER_DEG / 2.0)));
   x = EARTH_RADIUS_KM * longitude * RAD_PER_DEG;
}

GLuint mapList;

int loadmap(char *fname)
{
   ifstream mapfile(fname);
   if (mapfile.fail()) return(0);
   
   int rectype;                  // record type from map file
   float point_lat, point_long;  // latitude and longitude
   float point_x, point_y;
   
   // get map limits from first two lines of the file
   mapfile >> rectype >> point_long >> point_lat;
   cxsr_ll_xy(point_long, point_lat, world_x_min, world_y_min);
   mapfile >> rectype >> point_long >> point_lat;
   cxsr_ll_xy(point_long, point_lat, world_x_max, world_y_max);
   float delta_x = world_x_max - world_x_min;
   float delta_y = world_y_max - world_y_min;
   if (delta_x > delta_y) delta_y = delta_x;
   else delta_x = delta_y;
   world_x_max = world_x_min + delta_x;
   world_y_max = world_y_min + delta_y;
   
   // Build display list mapList, but do not draw it at this time
   glNewList(mapList, GL_COMPILE);
   int skip;
   int junk = 0;
   while (!mapfile.eof()) {
      mapfile >> rectype >> point_long >> point_lat;
      if (rectype == 4) {     // beginning land section
         glBegin(GL_LINE_STRIP);
         // color = coast/island/lake color
         glColor3f(0.0, 0.7, 0.0);
         skip = 0;
      }
      else if (rectype == 2) { // beginning border section
         glEnd();
         glBegin(GL_LINE_STRIP);
         // color = border color
         glColor3f(0.85,0.85, 0.25);
         skip = 0;
      }
      else if (rectype == 1) { // new segment within section
         glEnd();
         glBegin(GL_LINE_STRIP);
         skip = 0;
      }
      
      // If point is within our limits, add it to the point list
      cxsr_ll_xy(point_long, point_lat, point_x, point_y);
      if ((point_x >= world_x_min) &&
          (point_x <= world_x_max) &&
          (point_y >= world_y_min) &&
          (point_y <= world_y_max)) {
         if (skip == 0) {
            glVertex2f(point_x, point_y);
         }
         skip++;
         if (skip >= 2) skip = 0;
      }
   } // end reading map file
   glEnd();
   glEndList();
   return(1);
}

// Variables used in setting up the projection
int zoom;
int zoom_max;
float pan_x;
float pan_y;

// aspect ratio
float aspect;

// Variables used in mouse control
bool panning;
bool zooming;
int last_x;
int last_y;
int window_pixels_wide;
int window_pixels_high;
float window_world_wide;  // width of viewing area in world coordinates
float window_world_high;  // height of viewing area in world coordinates

void resize(int caller) {
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();

   // Specifying near and far with same magnitude and opposite sign 
   // gives parallel projection like gluOrtho2D
   // left right bottom top near far
   if (aspect >= 1) { // y longer than x
      float right = world_x_min + (world_x_max - world_x_min) / aspect;
      glOrtho(world_x_min + zoom + pan_x, right - zoom + pan_x,  
              world_y_min + zoom + pan_y, world_y_max - zoom + pan_y, 
              -10000.0, 10000.0);
      window_world_wide = right - world_x_min - 2.0 * zoom;
      window_world_high = world_y_max - world_y_min - 2.0 * zoom;
   } else {
      float top = world_y_min + aspect * (world_y_max - world_y_min);
      glOrtho(world_x_min + zoom + pan_x, world_x_max - zoom + pan_x,
              world_y_min + zoom + pan_y, top - zoom + pan_y,
              -10000.0, 10000.0);
      window_world_wide = world_x_max - world_x_min - 2.0 * zoom;
      window_world_high = top - world_y_min - 2.0 * zoom;
   }
   glutPostRedisplay();
}

void reshape(int x, int y) {
   window_pixels_wide = x;
   window_pixels_high = y;
   cout << "reshape " << x << " " << y << endl;
   aspect = (float) y / (float) x;
   glViewport(0,0,x,y);
   resize(0);
}

void click(int button, int state, int x, int y) {
   if (button == GLUT_MIDDLE_BUTTON) {
      if (state == GLUT_DOWN) {
         last_x = x;
         last_y = y;
         if (glutGetModifiers() & GLUT_ACTIVE_CTRL) zooming = true;
         else panning = true;
      } else { // user let go of the button
         panning = false;
         zooming = false;
      }
   }
}

void drag (int x, int y) {
   int delta_x = x - last_x;
   int delta_y = y - last_y;
   if (panning) {
      pan_x -=  window_world_wide * delta_x / window_pixels_wide;
      pan_y +=  window_world_high * delta_y / window_pixels_high;
      resize(-1);
   }
   if (zooming) {
      zoom += 20 * delta_x;
      if (zoom > zoom_max) zoom = zoom_max;
      if (zoom < 0) zoom = 0;
      resize(-1);
   }
   last_x = x;
   last_y = y;
}

void display() {
   glClear(GL_COLOR_BUFFER_BIT);
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   glCallList(mapList);
   //glFlush();
}

void keyboard(unsigned char key, int x, int y)
{
   switch (key) {
    case 27:
      exit(0);
      break;
   }
}

int main(int argc, char *argv[]) {
   if (argc != 2) {
      cout << "Usage: drawmap <mapfile name>" << endl;
      exit(0);
   }
   glutInit(&argc, argv);
   glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
   glutInitWindowPosition(50,50);
   glutInitWindowSize(600,600);
   int mainWindow = glutCreateWindow("Map");
   glutDisplayFunc(display);
   glutReshapeFunc(reshape);
   glutMouseFunc(click);
   glutMotionFunc(drag);
   glutKeyboardFunc(keyboard);
   glShadeModel(GL_FLAT);
   mapList = glGenLists(1);
   
   if (!loadmap(argv[1])) {
      cout << "Error loading map file" << endl;
   }
   zoom_max = int((world_x_max - world_x_min) * 0.485);
   
   glutMainLoop();
}

Reply via email to