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