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