Выбрать главу

 b = pointTimes(3*pow(u,2)*(1-u), p[1]);

 c = pointTimes(3*u*pow((1-u),2), p[2]);

 d = pointTimes(pow((1-u),3), p[3]);

 r = pointAdd(pointAdd(a, b), pointAdd(c, d));

 return r;

}

This function does the lion's share of the work by generating all the triangle strips and storing them in a display list. We do this so that we don't have to recalculate the patch each frame, only when it changes. By the way, a cool effect you might want to try might be to use the morphing tutorial to morph the patch's control points. This would yeild a very cool smooth, organic, morphing effect for relatively little overhead (you only morph 16 points, but you have to recalculate). The "last" array is used to keep the previous line of points (since a triangle strip needs both rows). Also, texture coordinates are calculated by using the u and v values as the percentages (planar mapping).

One thing we don't do is calculate the normals for lighting. When it comes to this, you basically have two options. The first is to find the center of each triangle, then use a bit of calculus and calculate the tangent on both the x and y axes, then do the cross product to get a vector perpendicular to both, THEN normalize the vector and use that as the normal. OR (yes, there is a faster way) you can cheat and just use the normal of the triangle (calculated your favorite way) to get a pretty good approximation. I prefer the latter; the speed hit, in my opinion, isn't worth the extra little bit of realism.

// Generates A Display List Based On The Data In The Patch

// And The Number Of Divisions

GLuint genBezier(BEZIER_PATCH patch, int divs) {

 int u = 0, v;

 float py, px, pyold;

 GLuint drawlist = glGenLists(1); // Make The Display List

 POINT_3D temp[4];

 POINT_3D *last = (POINT_3D*)malloc(sizeof(POINT_3D)*(divs+1));

 // Array Of Points To Mark The First Line Of Polys

 if (patch.dlBPatch != NULL) // Get Rid Of Any Old Display Lists

  glDeleteLists(patch.dlBPatch, 1);

 temp[0] = patch.anchors[0][3]; // The First Derived Curve (Along X-Axis)

 temp[1] = patch.anchors[1][3];

 temp[2] = patch.anchors[2][3];

 temp[3] = patch.anchors[3][3];

 for (v=0;v<=divs;v++) { // Create The First Line Of Points

  px = ((float)v)/((float)divs); // Percent Along Y-Axis

  // Use The 4 Points From The Derived Curve To Calculate The Points Along That Curve

  last[v] = Bernstein(px, temp);

 }

 glNewList(drawlist, GL_COMPILE); // Start A New Display List

 glBindTexture(GL_TEXTURE_2D, patch.texture); // Bind The Texture

 for (u=1;u<=divs;u++) {

  py = ((float)u)/((float)divs); // Percent Along Y-Axis

  pyold = ((float)u-1.0f)/((float)divs); // Percent Along Old Y Axis

  temp[0] = Bernstein(py, patch.anchors[0]); // Calculate New Bezier Points

  temp[1] = Bernstein(py, patch.anchors[1]);

  temp[2] = Bernstein(py, patch.anchors[2]);

  temp[3] = Bernstein(py, patch.anchors[3]);

  glBegin(GL_TRIANGLE_STRIP); // Begin A New Triangle Strip

  for (v=0;v<=divs;v++) {

   px = ((float)v)/((float)divs); // Percent Along The X-Axis

   glTexCoord2f(pyold, px); // Apply The Old Texture Coords

   glVertex3d(last[v].x, last[v].y, last[v].z); // Old Point

   last[v] = Bernstein(px, temp); // Generate New Point

   glTexCoord2f(py, px); // Apply The New Texture Coords

   glVertex3d(last[v].x, last[v].y, last[v].z); // New Point

  }

  glEnd(); // END The Triangle Strip

 }

 glEndList(); // END The List

 free(last); // Free The Old Vertices Array

 return drawlist; // Return The Display List

}

Here we're just loading the matrix with some values I've picked that I think look cool. Feel free to screw around with these and see what it looks like. :-)

void initBezier(void) {

 mybezier.anchors[0][0] = makePoint(-0.75, –0.75, –0.50); // Set The Bezier Vertices

 mybezier.anchors[0][1] = makePoint(-0.25, –0.75, 0.00);

 mybezier.anchors[0][2] = makePoint( 0.25, –0.75, 0.00);

 mybezier.anchors[0][3] = makePoint( 0.75, –0.75, –0.50);

 mybezier.anchors[1][0] = makePoint(-0.75, –0.25, –0.75);

 mybezier.anchors[1][1] = makePoint(-0.25, –0.25, 0.50);

 mybezier.anchors[1][2] = makePoint( 0.25, –0.25, 0.50);

 mybezier.anchors[1][3] = makePoint( 0.75, –0.25, –0.75);

 mybezier.anchors[2][0] = makePoint(-0.75, 0.25, 0.00);

 mybezier.anchors[2][1] = makePoint(-0.25, 0.25, –0.50);

 mybezier.anchors[2][2] = makePoint( 0.25, 0.25, –0.50);

 mybezier.anchors[2][3] = makePoint( 0.75, 0.25, 0.00);

 mybezier.anchors[3][0] = makePoint(-0.75, 0.75, –0.50);

 mybezier.anchors[3][1] = makePoint(-0.25, 0.75, –1.00);

 mybezier.anchors[3][2] = makePoint( 0.25, 0.75, –1.00);

 mybezier.anchors[3][3] = makePoint( 0.75, 0.75, –0.50);

 mybezier.dlBPatch = NULL; // Go Ahead And Initialize This To NULL

}

This is basically just an optimised routine to load a single bitmap. It can easily be used to load an array of em just by putting it in a simple loop.

// Load Bitmaps And Convert To Textures

BOOL LoadGLTexture(GLuint *texPntr, char* name) {

 BOOL success = FALSE;

 AUX_RGBImageRec *TextureImage = NULL;

 glGenTextures(1, texPntr); // Generate 1 Texture

 FILE* test=NULL;

 TextureImage = NULL;

 test = fopen(name, "r"); // Test To See If The File Exists

 if (test != NULL) { // If It Does

  fclose(test); // Close The File

  TextureImage = auxDIBImageLoad(name); // And Load The Texture

 }

 if (TextureImage != NULL) { // If It Loaded

  success = TRUE;

  // Typical Texture Generation Using Data From The Bitmap

  glBindTexture(GL_TEXTURE_2D, *texPntr);

  glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage->sizeX, TextureImage->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage->data);

  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

 }

 if (TextureImage->data)

 free(TextureImage->data);

 return success;

}

Just adding the patch initialization here. You would do this whenever you create a patch. Again, this might be a cool place to use C++ (bezier class?).

int InitGL(GLvoid) // All Setup For OpenGL Goes Here

{

 glEnable(GL_TEXTURE_2D); // Enable Texture Mapping