]> git.mxchange.org Git - simgear.git/blob - simgear/screen/tr.cxx
Patch from Melchior Franz:
[simgear.git] / simgear / screen / tr.cxx
1 /* $Id$ */
2
3 /*
4  * $Log$
5  * Revision 1.3  2001/07/30 20:34:21  curt
6  * Various MSVC fixes.
7  *
8  * Revision 1.2  2001/06/27 02:48:01  curt
9  * Fixed a type conversion bug that could trip up some of the pickier compilers
10  * out there.
11  *
12  * Revision 1.1  2001/06/26 15:19:39  curt
13  * Added tr.cxx / tr.h, Brian Paul's LGPL'd tiled rendering support libs for
14  * rendering ultra high res "tiled" screen shots.
15  *
16  * Revision 1.9  1998/01/29  16:56:54  brianp
17  * allow trOrtho() and trFrustum() to be called at any time, minor clean-up
18  *
19  * Revision 1.8  1998/01/28  19:47:39  brianp
20  * minor clean-up for C++
21  *
22  * Revision 1.7  1997/07/21  17:34:38  brianp
23  * added tile borders
24  *
25  * Revision 1.6  1997/07/21  15:47:35  brianp
26  * renamed all "near" and "far" variables
27  *
28  * Revision 1.5  1997/04/26  21:23:25  brianp
29  * added trRasterPos3f function
30  *
31  * Revision 1.4  1997/04/26  19:59:36  brianp
32  * set CurrentTile to -1 before first tile and after last tile
33  *
34  * Revision 1.3  1997/04/22  23:51:15  brianp
35  * added WIN32 header stuff, removed tabs
36  *
37  * Revision 1.2  1997/04/19  23:26:10  brianp
38  * many API changes
39  *
40  * Revision 1.1  1997/04/18  21:53:05  brianp
41  * Initial revision
42  *
43  */
44
45
46 /*
47  * Tiled Rendering library
48  * Version 1.1
49  * Copyright (C) Brian Paul
50  */
51
52
53 #include <simgear/compiler.h>
54
55 #include <assert.h>
56 #include <math.h>
57 #include <stdlib.h>
58 #include <stdio.h>
59 #ifdef WIN32
60 #include <windows.h>
61 #endif
62 #include <GL/gl.h>
63 #include <GL/glu.h>
64 #include <plib/ssg.h>
65 #include "tr.h"
66
67
68 #define DEFAULT_TILE_WIDTH  256
69 #define DEFAULT_TILE_HEIGHT 256
70 #define DEFAULT_TILE_BORDER 0
71
72
73 struct _TRctx {
74    /* Final image parameters */
75    GLint ImageWidth, ImageHeight;
76    GLenum ImageFormat, ImageType;
77    GLvoid *ImageBuffer;
78
79    /* Tile parameters */
80    GLint TileWidth, TileHeight;
81    GLint TileWidthNB, TileHeightNB;
82    GLint TileBorder;
83    GLenum TileFormat, TileType;
84    GLvoid *TileBuffer;
85
86    /* Projection parameters */
87    GLboolean Perspective;
88    GLdouble Left;
89    GLdouble Right;
90    GLdouble Bottom;
91    GLdouble Top;
92    GLdouble Near;
93    GLdouble Far;
94
95    /* Misc */
96    TRenum RowOrder;
97    GLint Rows, Columns;
98    GLint CurrentTile;
99    GLint CurrentTileWidth, CurrentTileHeight;
100    GLint CurrentRow, CurrentColumn;
101
102    GLint ViewportSave[4];
103 };
104
105
106
107 /*
108  * Misc setup including computing number of tiles (rows and columns).
109  */
110 static void Setup(TRcontext *tr)
111 {
112    if (!tr)
113       return;
114
115    tr->Columns = (tr->ImageWidth + tr->TileWidthNB - 1) / tr->TileWidthNB;
116    tr->Rows = (tr->ImageHeight + tr->TileHeightNB - 1) / tr->TileHeightNB;
117    tr->CurrentTile = 0;
118
119    assert(tr->Columns >= 0);
120    assert(tr->Rows >= 0);
121 }
122
123
124
125 TRcontext *trNew(void)
126 {
127    TRcontext *tr = (TRcontext *) calloc(1, sizeof(TRcontext));
128    if (tr) {
129       tr->TileWidth = DEFAULT_TILE_WIDTH;
130       tr->TileHeight = DEFAULT_TILE_HEIGHT;
131       tr->TileBorder = DEFAULT_TILE_BORDER;
132       tr->RowOrder = TR_BOTTOM_TO_TOP;
133       tr->CurrentTile = -1;
134    }
135    return (TRcontext *) tr;
136 }
137
138
139 void trDelete(TRcontext *tr)
140 {
141    if (tr)
142       free(tr);
143 }
144
145
146
147 void trTileSize(TRcontext *tr, GLint width, GLint height, GLint border)
148 {
149    if (!tr)
150       return;
151
152    assert(border >= 0);
153    assert(width >= 1);
154    assert(height >= 1);
155    assert(width >= 2*border);
156    assert(height >= 2*border);
157
158    tr->TileBorder = border;
159    tr->TileWidth = width;
160    tr->TileHeight = height;
161    tr->TileWidthNB = width - 2 * border;
162    tr->TileHeightNB = height - 2 * border;
163    Setup(tr);
164 }
165
166
167
168 void trTileBuffer(TRcontext *tr, GLenum format, GLenum type, GLvoid *image)
169 {
170    if (!tr)
171       return;
172
173    tr->TileFormat = format;
174    tr->TileType = type;
175    tr->TileBuffer = image;
176 }
177
178
179
180 void trImageSize(TRcontext *tr, GLint width, GLint height)
181 {
182    if (!tr)
183       return;
184
185    tr->ImageWidth = width;
186    tr->ImageHeight = height;
187    Setup(tr);
188 }
189
190
191 void trImageBuffer(TRcontext *tr, GLenum format, GLenum type, GLvoid *image)
192 {
193    if (!tr)
194       return;
195
196    tr->ImageFormat = format;
197    tr->ImageType = type;
198    tr->ImageBuffer = image;
199 }
200
201
202 GLint trGet(TRcontext *tr, TRenum param)
203 {
204    if (!tr)
205       return 0;
206    switch (param) {
207       case TR_TILE_WIDTH:
208          return tr->TileWidth;
209       case TR_TILE_HEIGHT:
210          return tr->TileHeight;
211       case TR_TILE_BORDER:
212          return tr->TileBorder;
213       case TR_IMAGE_WIDTH:
214          return tr->ImageWidth;
215       case TR_IMAGE_HEIGHT:
216          return tr->ImageHeight;
217       case TR_ROWS:
218          return tr->Rows;
219       case TR_COLUMNS:
220          return tr->Columns;
221       case TR_CURRENT_ROW:
222          if (tr->CurrentTile<0)
223             return -1;
224          else
225             return tr->CurrentRow;
226       case TR_CURRENT_COLUMN:
227          if (tr->CurrentTile<0)
228             return -1;
229          else
230             return tr->CurrentColumn;
231       case TR_CURRENT_TILE_WIDTH:
232          return tr->CurrentTileWidth;
233       case TR_CURRENT_TILE_HEIGHT:
234          return tr->CurrentTileHeight;
235       case TR_ROW_ORDER:
236          return (GLint) tr->RowOrder;
237       default:
238          return 0;
239    }
240 }
241
242 GLdouble trGetD(TRcontext *tr, TRenum param)
243 {
244         if (!tr)
245                 return 0.0;
246         switch (param) {
247         case TR_LEFT:
248                 return tr->Left;
249         case TR_RIGHT:
250                 return tr->Right;
251         case TR_BOTTOM:
252                 return tr->Bottom;
253         case TR_TOP:
254                 return tr->Top;
255         case TR_NEAR:
256                 return tr->Near;
257         case TR_FAR:
258                 return tr->Far;
259         default:
260                 return 0.0;
261         }
262 }
263
264 void trRowOrder(TRcontext *tr, TRenum order)
265 {
266    if (!tr)
267       return;
268
269    if (order==TR_TOP_TO_BOTTOM || order==TR_BOTTOM_TO_TOP)
270       tr->RowOrder = order;
271 }
272
273
274 void trOrtho(TRcontext *tr,
275              GLdouble left, GLdouble right,
276              GLdouble bottom, GLdouble top,
277              GLdouble zNear, GLdouble zFar)
278 {
279    if (!tr)
280       return;
281
282    tr->Perspective = GL_FALSE;
283    tr->Left = left;
284    tr->Right = right;
285    tr->Bottom = bottom;
286    tr->Top = top;
287    tr->Near = zNear;
288    tr->Far = zFar;
289 }
290
291
292 void trFrustum(TRcontext *tr,
293                GLdouble left, GLdouble right,
294                GLdouble bottom, GLdouble top,
295                GLdouble zNear, GLdouble zFar)
296 {
297    if (!tr)
298       return;
299
300    tr->Perspective = GL_TRUE;
301    tr->Left = left;
302    tr->Right = right;
303    tr->Bottom = bottom;
304    tr->Top = top;
305    tr->Near = zNear;
306    tr->Far = zFar;
307 }
308
309
310 void trPerspective(TRcontext *tr,
311                    GLdouble fovy, GLdouble aspect,
312                    GLdouble zNear, GLdouble zFar )
313 {
314    GLdouble xmin, xmax, ymin, ymax;
315    ymax = zNear * tan(fovy * 3.14159265 / 360.0);
316    ymin = -ymax;
317    xmin = ymin * aspect;
318    xmax = ymax * aspect;
319    trFrustum(tr, xmin, xmax, ymin, ymax, zNear, zFar);
320 }
321
322
323 void trBeginTile(TRcontext *tr)
324 {
325    GLint matrixMode;
326    GLint tileWidth, tileHeight, border;
327    GLdouble left, right, bottom, top;
328
329    if (!tr)
330       return;
331
332    if (tr->CurrentTile <= 0) {
333       Setup(tr);
334       /* Save user's viewport, will be restored after last tile rendered */
335       glGetIntegerv(GL_VIEWPORT, tr->ViewportSave);
336    }
337
338    /* which tile (by row and column) we're about to render */
339    if (tr->RowOrder==TR_BOTTOM_TO_TOP) {
340       tr->CurrentRow = tr->CurrentTile / tr->Columns;
341       tr->CurrentColumn = tr->CurrentTile % tr->Columns;
342    }
343    else if (tr->RowOrder==TR_TOP_TO_BOTTOM) {
344       tr->CurrentRow = tr->Rows - (tr->CurrentTile / tr->Columns) - 1;
345       tr->CurrentColumn = tr->CurrentTile % tr->Columns;
346    }
347    else {
348       /* This should never happen */
349       abort();
350    }
351    assert(tr->CurrentRow < tr->Rows);
352    assert(tr->CurrentColumn < tr->Columns);
353
354    border = tr->TileBorder;
355
356    /* Compute actual size of this tile with border */
357    if (tr->CurrentRow < tr->Rows-1)
358       tileHeight = tr->TileHeight;
359    else
360       tileHeight = tr->ImageHeight - (tr->Rows-1) * (tr->TileHeightNB) + 2 * border;
361
362    if (tr->CurrentColumn < tr->Columns-1)
363       tileWidth = tr->TileWidth;
364    else
365       tileWidth = tr->ImageWidth - (tr->Columns-1) * (tr->TileWidthNB) + 2 * border;
366
367    /* Save tile size, with border */
368    tr->CurrentTileWidth = tileWidth;
369    tr->CurrentTileHeight = tileHeight;
370
371    glViewport(0, 0, tileWidth, tileHeight);  /* tile size including border */
372
373    /* save current matrix mode */
374    glGetIntegerv(GL_MATRIX_MODE, &matrixMode);
375    glMatrixMode(GL_PROJECTION);
376    glLoadIdentity();
377
378    /* compute projection parameters */
379    left = tr->Left + (tr->Right - tr->Left)
380         * (tr->CurrentColumn * tr->TileWidthNB - border) / tr->ImageWidth;
381    right = left + (tr->Right - tr->Left) * tileWidth / tr->ImageWidth;
382    bottom = tr->Bottom + (tr->Top - tr->Bottom)
383           * (tr->CurrentRow * tr->TileHeightNB - border) / tr->ImageHeight;
384    top = bottom + (tr->Top - tr->Bottom) * tileHeight / tr->ImageHeight;
385
386    ssgSetFrustum ( left, right, bottom, top, tr->Near, tr->Far );
387
388    /* restore user's matrix mode */
389    glMatrixMode( (GLenum)matrixMode );
390 }
391
392
393
394 int trEndTile(TRcontext *tr)
395 {
396    GLint prevRowLength, prevSkipRows, prevSkipPixels /*, prevAlignment */;
397
398    if (!tr)
399       return 0;
400
401    assert(tr->CurrentTile>=0);
402
403    /* be sure OpenGL rendering is finished */
404    glFlush();
405
406    /* save current glPixelStore values */
407    glGetIntegerv(GL_PACK_ROW_LENGTH, &prevRowLength);
408    glGetIntegerv(GL_PACK_SKIP_ROWS, &prevSkipRows);
409    glGetIntegerv(GL_PACK_SKIP_PIXELS, &prevSkipPixels);
410    /*glGetIntegerv(GL_PACK_ALIGNMENT, &prevAlignment);*/
411
412    if (tr->TileBuffer) {
413       GLint srcX = tr->TileBorder;
414       GLint srcY = tr->TileBorder;
415       GLint srcWidth = tr->TileWidthNB;
416       GLint srcHeight = tr->TileHeightNB;
417       glReadPixels(srcX, srcY, srcWidth, srcHeight,
418                    tr->TileFormat, tr->TileType, tr->TileBuffer);
419    }
420
421    if (tr->ImageBuffer) {
422       GLint srcX = tr->TileBorder;
423       GLint srcY = tr->TileBorder;
424       GLint srcWidth = tr->CurrentTileWidth - 2 * tr->TileBorder;
425       GLint srcHeight = tr->CurrentTileHeight - 2 * tr->TileBorder;
426       GLint destX = tr->TileWidthNB * tr->CurrentColumn;
427       GLint destY = tr->TileHeightNB * tr->CurrentRow;
428
429       /* setup pixel store for glReadPixels */
430       glPixelStorei(GL_PACK_ROW_LENGTH, tr->ImageWidth);
431       glPixelStorei(GL_PACK_SKIP_ROWS, destY);
432       glPixelStorei(GL_PACK_SKIP_PIXELS, destX);
433       /*glPixelStorei(GL_PACK_ALIGNMENT, 1);*/
434
435       /* read the tile into the final image */
436       glReadPixels(srcX, srcY, srcWidth, srcHeight,
437                    tr->ImageFormat, tr->ImageType, tr->ImageBuffer);
438    }
439
440    /* restore previous glPixelStore values */
441    glPixelStorei(GL_PACK_ROW_LENGTH, prevRowLength);
442    glPixelStorei(GL_PACK_SKIP_ROWS, prevSkipRows);
443    glPixelStorei(GL_PACK_SKIP_PIXELS, prevSkipPixels);
444    /*glPixelStorei(GL_PACK_ALIGNMENT, prevAlignment);*/
445
446    /* increment tile counter, return 1 if more tiles left to render */
447    tr->CurrentTile++;
448    if (tr->CurrentTile >= tr->Rows * tr->Columns) {
449       /* restore user's viewport */
450       glViewport(tr->ViewportSave[0], tr->ViewportSave[1],
451                  tr->ViewportSave[2], tr->ViewportSave[3]);
452       tr->CurrentTile = -1;  /* all done */
453       return 0;
454    }
455    else
456       return 1;
457 }
458
459
460 /*
461  * Replacement for glRastePos3f() which avoids the problem with invalid
462  * raster pos.
463  */
464 void trRasterPos3f(TRcontext *tr, GLfloat x, GLfloat y, GLfloat z)
465 {
466    if (tr->CurrentTile<0) {
467       /* not doing tile rendering right now.  Let OpenGL do this. */
468       glRasterPos3f(x, y, z);
469    }
470    else {
471       GLdouble modelview[16], proj[16];
472       GLint viewport[4];
473       GLdouble winX, winY, winZ;
474
475       /* Get modelview, projection and viewport */
476       glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
477       glGetDoublev(GL_PROJECTION_MATRIX, proj);
478       viewport[0] = 0;
479       viewport[1] = 0;
480       viewport[2] = tr->CurrentTileWidth;
481       viewport[3] = tr->CurrentTileHeight;
482
483       /* Project object coord to window coordinate */
484       if (gluProject(x, y, z, modelview, proj, viewport, &winX, &winY, &winZ)){
485
486          /* set raster pos to window coord (0,0) */
487          glMatrixMode(GL_MODELVIEW);
488          glPushMatrix();
489          glLoadIdentity();
490          glMatrixMode(GL_PROJECTION);
491          glPushMatrix();
492          glLoadIdentity();
493          glOrtho(0.0, tr->CurrentTileWidth,
494                  0.0, tr->CurrentTileHeight, 0.0, 1.0);
495          glRasterPos3f(0.0, 0.0, -winZ);
496
497          /* Now use empty bitmap to adjust raster position to (winX,winY) */
498          {
499             GLubyte bitmap[1] = {0};
500             glBitmap(1, 1, 0.0, 0.0, winX, winY, bitmap);
501          }
502
503          /* restore original matrices */
504          glPopMatrix(); /*proj*/
505          glMatrixMode(GL_MODELVIEW);
506          glPopMatrix();
507       }
508 #ifdef DEBUG
509       if (glGetError())
510          printf("GL error!\n");
511 #endif
512    }
513 }
514