00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include <OpenGLRenderer.h>
00038 #include <ColorMap.h>
00039 #include <stdio.h>
00040 #include <stdlib.h>
00041 #include <Matrix.h>
00042
00043 #ifdef _WGL
00044 #include <windows.h>
00045 #include <GL/glaux.h>
00046 #include <GL/glu.h>
00047 #include <GL/gl.h>
00048
00049 #elif _GLX
00050
00051 #include <GL/glut.h>
00052
00053 #endif
00054
00055 #define PARALLEL_MODE 0
00056 #define PERSPECTIVE_MODE 1
00057
00058 #define WIRE_MODE 0
00059 #define FILL_MODE 1
00060
00061 #include <db.H>
00062 #include <Vector.h>
00063
00064 OpenGLRenderer::OpenGLRenderer(char *_title, int _xLoc, int _yLoc,
00065 int _width, int _height,
00066 ColorMap &_theMap)
00067 :Renderer(_theMap),
00068 windowTitle(0), height(_height), width(_width), xLoc(_xLoc), yLoc(_yLoc),
00069 count(-1), theFile(0), theOutputFileName(0),
00070 theDevice(0),
00071 vrp(3), vuv(3), vpn(3), cop(3), ViewMat(4,4),
00072 projectionMode(0), vpWindow(4), ProjMat(4,4),
00073 portWindow(4)
00074 {
00075
00076
00077 windowTitle = new char [strlen(_title)+1];
00078 strcpy(windowTitle, _title);
00079
00080 fillMode = WIRE_MODE;
00081 projectionMode = PARALLEL_MODE;
00082 portWindow(0) = -1.0; portWindow(1) = 1.0;
00083 portWindow(2) = -1.0; portWindow(3) = 1.0;
00084
00085 theDevice = new OpenGlDevice();
00086 theDevice->WINOPEN(_title, _xLoc, _yLoc, _width, _height);
00087
00088 theDevice->CLEAR();
00089 glClearColor(1.0f,1.0f,1.0f,1.0f);
00090
00091 glEnable(GL_DEPTH_TEST);
00092 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00093
00094 glFlush();
00095 theDevice->ENDIMAGE();
00096 }
00097
00098
00099
00100
00101 OpenGLRenderer::OpenGLRenderer(char *_title, int _xLoc, int _yLoc,
00102 int _width, int _height,
00103 ColorMap &_theMap,
00104 char *outputFileName,
00105 char *bitmapFileName)
00106 :Renderer(_theMap),
00107 windowTitle(0), height(_height), width(_width), xLoc(_xLoc), yLoc(_yLoc),
00108 count(-1), theFile(0), theOutputFileName(0),
00109 theDevice(0),
00110 vrp(3), vuv(3), vpn(3), cop(3), ViewMat(4,4),
00111 projectionMode(0), vpWindow(4), ProjMat(4,4),
00112 portWindow(4)
00113 {
00114
00115 windowTitle = new char [strlen(_title)+1];
00116 strcpy(windowTitle, _title);
00117
00118 fillMode = WIRE_MODE;
00119 projectionMode = PARALLEL_MODE;
00120 portWindow(0) = -1.0; portWindow(1) = 1.0;
00121 portWindow(2) = -1.0; portWindow(3) = 1.0;
00122
00123 theDevice = new OpenGlDevice();
00124 if (bitmapFileName == 0)
00125 theDevice->WINOPEN(_title, _xLoc, _yLoc, _width, _height);
00126 else
00127 theDevice->BITMAPOPEN(_title, _xLoc, _yLoc, _width, _height, bitmapFileName);
00128
00129 theDevice->CLEAR();
00130
00131
00132
00133 if (outputFileName != 0) {
00134 windowTitle = new char [strlen(_title)+1];
00135 theOutputFileName = new char [strlen(outputFileName)+1];
00136
00137 strcpy(windowTitle, _title);
00138 strcpy(theOutputFileName, outputFileName);
00139
00140 theFile.open(outputFileName, ios::out);
00141 if (theFile.bad()) {
00142 g3ErrorHandler->warning("WARNING - OpenGLRenderer::OpenGLRenderer() - could not open file %s\n",outputFileName);
00143 theOutputFileName = 0;
00144 } else {
00145 theFile << windowTitle << endl;
00146 theFile << xLoc << " " << yLoc << " " << width << " " << height << endl;
00147 }
00148 }
00149
00150 theDevice->CLEAR();
00151 glClearColor(1.0f,1.0f,1.0f,1.0f);
00152
00153 glEnable(GL_DEPTH_TEST);
00154 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00155
00156 glFlush();
00157 theDevice->ENDIMAGE();
00158 }
00159
00160 OpenGLRenderer::~OpenGLRenderer()
00161 {
00162 if (theDevice != 0)
00163 delete theDevice;
00164
00165 if (theOutputFileName != 0)
00166 theFile.close();
00167 }
00168
00169
00170 int
00171 OpenGLRenderer::clearImage(void)
00172 {
00173 theDevice->CLEAR();
00174 glClearColor(1.0f,1.0f,1.0f,1.0f);
00175
00176 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00177
00178 glFlush();
00179 theDevice->ENDIMAGE();
00180 return 0;
00181 }
00182
00183 int
00184 OpenGLRenderer::startImage(void)
00185 {
00186 theMap->startImage();
00187
00188 theDevice->STARTIMAGE();
00189
00190 if (fillMode == WIRE_MODE) {
00191 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
00192 } else {
00193 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00194 }
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205 static Vector u(3), v(3), n(3);
00206
00207
00208 static Vector vpnCopy(3);
00209
00210 if (vpn(0) == 0.0 && vpn(1) == 0.0 && vpn(2) == 0.0) {
00211 vpnCopy(0) = cop(0) - vrp(0);
00212 vpnCopy(1) = cop(1) - vrp(1);
00213 vpnCopy(2) = cop(2) - vrp(2);
00214 } else {
00215 vpnCopy(0) = vpn(0);
00216 vpnCopy(1) = vpn(1);
00217 vpnCopy(2) = vpn(2);
00218 }
00219
00220 for (int i=0; i<3; i++) {
00221 n(i) = vpnCopy(i);
00222 v(i) = vuv(i);
00223 }
00224
00225 if (n.Normalize() == 0) {
00226 cerr << "View::update() - VPN cannot have zero length\n";
00227 return -1;
00228 }
00229
00230
00231 u(0) = v(1)*n(2) - v(2)*n(1) ;
00232 u(1) = v(2)*n(0) - v(0)*n(2) ;
00233 u(2) = v(0)*n(1) - v(1)*n(0) ;
00234
00235 if (u.Normalize() == 0) {
00236 cerr << "View::update() - VUV X VPN cannot have zero length\n";
00237 return -1;
00238 }
00239
00240
00241 v(0) = n(1)*u(2) - n(2)*u(1) ;
00242 v(1) = n(2)*u(0) - n(0)*u(2) ;
00243 v(2) = n(0)*u(1) - n(1)*u(0) ;
00244
00245 v.Normalize();
00246
00247 ViewMat(0,0) = u(0); ViewMat(0,1) = u(1); ViewMat(0,2) = u(2); ViewMat(0,3) = -(vrp^u);
00248 ViewMat(1,0) = v(0); ViewMat(1,1) = v(1); ViewMat(1,2) = v(2); ViewMat(1,3) = -(vrp^v);
00249 ViewMat(2,0) = n(0); ViewMat(2,1) = n(1); ViewMat(2,2) = n(2); ViewMat(2,3) = -(vrp^n);
00250 ViewMat(3,0) = 0.0; ViewMat(3,1) = 0.0; ViewMat(3,2) = 0.0; ViewMat(3,3) = 1.0;
00251
00252 for (int j=0; j<4; j++)
00253 for (int k=0; k<4; k++)
00254 viewData[j+k*4] = ViewMat(j,k);
00255
00256 glMatrixMode(GL_MODELVIEW);
00257 glLoadMatrixf(viewData);
00258
00259
00260
00261
00262
00263 float midU, midV, dopU, dopV, dopN, shU, shV, F, B;
00264 midU = (vpWindow(0) + vpWindow(1))/2;
00265 midV = (vpWindow(2) + vpWindow(3))/2;
00266
00267
00268 float PRPu = u(0)*cop(0) + u(1)*cop(1) + u(2)*cop(2) + ViewMat(0,3);
00269 float PRPv = v(0)*cop(0) + v(1)*cop(1) + v(2)*cop(2) + ViewMat(1,3);
00270 float PRPn = n(0)*cop(0) + n(1)*cop(1) + n(2)*cop(2) + ViewMat(2,3);
00271
00272 float diffU, diffV;
00273
00274 diffU = vpWindow(1)-vpWindow(0);
00275 diffV = vpWindow(3)-vpWindow(2);
00276
00277 dopU = midU - PRPu;
00278 dopV = midV - PRPv;
00279 dopN = -PRPn;
00280
00281 shU = dopU/dopN;
00282 shV = dopV/dopN;
00283 F = clippingPlanes[0];
00284 B = clippingPlanes[1];
00285
00286
00287
00288
00289
00290
00291
00292 if (projectionMode == PARALLEL_MODE) {
00293
00294 ProjMat(0,0) = 2.0/diffU; ProjMat(0,1) = 0.0; ProjMat(0,2) = 2.0*shU/diffU;
00295 ProjMat(0,3) = -2*midU/diffU,
00296
00297 ProjMat(1,0) = 0.0; ProjMat(1,1) = 2/diffV; ProjMat(1,2) = 2*shV/diffV;
00298 ProjMat(1,3) = -2*midV/diffV;
00299
00300 ProjMat(2,0) = 0.0; ProjMat(2,1) = 0.0; ProjMat(2,2) = 1.0; ProjMat(2,3) = 0.0;
00301 ProjMat(3,0) = 0.0; ProjMat(3,1) = 0.0; ProjMat(3,2) = 0.0; ProjMat(3,3) = 1.0;
00302
00303 for (int jj=0; jj<4; jj++)
00304 for (int kk=0; kk<4; kk++)
00305 projData[jj+kk*4] = ProjMat(jj,kk);
00306
00307 glMatrixMode(GL_PROJECTION);
00308 glLoadMatrixf(projData);
00309 glOrtho(-1.0, 1.0, -1.0, 1.0, -F, -B);
00310
00311 } else {
00312
00313 double VRPn = -PRPn;
00314 float near2 = PRPn-F;
00315 float far2 = PRPn-B;
00316 float zMin = near2/far2;
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344 glMatrixMode(GL_MODELVIEW);
00345 glLoadIdentity();
00346 gluLookAt(cop(0),cop(1),cop(2),vrp(0),vrp(1),vrp(2),vuv(0),vuv(1),vuv(2));
00347
00348 glMatrixMode(GL_PROJECTION);
00349 float left = near2*diffU/VRPn/2;
00350 float bottom = near2*diffV/VRPn/2;
00351 float right = -left;
00352 float top = -bottom;
00353 glLoadIdentity();
00354 glFrustum(left,right,bottom,top,near2,far2);
00355
00356 }
00357
00358 int xMin = floor((portWindow(0)+1) * width/2.0);
00359 int xDiff = floor((portWindow(1)-portWindow(0)) * width/2.0);
00360 int yMin = floor((portWindow(2)+1) * height/2.0);
00361 int yDiff = floor((portWindow(3)-portWindow(2)) * height/2.0);
00362
00363 glViewport((GLsizei) xMin, (GLsizei) yMin, (GLsizei) xDiff, (GLsizei) yDiff);
00364
00365 if (theOutputFileName != 0) {
00366 theFile << "StartImage\n";
00367 theFile << "VRP " << vrp(0) << " " << vrp(1) << " "
00368 << vrp(2) << " " << endl;
00369 theFile << "VPN " << vpn(0) << " " << vpn(1) << " "
00370 << vpn(2) << " " << endl;
00371 theFile << "VUV " << vuv(0) << " " << vuv(1) << " "
00372 << vuv(2) << " " << endl;
00373 theFile << "COP " << cop(0) << " " << cop(1) << " "
00374 << cop(2) << " " << endl;
00375
00376 theFile << "PROJECTIONMODE " << projectionMode << endl;
00377 theFile << "VPWINDOW " << vpWindow(0) << " " << vpWindow(1) << " "
00378 << vpWindow(2) << " " << vpWindow(3) << " " << endl;
00379 theFile << "PLANES " << clippingPlanes[0] << " " << clippingPlanes[1] << "\n";
00380 theFile << "PORTWINDOW " << portWindow(0) << " " << portWindow(1) << " "
00381 << portWindow(2) << " " << portWindow(3) << " " << endl;
00382 }
00383
00384
00385 return 0;
00386 }
00387
00388
00389 int
00390 OpenGLRenderer::doneImage(void)
00391 {
00392 if (theOutputFileName != 0) {
00393 theFile << "DoneImage\n";
00394 }
00395
00396 if (count != -1) {
00397 count++;
00398 }
00399
00400 theDevice->ENDIMAGE();
00401 return 0;
00402 }
00403
00404 int
00405 OpenGLRenderer::drawPoint(const Vector &pos1, float V1, int numPixels)
00406 {
00407 glPointSize(numPixels);
00408
00409 glBegin(GL_POINTS);
00410 float r, g, b;
00411
00412 theMap->getRGB(V1, r, g, b);
00413 glColor3f(r,g,b);
00414 glVertex3f(pos1(0),pos1(1),pos1(2));
00415
00416 if (theOutputFileName != 0) {
00417 theFile << "Point\n" << pos1(0) << " " << pos1(1) << " " << pos1(2)
00418 << " " << r << " " << g << " " << b << " " << endl;
00419 }
00420
00421 glEnd();
00422
00423 return 0;
00424 }
00425
00426
00427 int
00428 OpenGLRenderer::drawPoint(const Vector &pos1, const Vector &rgb, int numPixels)
00429 {
00430 glPointSize(numPixels);
00431
00432 glBegin(GL_POINTS);
00433 float r, g, b;
00434 r = rgb(0);
00435 g = rgb(1);
00436 b = rgb(2);
00437
00438 glColor3f(r,g,b);
00439 glVertex3f(pos1(0),pos1(1),pos1(2));
00440
00441 if (theOutputFileName != 0) {
00442 theFile << "Point\n" << pos1(0) << " " << pos1(1) << " " << pos1(2)
00443 << " " << r << " " << g << " " << b << " " << endl;
00444 }
00445
00446 glEnd();
00447
00448 return 0;
00449 }
00450
00451
00452
00453 int
00454 OpenGLRenderer::drawLine(const Vector &pos1, const Vector &pos2,
00455 float V1, float V2, int width, int style)
00456 {
00457
00458 if (pos1(0) == pos2(0) && pos1(1) == pos2(1) && pos1(2) == pos2(2))
00459 return 0;
00460
00461 glLineWidth(width);
00462
00463 glBegin(GL_LINES);
00464 float r, g, b;
00465
00466 theMap->getRGB(V1, r, g, b);
00467 glColor3f(r,g,b);
00468
00469 glVertex3f(pos1(0),pos1(1),pos1(2));
00470
00471 if (theOutputFileName != 0) {
00472 theFile << "Line\n" << pos1(0) << " " << pos1(1) << " " << pos1(2)
00473 << " " << r << " " << g << " " << b << " " << endl;
00474 }
00475
00476 theMap->getRGB(V2, r, g, b);
00477 glColor3f(r,g,b);
00478
00479 glVertex3f(pos2(0),pos2(1),pos2(2));
00480 glEnd();
00481
00482 if (theOutputFileName != 0) {
00483 theFile << pos2(0) << " " << pos2(1) << " " << pos2(2) << " " << r
00484 << " " << g << " " << b << " " << endl;
00485 }
00486
00487 return 0;
00488 }
00489
00490
00491
00492 int
00493 OpenGLRenderer::drawLine(const Vector &end1, const Vector &end2,
00494 const Vector &rgb1, const Vector &rgb2,
00495 int width, int style)
00496 {
00497
00498 if (end1(0) == end2(0) && end1(1) == end2(1) && end1(2) == end2(2))
00499 return 0;
00500
00501 glLineWidth(width);
00502
00503 glBegin(GL_LINES);
00504 float r, g, b;
00505 r = rgb1(0);
00506 g = rgb1(1);
00507 b = rgb1(2);
00508
00509 if (theOutputFileName != 0) {
00510 theFile << "Line\n" << end1(0) << " " << end1(1) << " " << end1(2)
00511 << " " << r << " " << g << " " << b << " " << endl;
00512 }
00513 glColor3f(r,g,b);
00514 glVertex3f(end1(0),end1(1),end1(2));
00515
00516 r = rgb2(0);
00517 g = rgb2(1);
00518 b = rgb2(2);
00519
00520 if (theOutputFileName != 0) {
00521 theFile << end2(0) << " " << end2(1) << " " << end2(2) << " " << r
00522 << " " << g << " " << b << " " << endl;
00523 }
00524 glColor3f(r,g,b);
00525
00526 glVertex3f(end2(0),end2(1),end2(2));
00527 glEnd();
00528
00529 return 0;
00530 }
00531
00532
00533
00534 int
00535 OpenGLRenderer::drawPolygon(const Matrix &pos, const Vector &data)
00536
00537 {
00538 #ifdef _G3DEBUG
00539 if (pos.noCols() != 3) {
00540 g3ErrorHandler->warning("OpenGLRenderer::drawPolygon - matrix needs 3 cols\n");
00541 return -1;
00542 }
00543 if (pos.noRows() != data.Size()) {
00544 g3ErrorHandler->warning("OpenGLRenderer::drawPolygon - matrix & vector incompatable\n");
00545 return -1;
00546 }
00547 #endif
00548
00549 double posX, posY, posZ, value;
00550 float r,g,b;
00551
00552 glBegin(GL_POLYGON);
00553 int numRows = pos.noRows();
00554 for (int i=0; i<numRows; i++) {
00555 posX = pos(i,0);
00556 posY = pos(i,1);
00557 posZ = pos(i,2);
00558 value = data(i);
00559 theMap->getRGB(value, r, g, b);
00560
00561 cerr << value << " RGB " << r << " " << g << " " << b << endl;
00562
00563 if (theOutputFileName != 0) {
00564 theFile << posX << " " << posY << " " << posZ << " " << r
00565 << " " << g << " " << b << " " << endl;
00566 }
00567 glColor3f(r,g,b);
00568 glVertex3f(posX, posY, posZ);
00569 }
00570
00571 glEnd();
00572
00573 return 0;
00574 }
00575
00576
00577 int
00578 OpenGLRenderer::drawPolygon(const Matrix &pos, const Matrix &rgbData)
00579
00580 {
00581 #ifdef _G3DEBUG
00582 if (pos.noCols() != 3 || rgbData.noCols() != 3) {
00583 g3ErrorHandler->warning("OpenGLRenderer::drawPolygon - matrix needs 3 cols\n");
00584 return -1;
00585 }
00586 if (pos.noRows() != rgbData.noRows()) {
00587 g3ErrorHandler->warning("OpenGLRenderer::drawPolygon - matrix & vector incompatable\n");
00588 return -1;
00589 }
00590 #endif
00591
00592 double posX, posY, posZ;
00593 float r,g,b;
00594
00595 glBegin(GL_POLYGON);
00596 int numRows = pos.noRows();
00597 for (int i=0; i<numRows; i++) {
00598 posX = pos(i,0);
00599 posY = pos(i,1);
00600 posZ = pos(i,2);
00601 r = rgbData(i,0);
00602 g = rgbData(i,1);
00603 b = rgbData(i,2);
00604
00605 if (theOutputFileName != 0) {
00606 theFile << posX << " " << posY << " " << posZ << " " << r
00607 << " " << g << " " << b << " " << endl;
00608 }
00609 glColor3f(r,g,b);
00610 glVertex3f(posX, posY, posZ);
00611 }
00612
00613 glEnd();
00614
00615 return 0;
00616 }
00617
00618
00619
00620 int
00621 OpenGLRenderer::drawText(const Vector &pos, char *text, int length,
00622 char horizontalJustify, char verticalJustify)
00623 {
00624
00625 int size = pos.Size();
00626 float x,y,z;
00627 if (size == 1) {
00628 x = pos(0);
00629 y = 0;
00630 z = 0;
00631 } else if (size == 2) {
00632 x = pos(0);
00633 y = pos(1);
00634 z = 0;
00635 } else {
00636 x = pos(0);
00637 y = pos(1);
00638 z = pos(2);
00639 }
00640
00641 theDevice->drawText(x,y,z, text, length, horizontalJustify, verticalJustify);
00642
00643 return 0;
00644 }
00645
00646 int
00647 OpenGLRenderer::setVRP(float x, float y, float z)
00648 {
00649 vrp(0) = x;
00650 vrp(1) = y;
00651 vrp(2) = z;
00652
00653 return 0;
00654 }
00655
00656 int
00657 OpenGLRenderer::setVPN(float x, float y, float z)
00658 {
00659 vpn(0) = x;
00660 vpn(1) = y;
00661 vpn(2) = z;
00662
00663 return 0;
00664 }
00665
00666 int
00667 OpenGLRenderer::setVUP(float x, float y, float z)
00668 {
00669 vuv(0) = x;
00670 vuv(1) = y;
00671 vuv(2) = z;
00672
00673 return 0;
00674 }
00675
00676 int
00677 OpenGLRenderer::setViewWindow(float umin, float umax, float vmin, float vmax)
00678 {
00679 if (umin > umax || vmin > vmax) {
00680 cerr << "OpenGLRenderer::setViewWindow() - invalid window ";
00681 cerr << umin << " "<< umax << " "<< vmin << " "<< vmax << endl;
00682 return -1;
00683 }
00684
00685 vpWindow(0) = umin;
00686 vpWindow(1) = umax;
00687 vpWindow(2) = vmin;
00688 vpWindow(3) = vmax;
00689
00690 return 0;
00691 }
00692
00693 int
00694 OpenGLRenderer::setPlaneDist(float anear, float afar)
00695 {
00696 if ((anear < afar)) {
00697 cerr << "OpenGLRenderer::setClippingPlanes() - invalid planes";
00698 cerr << anear << " " << afar << endl;
00699 return -1;
00700 }
00701
00702 clippingPlanes[0] = anear;
00703 clippingPlanes[1] = afar;
00704
00705 return 0;
00706 }
00707
00708 int
00709 OpenGLRenderer::setProjectionMode(char *newMode)
00710 {
00711 if ((strcmp(newMode, "parallel") == 0) || (strcmp(newMode, "Parallel") == 0))
00712 projectionMode = PARALLEL_MODE;
00713 else if ((strcmp(newMode, "perspective") == 0) || (strcmp(newMode, "Perspective") == 0))
00714 projectionMode = PERSPECTIVE_MODE;
00715 return 0;
00716 }
00717
00718 int
00719 OpenGLRenderer::setFillMode(char *newMode)
00720 {
00721 if ((strcmp(newMode, "wire") == 0) || (strcmp(newMode, "Wire") == 0))
00722 fillMode = WIRE_MODE;
00723 else if ((strcmp(newMode, "fill") == 0) || (strcmp(newMode, "Fill") == 0))
00724 fillMode = FILL_MODE;
00725
00726 return 0;
00727 }
00728
00729
00730 int
00731 OpenGLRenderer::setPRP(float u, float v, float n){
00732 cop(0) = u;
00733 cop(1) = v;
00734 cop(2) = n;
00735
00736 return 0;
00737 }
00738
00739 int
00740 OpenGLRenderer::setPortWindow(float left, float right,
00741 float bottom, float top)
00742 {
00743 if (left < -1 || right > 1 || bottom < -1 || top > 1
00744 || left > right || bottom > top) {
00745
00746 cerr << "OpenGLRenderer::setPortWindow() - bounds invalid ";
00747 cerr << left << " "<< right << " "<< bottom << " "<< top << endl;
00748 return -1;
00749 }
00750
00751 portWindow(0) = left;
00752 portWindow(1) = right;
00753 portWindow(2) = bottom;
00754 portWindow(3) = top;
00755
00756 return 0;
00757 }
00758