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
00038 #include "Teddy/Graphics/PsRenderer.h"
00039 #include "Teddy/SysSupport/StdMaths.h"
00040 #include <cassert>
00041 #include <algorithm>
00042 using namespace Teddy::SysSupport;
00043
00044
00045 namespace Teddy {
00046 namespace Graphics {
00047
00048
00049 #define EPS_SMOOTH_LINE_FACTOR 0.06
00050 #define EPS_GOURAUD_THRESHOLD 0.05
00051 #define EPS_LINE_WIDTH 0.1
00052
00053
00054
00055 struct Feedback3Dcolor {
00056 GLfloat x;
00057 GLfloat y;
00058 GLfloat z;
00059 GLfloat red;
00060 GLfloat green;
00061 GLfloat blue;
00062 GLfloat alpha;
00063 };
00064
00065
00066 static char *NicegouraudtriangleEPS[] = {
00067 "\n% Smooth-shaded triangle - x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 ST",
00068 "/ST {",
00069 " /b1 exch def",
00070 " /g1 exch def",
00071 " /r1 exch def",
00072 " /y1 exch def",
00073 " /x1 exch def",
00074 " /b2 exch def",
00075 " /g2 exch def",
00076 " /r2 exch def",
00077 " /y2 exch def",
00078 " /x2 exch def",
00079 " /b3 exch def",
00080 " /g3 exch def",
00081 " /r3 exch def",
00082 " /y3 exch def",
00083 " /x3 exch def",
00084 " b2 b1 sub abs 0.05 gt",
00085 " g2 g1 sub abs 0.017 gt",
00086 " r2 r1 sub abs 0.032 gt",
00087 " b3 b1 sub abs 0.05 gt",
00088 " g3 g1 sub abs 0.017 gt",
00089 " r3 r1 sub abs 0.032 gt",
00090 " b2 b3 sub abs 0.05 gt",
00091 " g2 g3 sub abs 0.017 gt",
00092 " r2 r3 sub abs 0.032 gt",
00093 " or or or or or or or or {",
00094 " /b12 b1 b2 add 0.5 mul def",
00095 " /g12 g1 g2 add 0.5 mul def",
00096 " /r12 r1 r2 add 0.5 mul def",
00097 " /y12 y1 y2 add 0.5 mul def",
00098 " /x12 x1 x2 add 0.5 mul def",
00099 " /b13 b1 b3 add 0.5 mul def",
00100 " /g13 g1 g3 add 0.5 mul def",
00101 " /r13 r1 r3 add 0.5 mul def",
00102 " /y13 y1 y3 add 0.5 mul def",
00103 " /x13 x1 x3 add 0.5 mul def",
00104 " /b32 b3 b2 add 0.5 mul def",
00105 " /g32 g3 g2 add 0.5 mul def",
00106 " /r32 r3 r2 add 0.5 mul def",
00107 " /y32 y3 y2 add 0.5 mul def",
00108 " /x32 x3 x2 add 0.5 mul def",
00109 " x1 y1 r1 g1 b1 x12 y12 r12 g12 b12 x13 y13 r13 g13 b13",
00110 " x2 y2 r2 g2 b2 x12 y12 r12 g12 b12 x32 y32 r32 g32 b32",
00111 " x3 y3 r3 g3 b3 x32 y32 r32 g32 b32 x13 y13 r13 g13 b13",
00112 " x32 y32 r32 g32 b32 x12 y12 r12 g12 b12 x13 y13 r13 g13 b13",
00113 " ST ST ST ST",
00114 " } {",
00115 " x1 y1 x2 y2 x3 y3 r1 g1 b1 T",
00116 " } ifelse",
00117 "} bind def"
00118 "\n",
00119 NULL
00120 };
00121
00122
00123 static char *gouraudtriangleEPS[] ={
00124 "/bd{bind def}bind def /triangle { aload pop setrgbcolor aload pop 5 3",
00125 "roll 4 2 roll 3 2 roll exch moveto lineto lineto closepath fill } bd",
00126 "/computediff1 { 2 copy sub abs threshold ge {pop pop pop true} { exch 2",
00127 "index sub abs threshold ge { pop pop true} { sub abs threshold ge } ifelse",
00128 "} ifelse } bd /computediff3 { 3 copy 0 get 3 1 roll 0 get 3 1 roll 0 get",
00129 "computediff1 {true} { 3 copy 1 get 3 1 roll 1 get 3 1 roll 1 get",
00130 "computediff1 {true} { 3 copy 2 get 3 1 roll 2 get 3 1 roll 2 get",
00131 "computediff1 } ifelse } ifelse } bd /middlecolor { aload pop 4 -1 roll",
00132 "aload pop 4 -1 roll add 2 div 5 1 roll 3 -1 roll add 2 div 3 1 roll add 2",
00133 "div 3 1 roll exch 3 array astore } bd /gouraudtriangle { computediff3 { 4",
00134 "-1 roll aload 7 1 roll 6 -1 roll pop 3 -1 roll pop add 2 div 3 1 roll add",
00135 "2 div exch 3 -1 roll aload 7 1 roll exch pop 4 -1 roll pop add 2 div 3 1",
00136 "roll add 2 div exch 3 -1 roll aload 7 1 roll pop 3 -1 roll pop add 2 div 3",
00137 "1 roll add 2 div exch 7 3 roll 10 -3 roll dup 3 index middlecolor 4 1 roll",
00138 "2 copy middlecolor 4 1 roll 3 copy pop middlecolor 4 1 roll 13 -1 roll",
00139 "aload pop 17 index 6 index 15 index 19 index 6 index 17 index 6 array",
00140 "astore 10 index 10 index 14 index gouraudtriangle 17 index 5 index 17",
00141 "index 19 index 5 index 19 index 6 array astore 10 index 9 index 13 index",
00142 "gouraudtriangle 13 index 16 index 5 index 15 index 18 index 5 index 6",
00143 "array astore 12 index 12 index 9 index gouraudtriangle 17 index 16 index",
00144 "15 index 19 index 18 index 17 index 6 array astore 10 index 12 index 14",
00145 "index gouraudtriangle 18 {pop} repeat } { aload pop 5 3 roll aload pop 7 3",
00146 "roll aload pop 9 3 roll 8 index 6 index 4 index add add 3 div 10 1 roll 7",
00147 "index 5 index 3 index add add 3 div 10 1 roll 6 index 4 index 2 index add",
00148 "add 3 div 10 1 roll 9 {pop} repeat 3 array astore triangle } ifelse } bd",
00149 NULL
00150 };
00151
00152
00153
00154 void PsRenderer::writePs( char *pFilename, GLfloat *pFeedbackBuffer, int NbValues, bool sort ){
00155 assert( pFilename );
00156
00157 FILE *pFile = fopen( pFilename, "wt" );
00158 if( !pFile ){
00159 return;
00160 }
00161
00162 spewWireFrameEPS( pFile, sort, NbValues, pFeedbackBuffer );
00163 fclose( pFile );
00164 }
00165
00166
00167 GLfloat *PsRenderer::spewPrimitiveEPS( FILE *file, GLfloat *loc ){
00168 int token;
00169 int nvertices, i;
00170 GLfloat red, green, blue;
00171 int smooth;
00172 GLfloat dx, dy, dr, dg, db, absR, absG, absB, colormax;
00173 int steps;
00174 Feedback3Dcolor *vertex;
00175 GLfloat xstep, ystep, rstep, gstep, bstep;
00176 GLfloat xnext, ynext, rnext, gnext, bnext, distance;
00177
00178 token = (int)*loc;
00179 loc++;
00180 switch( token ){
00181 case GL_LINE_RESET_TOKEN:
00182 case GL_LINE_TOKEN:
00183 vertex = (Feedback3Dcolor *) loc;
00184
00185 dr = vertex[1].red - vertex[0].red;
00186 dg = vertex[1].green - vertex[0].green;
00187 db = vertex[1].blue - vertex[0].blue;
00188
00189 if( dr != 0 || dg != 0 || db != 0 ){
00190
00191 dx = vertex[1].x - vertex[0].x;
00192 dy = vertex[1].y - vertex[0].y;
00193 distance = (float)sqrt(dx * dx + dy * dy);
00194
00195 absR = (float)fabs( dr );
00196 absG = (float)fabs( dg );
00197 absB = (float)fabs( db );
00198
00199 colormax = MAX( absR, MAX(absG, absB) );
00200 steps = (int)MAX( 1.0, colormax * distance * EPS_SMOOTH_LINE_FACTOR );
00201
00202 xstep = dx / steps;
00203 ystep = dy / steps;
00204
00205 rstep = dr / steps;
00206 gstep = dg / steps;
00207 bstep = db / steps;
00208
00209 xnext = vertex[0].x;
00210 ynext = vertex[0].y;
00211 rnext = vertex[0].red;
00212 gnext = vertex[0].green;
00213 bnext = vertex[0].blue;
00214
00215
00216
00217 xnext -= (float)xstep / 2.0f;
00218 ynext -= (float)ystep / 2.0f;
00219 rnext -= (float)rstep / 2.0f;
00220 gnext -= (float)gstep / 2.0f;
00221 bnext -= (float)bstep / 2.0f;
00222
00223 fprintf( file, "%g %g %g setrgbcolor\n", vertex[0].red, vertex[0].green, vertex[0].blue );
00224 fprintf( file, "%g %g moveto\n", vertex[0].x, vertex[0].y );
00225
00226 for( i = 0; i < steps; i++ ){
00227 xnext += xstep;
00228 ynext += ystep;
00229 rnext += rstep;
00230 gnext += gstep;
00231 bnext += bstep;
00232 fprintf( file, "%g %g lineto stroke\n", xnext, ynext );
00233 fprintf( file, "%g %g %g setrgbcolor\n", rnext, gnext, bnext );
00234 fprintf( file, "%g %g moveto\n", xnext, ynext);
00235 }
00236 fprintf( file, "%g %g lineto stroke\n", vertex[1].x, vertex[1].y );
00237 }else{
00238 fprintf( file, "%g %g %g %g %g %g %g S\n",vertex[1].x,vertex[1].y, vertex[0].x,vertex[0].y,vertex[0].red, vertex[0].green, vertex[0].blue );
00239 }
00240
00241 loc += 14;
00242
00243 break;
00244
00245 case GL_POLYGON_TOKEN:
00246 nvertices = (int)*loc;
00247 loc++;
00248
00249 vertex = (Feedback3Dcolor *) loc;
00250
00251 if( nvertices > 0 ){
00252 red = vertex[0].red;
00253 green = vertex[0].green;
00254 blue = vertex[0].blue;
00255 smooth = 0;
00256 for( i=1; i<nvertices; i++ ){
00257 if (red != vertex[i].red || green != vertex[i].green || blue != vertex[i].blue ){
00258 smooth = 1;
00259 break;
00260 }
00261 }
00262 if( smooth ){
00263
00264 int triOffset;
00265
00266
00267 for( i=0; i<nvertices - 2; i++ ){
00268 triOffset = i * 7;
00269
00270 fprintf(file, "[%g %g %g %g %g %g]", vertex[0].x, vertex[i + 1].x, vertex[i + 2].x, vertex[0].y, vertex[i + 1].y, vertex[i + 2].y );
00271 fprintf(file, " [%g %g %g] [%g %g %g] [%g %g %g] gouraudtriangle\n", vertex[0].red, vertex[0].green, vertex[0].blue, vertex[i + 1].red, vertex[i + 1].green, vertex[i + 1].blue, vertex[i + 2].red, vertex[i + 2].green, vertex[i + 2].blue );
00272
00273
00274
00275
00276
00277
00278 }
00279 }else{
00280 if( nvertices > 3 ){
00281
00282 fprintf( file, "newpath\n" );
00283 fprintf( file, "%g %g %g setrgbcolor\n", red, green, blue );
00284 fprintf( file, "%g %g moveto\n", vertex[0].x, vertex[0].y);
00285 for( i=1; i<nvertices; i++){
00286 fprintf( file, "%g %g lineto\n", vertex[i].x, vertex[i].y );
00287 }
00288 fprintf( file, "closepath fill\n\n" );
00289 }else{
00290 fprintf(file,"%g %g %g %g %g %g %g %g %g T\n", vertex[2].x,vertex[2].y, vertex[1].x,vertex[1].y, vertex[0].x,vertex[0].y, red,green,blue );
00291 }
00292 }
00293 }
00294 loc += nvertices * 7;
00295 break;
00296
00297 case GL_POINT_TOKEN:
00298 vertex = (Feedback3Dcolor *) loc;
00299 fprintf(file, "%g %g %g 0 360 %g %g %g P\n",vertex[0].x, vertex[0].y, m_PointSize / 2.0,vertex[0].red,vertex[0].green,vertex[0].blue );
00300 loc += 7;
00301 break;
00302 default:
00303
00304
00305
00306 break;
00307 }
00308 return loc;
00309 }
00310
00311 void PsRenderer::spewUnsortedFeedback( FILE *file, GLint size, GLfloat * buffer ){
00312 GLfloat *loc, *end;
00313
00314 loc = buffer;
00315 end = buffer + size;
00316 while( loc < end ){
00317 loc = spewPrimitiveEPS( file, loc );
00318 }
00319 }
00320
00321
00322 int PsRenderer::compare( const void *a, const void *b ){
00323 DepthIndex *p1 = (DepthIndex *) a;
00324 DepthIndex *p2 = (DepthIndex *) b;
00325 GLfloat diff = p2->depth - p1->depth;
00326
00327 if( diff > 0.0 ){
00328 return 1;
00329 }else if( diff < 0.0 ){
00330 return -1;
00331 }else{
00332 return 0;
00333 }
00334 }
00335
00336
00337 void PsRenderer::spewSortedFeedback( FILE *file, GLint size, GLfloat *buffer ){
00338 int token;
00339 GLfloat *loc, *end;
00340 Feedback3Dcolor *vertex;
00341 GLfloat depthSum;
00342 int nprimitives, item;
00343 DepthIndex *prims;
00344 int nvertices, i;
00345
00346 end = buffer + size;
00347
00348
00349 nprimitives = 0;
00350 loc = buffer;
00351 while( loc < end ){
00352 token = (int)*loc;
00353 loc++;
00354 switch( token ){
00355 case GL_LINE_TOKEN:
00356 case GL_LINE_RESET_TOKEN:
00357 loc += 14;
00358 nprimitives++;
00359 break;
00360 case GL_POLYGON_TOKEN:
00361 nvertices = (int)*loc;
00362 loc++;
00363 loc += (7 * nvertices);
00364 nprimitives++;
00365 break;
00366 case GL_POINT_TOKEN:
00367 loc += 7;
00368 nprimitives++;
00369 break;
00370 default:
00371
00372
00373
00374 break;
00375 }
00376 }
00377
00378
00379
00380
00381
00382
00383 prims = new DepthIndex[nprimitives];
00384
00385 item = 0;
00386 loc = buffer;
00387 while( loc < end ){
00388 prims[item].ptr = loc;
00389 token = (int)*loc;
00390 loc++;
00391 switch( token ){
00392 case GL_LINE_TOKEN:
00393 case GL_LINE_RESET_TOKEN:
00394 vertex = (Feedback3Dcolor *) loc;
00395 depthSum = vertex[0].z + vertex[1].z;
00396 prims[item].depth = (float)depthSum / 2.0f;
00397 loc += 14;
00398 break;
00399 case GL_POLYGON_TOKEN:
00400 nvertices = (int)*loc;
00401 loc++;
00402 vertex = (Feedback3Dcolor *) loc;
00403 depthSum = vertex[0].z;
00404 for( i=1; i<nvertices; i++ ){
00405 depthSum += vertex[i].z;
00406 }
00407 prims[item].depth = depthSum / nvertices;
00408 loc += (7 * nvertices);
00409 break;
00410 case GL_POINT_TOKEN:
00411 vertex = (Feedback3Dcolor *) loc;
00412 prims[item].depth = vertex[0].z;
00413 loc += 7;
00414 break;
00415 default:
00416
00417
00418 break;
00419 }
00420 item++;
00421 }
00422 assert( item == nprimitives );
00423
00424
00425 qsort( prims, nprimitives, sizeof(DepthIndex), compare );
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435 for( item=0; item<nprimitives; item++ ){
00436 (void) spewPrimitiveEPS( file, prims[item].ptr );
00437 }
00438
00439 delete[] prims;
00440 }
00441
00442
00443 void PsRenderer::spewWireFrameEPS( FILE *file, bool doSort, GLint size, GLfloat *buffer ){
00444 GLfloat clearColor[4], viewport[4];
00445 GLfloat lineWidth;
00446
00447
00448
00449
00450 glGetFloatv( GL_VIEWPORT, viewport );
00451 glGetFloatv( GL_COLOR_CLEAR_VALUE, clearColor );
00452 glGetFloatv( GL_LINE_WIDTH, &lineWidth );
00453 glGetFloatv( GL_POINT_SIZE, &m_PointSize );
00454
00455
00456 fputs( "%!PS-Adobe-2.0 EPSF-2.0\n", file );
00457
00458 fprintf( file, "%%%%BoundingBox: %g %g %g %g\n", viewport[0], viewport[1], viewport[2], viewport[3] );
00459 fputs( "%%EndComments\n", file );
00460 fputs( "\n", file );
00461 fputs( "gsave\n", file );
00462 fputs( "\n", file );
00463
00464 fprintf( file, "/threshold %g def\n", EPS_GOURAUD_THRESHOLD );
00465
00466 fprintf( file, "\n%% RGB color command - r g b C\n" );
00467 fprintf( file, "/C { setrgbcolor } bind def\n" );
00468
00469
00470 fprintf( file, "\n%% Point - x_center y_center PointSize/2 0 360 r g b P\n" );
00471 fprintf( file, "/P { C arc fill } bind def\n" );
00472
00473 fprintf( file, "\n%% Segment - x2 y2 x1 y1 r g b S\n" );
00474 fprintf( file, "/S { C moveto lineto stroke } bind def\n" );
00475
00476 fprintf( file, "\n%% Flat-shaded triangle - x3 y3 x2 y2 x1 y1 r g b T\n" );
00477 fprintf( file, "/T { C newpath moveto lineto lineto closepath fill } bind def\n" );
00478
00479
00480 fputs( "% The gouraudtriangle PostScript fragement below is free\n", file );
00481 fputs( "% written by Frederic Delhoume (delhoume@ilog.fr)\n", file );
00482
00483 for( int i=0; gouraudtriangleEPS[i]; i++ ){
00484 fprintf( file, "%s\n", gouraudtriangleEPS[i] );
00485 }
00486
00487 fprintf( file, "\n%g setlinewidth\n", EPS_LINE_WIDTH );
00488
00489
00490 fprintf( file, "%g %g %g setrgbcolor\n", clearColor[0], clearColor[1], clearColor[2] );
00491 fprintf( file, "%g %g %g %g rectfill\n\n", viewport[0], viewport[1], viewport[2], viewport[3] );
00492
00493
00494 if( doSort ){
00495 spewSortedFeedback( file, size, buffer );
00496 }else{
00497 spewUnsortedFeedback( file, size, buffer );
00498 }
00499
00500
00501 fputs( "\ngrestore\n", file );
00502 fputs( "showpage\n", file );
00503
00504 }
00505
00506
00507 };
00508 };
00509