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