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