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