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