Use jw from docbook-utils instead of sgmltools-lite
[survex.git] / src / tr.c
blob724267b30e803aac295ee313f91fd80ea57de045
1 /* $Id: tr.c,v 1.9 1998/01/29 16:56:54 brianp Exp $ */
3 /*
4 * $Log: tr.c,v $
5 * Revision 1.9 1998/01/29 16:56:54 brianp
6 * allow trOrtho() and trFrustum() to be called at any time, minor clean-up
8 * Revision 1.8 1998/01/28 19:47:39 brianp
9 * minor clean-up for C++
11 * Revision 1.7 1997/07/21 17:34:38 brianp
12 * added tile borders
14 * Revision 1.6 1997/07/21 15:47:35 brianp
15 * renamed all "near" and "far" variables
17 * Revision 1.5 1997/04/26 21:23:25 brianp
18 * added trRasterPos3f function
20 * Revision 1.4 1997/04/26 19:59:36 brianp
21 * set CurrentTile to -1 before first tile and after last tile
23 * Revision 1.3 1997/04/22 23:51:15 brianp
24 * added WIN32 header stuff, removed tabs
26 * Revision 1.2 1997/04/19 23:26:10 brianp
27 * many API changes
29 * Revision 1.1 1997/04/18 21:53:05 brianp
30 * Initial revision
36 * Tiled Rendering library
37 * Version 1.1
38 * Copyright (C) Brian Paul
42 #include <assert.h>
43 #include <math.h>
44 #include <stdlib.h>
45 #include <stdio.h>
46 #ifdef WIN32
47 #include <windows.h>
48 #endif
49 #include <GL/gl.h>
50 #include <GL/glu.h>
51 #include "tr.h"
54 #define DEFAULT_TILE_WIDTH 256
55 #define DEFAULT_TILE_HEIGHT 256
56 #define DEFAULT_TILE_BORDER 0
59 struct _TRctx {
60 /* Final image parameters */
61 GLint ImageWidth, ImageHeight;
62 GLenum ImageFormat, ImageType;
63 GLvoid *ImageBuffer;
65 /* Tile parameters */
66 GLint TileWidth, TileHeight;
67 GLint TileWidthNB, TileHeightNB;
68 GLint TileBorder;
69 GLenum TileFormat, TileType;
70 GLvoid *TileBuffer;
72 /* Projection parameters */
73 GLboolean Perspective;
74 GLdouble Left;
75 GLdouble Right;
76 GLdouble Bottom;
77 GLdouble Top;
78 GLdouble Near;
79 GLdouble Far;
81 /* Misc */
82 TRenum RowOrder;
83 GLint Rows, Columns;
84 GLint CurrentTile;
85 GLint CurrentTileWidth, CurrentTileHeight;
86 GLint CurrentRow, CurrentColumn;
88 GLint ViewportSave[4];
94 * Misc setup including computing number of tiles (rows and columns).
96 static void Setup(TRcontext *tr)
98 if (!tr)
99 return;
101 tr->Columns = (tr->ImageWidth + tr->TileWidthNB - 1) / tr->TileWidthNB;
102 tr->Rows = (tr->ImageHeight + tr->TileHeightNB - 1) / tr->TileHeightNB;
103 tr->CurrentTile = 0;
105 assert(tr->Columns >= 0);
106 assert(tr->Rows >= 0);
111 TRcontext *trNew(void)
113 TRcontext *tr = (TRcontext *) calloc(1, sizeof(TRcontext));
114 if (tr) {
115 tr->TileWidth = DEFAULT_TILE_WIDTH;
116 tr->TileHeight = DEFAULT_TILE_HEIGHT;
117 tr->TileBorder = DEFAULT_TILE_BORDER;
118 tr->RowOrder = TR_BOTTOM_TO_TOP;
119 tr->CurrentTile = -1;
121 return (TRcontext *) tr;
125 void trDelete(TRcontext *tr)
127 if (tr)
128 free(tr);
133 void trTileSize(TRcontext *tr, GLint width, GLint height, GLint border)
135 if (!tr)
136 return;
138 assert(border >= 0);
139 assert(width >= 1);
140 assert(height >= 1);
141 assert(width >= 2*border);
142 assert(height >= 2*border);
144 tr->TileBorder = border;
145 tr->TileWidth = width;
146 tr->TileHeight = height;
147 tr->TileWidthNB = width - 2 * border;
148 tr->TileHeightNB = height - 2 * border;
149 Setup(tr);
154 void trTileBuffer(TRcontext *tr, GLenum format, GLenum type, GLvoid *image)
156 if (!tr)
157 return;
159 tr->TileFormat = format;
160 tr->TileType = type;
161 tr->TileBuffer = image;
166 void trImageSize(TRcontext *tr, GLint width, GLint height)
168 if (!tr)
169 return;
171 tr->ImageWidth = width;
172 tr->ImageHeight = height;
173 Setup(tr);
177 void trImageBuffer(TRcontext *tr, GLenum format, GLenum type, GLvoid *image)
179 if (!tr)
180 return;
182 tr->ImageFormat = format;
183 tr->ImageType = type;
184 tr->ImageBuffer = image;
188 GLint trGet(TRcontext *tr, TRenum param)
190 if (!tr)
191 return 0;
193 switch (param) {
194 case TR_TILE_WIDTH:
195 return tr->TileWidth;
196 case TR_TILE_HEIGHT:
197 return tr->TileHeight;
198 case TR_TILE_BORDER:
199 return tr->TileBorder;
200 case TR_IMAGE_WIDTH:
201 return tr->ImageWidth;
202 case TR_IMAGE_HEIGHT:
203 return tr->ImageHeight;
204 case TR_ROWS:
205 return tr->Rows;
206 case TR_COLUMNS:
207 return tr->Columns;
208 case TR_CURRENT_ROW:
209 if (tr->CurrentTile<0)
210 return -1;
211 else
212 return tr->CurrentRow;
213 case TR_CURRENT_COLUMN:
214 if (tr->CurrentTile<0)
215 return -1;
216 else
217 return tr->CurrentColumn;
218 case TR_CURRENT_TILE_WIDTH:
219 return tr->CurrentTileWidth;
220 case TR_CURRENT_TILE_HEIGHT:
221 return tr->CurrentTileHeight;
222 case TR_ROW_ORDER:
223 return (GLint) tr->RowOrder;
224 default:
225 return 0;
230 void trRowOrder(TRcontext *tr, TRenum order)
232 if (!tr)
233 return;
235 if (order==TR_TOP_TO_BOTTOM || order==TR_BOTTOM_TO_TOP)
236 tr->RowOrder = order;
240 void trOrtho(TRcontext *tr,
241 GLdouble left, GLdouble right,
242 GLdouble bottom, GLdouble top,
243 GLdouble zNear, GLdouble zFar)
245 if (!tr)
246 return;
248 tr->Perspective = GL_FALSE;
249 tr->Left = left;
250 tr->Right = right;
251 tr->Bottom = bottom;
252 tr->Top = top;
253 tr->Near = zNear;
254 tr->Far = zFar;
258 void trFrustum(TRcontext *tr,
259 GLdouble left, GLdouble right,
260 GLdouble bottom, GLdouble top,
261 GLdouble zNear, GLdouble zFar)
263 if (!tr)
264 return;
266 tr->Perspective = GL_TRUE;
267 tr->Left = left;
268 tr->Right = right;
269 tr->Bottom = bottom;
270 tr->Top = top;
271 tr->Near = zNear;
272 tr->Far = zFar;
276 void trPerspective(TRcontext *tr,
277 GLdouble fovy, GLdouble aspect,
278 GLdouble zNear, GLdouble zFar )
280 GLdouble xmin, xmax, ymin, ymax;
281 ymax = zNear * tan(fovy * 3.14159265 / 360.0);
282 ymin = -ymax;
283 xmin = ymin * aspect;
284 xmax = ymax * aspect;
285 trFrustum(tr, xmin, xmax, ymin, ymax, zNear, zFar);
289 void trBeginTile(TRcontext *tr)
291 GLint matrixMode;
292 GLint tileWidth, tileHeight, border;
293 GLdouble left, right, bottom, top;
295 if (!tr)
296 return;
298 if (tr->CurrentTile <= 0) {
299 Setup(tr);
300 /* Save user's viewport, will be restored after last tile rendered */
301 glGetIntegerv(GL_VIEWPORT, tr->ViewportSave);
304 /* which tile (by row and column) we're about to render */
305 if (tr->RowOrder==TR_BOTTOM_TO_TOP) {
306 tr->CurrentRow = tr->CurrentTile / tr->Columns;
307 tr->CurrentColumn = tr->CurrentTile % tr->Columns;
309 else if (tr->RowOrder==TR_TOP_TO_BOTTOM) {
310 tr->CurrentRow = tr->Rows - (tr->CurrentTile / tr->Columns) - 1;
311 tr->CurrentColumn = tr->CurrentTile % tr->Columns;
313 else {
314 /* This should never happen */
315 abort();
317 assert(tr->CurrentRow < tr->Rows);
318 assert(tr->CurrentColumn < tr->Columns);
320 border = tr->TileBorder;
322 /* Compute actual size of this tile with border */
323 if (tr->CurrentRow < tr->Rows-1)
324 tileHeight = tr->TileHeight;
325 else
326 tileHeight = tr->ImageHeight - (tr->Rows-1) * (tr->TileHeightNB) + 2 * border;
328 if (tr->CurrentColumn < tr->Columns-1)
329 tileWidth = tr->TileWidth;
330 else
331 tileWidth = tr->ImageWidth - (tr->Columns-1) * (tr->TileWidthNB) + 2 * border;
333 /* Save tile size, with border */
334 tr->CurrentTileWidth = tileWidth;
335 tr->CurrentTileHeight = tileHeight;
337 glViewport(0, 0, tileWidth, tileHeight); /* tile size including border */
339 /* save current matrix mode */
340 glGetIntegerv(GL_MATRIX_MODE, &matrixMode);
341 glMatrixMode(GL_PROJECTION);
342 glLoadIdentity();
344 /* compute projection parameters */
345 left = tr->Left + (tr->Right - tr->Left)
346 * (tr->CurrentColumn * tr->TileWidthNB - border) / tr->ImageWidth;
347 right = left + (tr->Right - tr->Left) * tileWidth / tr->ImageWidth;
348 bottom = tr->Bottom + (tr->Top - tr->Bottom)
349 * (tr->CurrentRow * tr->TileHeightNB - border) / tr->ImageHeight;
350 top = bottom + (tr->Top - tr->Bottom) * tileHeight / tr->ImageHeight;
352 if (tr->Perspective)
353 glFrustum(left, right, bottom, top, tr->Near, tr->Far);
354 else
355 glOrtho(left, right, bottom, top, tr->Near, tr->Far);
357 /* restore user's matrix mode */
358 glMatrixMode(matrixMode);
363 int trEndTile(TRcontext *tr)
365 GLint prevRowLength, prevSkipRows, prevSkipPixels, prevAlignment;
367 if (!tr)
368 return 0;
370 assert(tr->CurrentTile>=0);
372 /* be sure OpenGL rendering is finished */
373 glFlush();
375 /* save current glPixelStore values */
376 glGetIntegerv(GL_PACK_ROW_LENGTH, &prevRowLength);
377 glGetIntegerv(GL_PACK_SKIP_ROWS, &prevSkipRows);
378 glGetIntegerv(GL_PACK_SKIP_PIXELS, &prevSkipPixels);
379 /*glGetIntegerv(GL_PACK_ALIGNMENT, &prevAlignment);*/
381 if (tr->TileBuffer) {
382 GLint srcX = tr->TileBorder;
383 GLint srcY = tr->TileBorder;
384 GLint srcWidth = tr->TileWidthNB;
385 GLint srcHeight = tr->TileHeightNB;
386 glReadPixels(srcX, srcY, srcWidth, srcHeight,
387 tr->TileFormat, tr->TileType, tr->TileBuffer);
390 if (tr->ImageBuffer) {
391 GLint srcX = tr->TileBorder;
392 GLint srcY = tr->TileBorder;
393 GLint srcWidth = tr->CurrentTileWidth - 2 * tr->TileBorder;
394 GLint srcHeight = tr->CurrentTileHeight - 2 * tr->TileBorder;
395 GLint destX = tr->TileWidthNB * tr->CurrentColumn;
396 GLint destY = tr->TileHeightNB * tr->CurrentRow;
398 /* setup pixel store for glReadPixels */
399 glPixelStorei(GL_PACK_ROW_LENGTH, tr->ImageWidth);
400 glPixelStorei(GL_PACK_SKIP_ROWS, destY);
401 glPixelStorei(GL_PACK_SKIP_PIXELS, destX);
402 /*glPixelStorei(GL_PACK_ALIGNMENT, 1);*/
404 /* read the tile into the final image */
405 glReadPixels(srcX, srcY, srcWidth, srcHeight,
406 tr->ImageFormat, tr->ImageType, tr->ImageBuffer);
409 /* restore previous glPixelStore values */
410 glPixelStorei(GL_PACK_ROW_LENGTH, prevRowLength);
411 glPixelStorei(GL_PACK_SKIP_ROWS, prevSkipRows);
412 glPixelStorei(GL_PACK_SKIP_PIXELS, prevSkipPixels);
413 /*glPixelStorei(GL_PACK_ALIGNMENT, prevAlignment);*/
415 /* increment tile counter, return 1 if more tiles left to render */
416 tr->CurrentTile++;
417 if (tr->CurrentTile >= tr->Rows * tr->Columns) {
418 /* restore user's viewport */
419 glViewport(tr->ViewportSave[0], tr->ViewportSave[1],
420 tr->ViewportSave[2], tr->ViewportSave[3]);
421 tr->CurrentTile = -1; /* all done */
422 return 0;
424 else
425 return 1;
430 * Replacement for glRastePos3f() which avoids the problem with invalid
431 * raster pos.
433 void trRasterPos3f(TRcontext *tr, GLfloat x, GLfloat y, GLfloat z)
435 if (tr->CurrentTile<0) {
436 /* not doing tile rendering right now. Let OpenGL do this. */
437 glRasterPos3f(x, y, z);
439 else {
440 GLdouble modelview[16], proj[16];
441 GLint viewport[4];
442 GLdouble winX, winY, winZ;
444 /* Get modelview, projection and viewport */
445 glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
446 glGetDoublev(GL_PROJECTION_MATRIX, proj);
447 viewport[0] = 0;
448 viewport[1] = 0;
449 viewport[2] = tr->CurrentTileWidth;
450 viewport[3] = tr->CurrentTileHeight;
452 /* Project object coord to window coordinate */
453 if (gluProject(x, y, z, modelview, proj, viewport, &winX, &winY, &winZ)){
455 /* set raster pos to window coord (0,0) */
456 glMatrixMode(GL_MODELVIEW);
457 glPushMatrix();
458 glLoadIdentity();
459 glMatrixMode(GL_PROJECTION);
460 glPushMatrix();
461 glLoadIdentity();
462 glOrtho(0.0, tr->CurrentTileWidth,
463 0.0, tr->CurrentTileHeight, 0.0, 1.0);
464 glRasterPos3f(0.0, 0.0, -winZ);
466 /* Now use empty bitmap to adjust raster position to (winX,winY) */
468 GLubyte bitmap[1] = {0};
469 glBitmap(1, 1, 0.0, 0.0, winX, winY, bitmap);
472 /* restore original matrices */
473 glPopMatrix(); /*proj*/
474 glMatrixMode(GL_MODELVIEW);
475 glPopMatrix();
477 #ifdef DEBUG
478 if (glGetError())
479 printf("GL error!\n");
480 #endif