|
Scientific Visualization and Animation using Bezier Surfaces
An Introduction |
|
Prof. David Bernstein |
| Computer Science Department |
| bernstdh@jmu.edu |
glMapGrid2f())glEvalMesh2()
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include "../sva/sva.h" // Must be after windows.h
#include "GL/gl.h"
/**
* An application for "editing" Bezier surfaces
*
* Mouse Commands:
*
* Left-Drag: To move a point
*
* @author Prof. David Bernstein, James Madison University
* @version 1.0
*/
/**
* A second order surface
*/
GLfloat points[2][2][3] =
{
{
{-2.0, -2.0, 0.0},
{ 2.0, -2.0, 0.0}},
{
{-2.0, 2.0, 0.0},
{ 2.0, 2.0, 0.0}}
};
int uSize = 2;
int vSize = 2;
/*
* A fourth order surface
GLfloat points[4][4][3] =
{
{
{-2.0, -2.0, 0.0},
{-0.5, -2.0, 0.0},
{ 0.5, -2.0, 0.0},
{ 2.0, -2.0, 0.0}},
{
{-2.0, -0.5, 0.0},
{-0.5, -0.5, 0.0},
{ 0.5, -0.5, 0.0},
{ 2.0, -0.5, 0.0}},
{
{-2.0, 0.5, 0.0},
{-0.5, 0.5, 0.0},
{ 0.5, 0.5, 0.0},
{ 2.0, 0.5, 0.0}},
{
{-2.0, 2.0, 0.0},
{-0.5, 2.0, 0.0},
{ 0.5, 2.0, 0.0},
{ 2.0, 2.0, 0.0}}
};
int uSize = 4;
int vSize = 4;
*/
// The number of subdivisions in the grid
int gridSize = 20;
int uSelected = -1;
int vSelected = -1;
// Empty SVA functions
void onMouseMove(GLfloat x, GLfloat y){}
void onTimer(int time){}
// Prototypes
GLfloat distanceSquared(GLfloat x1, GLfloat y1, GLfloat z1,
GLfloat x2, GLfloat y2, GLfloat z2);
/**
* Find the closest point controlling the curve
*
* @param x The x-coordinate to compare to
* @param y The y-coordinate to compare to
* @param z The z-coordinate to compare to
* @param ui The u-index of the clossest point (OUT)
* @param vi The v-index of the clossest point (OUR)
*/
void closestPointTo(GLfloat x, GLfloat y, GLfloat z, int &ui, int &vi)
{
GLfloat d, min;
ui = -1;
vi = -1;
min = distanceSquared(points[0][0][0], points[0][0][1], points[0][0][2],
x, y, z);
ui = 0;
vi = 0;
for (int u=0; u<uSize; u++)
{
for (int v=0; v<vSize; v++)
{
d = distanceSquared(points[u][v][0], points[u][v][1], points[u][v][2],
x, y, z);
if (d < min)
{
ui = u;
vi = v;
min = d;
}
}
}
}
/**
* Return the squared Euclidean sistance between two points
*/
GLfloat distanceSquared(GLfloat x1, GLfloat y1, GLfloat z1,
GLfloat x2, GLfloat y2, GLfloat z2)
{
GLfloat d;
d = (x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2) + (z1 - z2)*(z1 - z2);
return d;
}
/**
* Display Callback
*/
void onDisplay()
{
// Clear the screen
glClear(GL_COLOR_BUFFER_BIT);
// Set the color
glColor3f(1.0, 0.0, 0.0);
//
// The evaluator
glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, uSize, 0, 1, uSize*3, vSize,
&points[0][0][0]);
// Draw the mesh
glEvalMesh2(GL_LINE, 0, gridSize, 0, gridSize);
// Show the points
glPointSize(3.);
glBegin(GL_POINTS);
{
for (int u=0; u<uSize; u++)
{
for (int v=0; v<vSize; v++)
{
if ((u == uSelected) && (v == vSelected))
{
glColor3f(1.0, 0.0, 1.0);
glVertex3fv(&points[u][v][0]);
}
else
{
glColor3f(0.0, 1.0, 0.0);
glVertex3fv(&points[u][v][0]);
}
}
}
glEnd();
}
}
/**
* The mouse callback (i.e., the function that is called
* each time a mouse button is pressed or released).
*
* @param button The button (e.g., GLUT_LEFT_BUTTON)
* @param state The state (e.g., GLUT_UP or GLUT_DOWN)
* @param x The x-position of the mouse
* @param y The y-position of the mouse
*/
void onMouseClick(int button, int state, GLfloat x, GLfloat y)
{
if(button == SVA_LEFT_BUTTON)
{
if (state == SVA_DOWN)
{
closestPointTo(x, y, 0.0, uSelected, vSelected);
}
else
{
uSelected = -1;
vSelected = -1;
}
svaRedisplay();
}
}
/**
* The mouse drag callback
*
* @param x The x-position of the mouse
* @param y The y-position of the mouse
*/
void onMouseDrag(GLfloat x, GLfloat y)
{
if ((uSelected >= 0) && (vSelected >= 0))
{
points[uSelected][vSelected][0] = x;
points[uSelected][vSelected][1] = y;
svaRedisplay();
}
}
/**
* The entry point of the application.
*
* @param argc The number of command line arguments
* @param argv The array of command line arguments
* @return A status code
*/
int main(int argc, char **argv)
{
float min[] = {-4.0, -4.0, -4.0};
float max[] = { 4.0, 4.0, 4.0};
int k;
// Create and initialize the SVA window
svaCreate(argc, argv, min, max);
svaShowAxes(false);
svaSetRotation(0.0, 0.0, 0.0);
// Enable the 2-dimensional evaluator
glEnable(GL_MAP2_VERTEX_3);
glMapGrid2f(gridSize, 0.0, 1.0, gridSize, 0.0, 1.0);
// Start the SVA visualization
svaStartVisualization();
}
// Enable lighting and shading
GLfloat ambient[] = {0.2, 0.2, 0.2, 1.0};
GLfloat position[] = {0.0, 0.0, 2.0, 1.0};
GLfloat diffuse[] = {0.7, 0.0, 0.1, 1.0};
GLfloat specular[] = {1.0, 1.0, 1.0, 1.0};
GLfloat shininess[] = {50.0};
glEnable(GL_LIGHTING); // Enable lighting
glEnable(GL_LIGHT0); // Enable light 0
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
glLightfv(GL_LIGHT0, GL_POSITION, position);
glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, specular);
glMaterialfv(GL_FRONT, GL_SHININESS, shininess);
glEnable(GL_DEPTH_TEST);
glEnable(GL_AUTO_NORMAL);
glEnable(GL_NORMALIZE);
// Enable the 2-dimensional evaluator
glEnable(GL_MAP2_VERTEX_3);
glMapGrid2f(gridSize, 0.0, 1.0, gridSize, 0.0, 1.0);