1 | /* Copyright (c) 2001, Stanford University
|
---|
2 | * All rights reserved
|
---|
3 | *
|
---|
4 | * See the file LICENSE.txt for information on redistributing this software.
|
---|
5 | */
|
---|
6 |
|
---|
7 | #include "server_dispatch.h"
|
---|
8 | #include "server.h"
|
---|
9 | #include "cr_error.h"
|
---|
10 | #include "state/cr_statetypes.h"
|
---|
11 |
|
---|
12 |
|
---|
13 | static const CRmatrix identity_matrix = {
|
---|
14 | 1.0, 0.0, 0.0, 0.0,
|
---|
15 | 0.0, 1.0, 0.0, 0.0,
|
---|
16 | 0.0, 0.0, 1.0, 0.0,
|
---|
17 | 0.0, 0.0, 0.0, 1.0
|
---|
18 | };
|
---|
19 |
|
---|
20 |
|
---|
21 | /*
|
---|
22 | * Clip the rectangle q against the given image window.
|
---|
23 | */
|
---|
24 | static void
|
---|
25 | crServerViewportClipToWindow( const CRrecti *imagewindow, CRrecti *q)
|
---|
26 | {
|
---|
27 | if (q->x1 < imagewindow->x1) q->x1 = imagewindow->x1;
|
---|
28 | if (q->x1 > imagewindow->x2) q->x1 = imagewindow->x2;
|
---|
29 |
|
---|
30 | if (q->x2 > imagewindow->x2) q->x2 = imagewindow->x2;
|
---|
31 | if (q->x2 < imagewindow->x1) q->x2 = imagewindow->x1;
|
---|
32 |
|
---|
33 | if (q->y1 < imagewindow->y1) q->y1 = imagewindow->y1;
|
---|
34 | if (q->y1 > imagewindow->y2) q->y1 = imagewindow->y2;
|
---|
35 |
|
---|
36 | if (q->y2 > imagewindow->y2) q->y2 = imagewindow->y2;
|
---|
37 | if (q->y2 < imagewindow->y1) q->y2 = imagewindow->y1;
|
---|
38 | }
|
---|
39 |
|
---|
40 |
|
---|
41 | /*
|
---|
42 | * Translate the rectangle q from the image window space to the outputwindow
|
---|
43 | * space.
|
---|
44 | */
|
---|
45 | static void
|
---|
46 | crServerConvertToOutput( const CRrecti *imagewindow,
|
---|
47 | const CRrecti *outputwindow,
|
---|
48 | CRrecti *q )
|
---|
49 | {
|
---|
50 | q->x1 = q->x1 - imagewindow->x1 + outputwindow->x1;
|
---|
51 | q->x2 = q->x2 - imagewindow->x2 + outputwindow->x2;
|
---|
52 | q->y1 = q->y1 - imagewindow->y1 + outputwindow->y1;
|
---|
53 | q->y2 = q->y2 - imagewindow->y2 + outputwindow->y2;
|
---|
54 | }
|
---|
55 |
|
---|
56 |
|
---|
57 | /*
|
---|
58 | * Compute clipped image window, scissor, viewport and base projection
|
---|
59 | * info for each tile in the mural.
|
---|
60 | * Need to call this when either the viewport or mural is changed.
|
---|
61 | */
|
---|
62 | void
|
---|
63 | crServerComputeViewportBounds(const CRViewportState *v, CRMuralInfo *mural)
|
---|
64 | {
|
---|
65 | static GLuint serialNo = 1;
|
---|
66 | int i;
|
---|
67 |
|
---|
68 | for (i = 0; i < mural->numExtents; i++) {
|
---|
69 | CRExtent *extent = &mural->extents[i];
|
---|
70 | CRrecti q;
|
---|
71 |
|
---|
72 | /* If the scissor is disabled set it to the whole output.
|
---|
73 | ** We might as well use the actual scissorTest rather than
|
---|
74 | ** scissorValid - it never gets reset anyway.
|
---|
75 | */
|
---|
76 | if (!v->scissorTest)
|
---|
77 | {
|
---|
78 | extent->scissorBox = extent->outputwindow;
|
---|
79 | }
|
---|
80 | else
|
---|
81 | {
|
---|
82 | q.x1 = v->scissorX;
|
---|
83 | q.x2 = v->scissorX + v->scissorW;
|
---|
84 | q.y1 = v->scissorY;
|
---|
85 | q.y2 = v->scissorY + v->scissorH;
|
---|
86 |
|
---|
87 | crServerViewportClipToWindow(&(extent->imagewindow), &q);
|
---|
88 | crServerConvertToOutput(&(extent->imagewindow),
|
---|
89 | &(extent->outputwindow), &q);
|
---|
90 | extent->scissorBox = q;
|
---|
91 | }
|
---|
92 |
|
---|
93 | /* if the viewport is not valid,
|
---|
94 | ** set it to the entire output.
|
---|
95 | */
|
---|
96 | if (!v->viewportValid)
|
---|
97 | {
|
---|
98 | extent->clippedImagewindow = extent->imagewindow;
|
---|
99 | extent->viewport = extent->outputwindow;
|
---|
100 | }
|
---|
101 | else
|
---|
102 | {
|
---|
103 | q.x1 = v->viewportX;
|
---|
104 | q.x2 = v->viewportX + v->viewportW;
|
---|
105 | q.y1 = v->viewportY;
|
---|
106 | q.y2 = v->viewportY + v->viewportH;
|
---|
107 |
|
---|
108 | /* This is where the viewport gets clamped to the max size. */
|
---|
109 | crServerViewportClipToWindow(&(extent->imagewindow), &q);
|
---|
110 |
|
---|
111 | extent->clippedImagewindow = q;
|
---|
112 |
|
---|
113 | crServerConvertToOutput(&(extent->imagewindow),
|
---|
114 | &(extent->outputwindow), &q);
|
---|
115 |
|
---|
116 | extent->viewport = q;
|
---|
117 | }
|
---|
118 |
|
---|
119 | /*
|
---|
120 | ** Now, compute the base projection.
|
---|
121 | */
|
---|
122 | if (extent->clippedImagewindow.x1 == extent->clippedImagewindow.x2 ||
|
---|
123 | extent->clippedImagewindow.y1 == extent->clippedImagewindow.y2) {
|
---|
124 | /* zero-area extent, use identity matrix (doesn't really matter) */
|
---|
125 | extent->baseProjection = identity_matrix;
|
---|
126 | }
|
---|
127 | else
|
---|
128 | {
|
---|
129 | const int vpx = v->viewportX;
|
---|
130 | const int vpy = v->viewportY;
|
---|
131 | const int vpw = v->viewportW;
|
---|
132 | const int vph = v->viewportH;
|
---|
133 | GLfloat xscale, yscale;
|
---|
134 | GLfloat xtrans, ytrans;
|
---|
135 | CRrectf p;
|
---|
136 |
|
---|
137 | /*
|
---|
138 | * We need to take account of the current viewport parameters,
|
---|
139 | * and they are passed to this function as x, y, w, h.
|
---|
140 | * In the default case (from main.c) we pass the the
|
---|
141 | * full muralsize of 0, 0, width, height
|
---|
142 | */
|
---|
143 | p.x1 = (GLfloat) (extent->clippedImagewindow.x1 - vpx) / vpw;
|
---|
144 | p.y1 = (GLfloat) (extent->clippedImagewindow.y1 - vpy) / vph;
|
---|
145 | p.x2 = (GLfloat) (extent->clippedImagewindow.x2 - vpx) / vpw;
|
---|
146 | p.y2 = (GLfloat) (extent->clippedImagewindow.y2 - vpy) / vph;
|
---|
147 |
|
---|
148 | /* XXX not sure this clamping is really neeed anymore
|
---|
149 | */
|
---|
150 | if (p.x1 < 0.0) {
|
---|
151 | p.x1 = 0.0;
|
---|
152 | if (p.x2 > 1.0) p.x2 = 1.0;
|
---|
153 | }
|
---|
154 |
|
---|
155 | if (p.y1 < 0.0) {
|
---|
156 | p.y1 = 0.0;
|
---|
157 | if (p.y2 > 1.0) p.y2 = 1.0;
|
---|
158 | }
|
---|
159 |
|
---|
160 | /* Rescale [0,1] -> [-1,1] */
|
---|
161 | p.x1 = p.x1 * 2.0f - 1.0f;
|
---|
162 | p.x2 = p.x2 * 2.0f - 1.0f;
|
---|
163 | p.y1 = p.y1 * 2.0f - 1.0f;
|
---|
164 | p.y2 = p.y2 * 2.0f - 1.0f;
|
---|
165 |
|
---|
166 | xscale = 2.0f / (p.x2 - p.x1);
|
---|
167 | yscale = 2.0f / (p.y2 - p.y1);
|
---|
168 | xtrans = -(p.x2 + p.x1) / 2.0f;
|
---|
169 | ytrans = -(p.y2 + p.y1) / 2.0f;
|
---|
170 |
|
---|
171 | CRASSERT(xscale == xscale); /* NaN test */
|
---|
172 | CRASSERT(yscale == yscale);
|
---|
173 |
|
---|
174 | extent->baseProjection = identity_matrix;
|
---|
175 | extent->baseProjection.m00 = xscale;
|
---|
176 | extent->baseProjection.m11 = yscale;
|
---|
177 | extent->baseProjection.m30 = xtrans * xscale;
|
---|
178 | extent->baseProjection.m31 = ytrans * yscale;
|
---|
179 | }
|
---|
180 |
|
---|
181 | extent->serialNo = serialNo++;
|
---|
182 | }
|
---|
183 | mural->viewportValidated = GL_TRUE;
|
---|
184 | }
|
---|
185 |
|
---|
186 |
|
---|
187 | /*
|
---|
188 | * Issue the glScissor, glViewport and projection matrix needed for
|
---|
189 | * rendering the tile specified by extNum. We computed the scissor,
|
---|
190 | * viewport and projection parameters above in crServerComputeViewportBounds.
|
---|
191 | */
|
---|
192 | void
|
---|
193 | crServerSetOutputBounds( const CRMuralInfo *mural, int extNum )
|
---|
194 | {
|
---|
195 | const CRExtent *extent = mural->extents + extNum;
|
---|
196 | CRASSERT(mural->viewportValidated);
|
---|
197 |
|
---|
198 | /*
|
---|
199 | * Serial Number info:
|
---|
200 | * Everytime we compute new scissor, viewport, projection matrix info for
|
---|
201 | * a tile, we give that tile a new serial number.
|
---|
202 | * When we're about to render into a tile, we only update the scissor,
|
---|
203 | * viewport and projection matrix if the tile's serial number doesn't match
|
---|
204 | * the current serial number. This avoids a _LOT_ of redundant calls to
|
---|
205 | * those three functions.
|
---|
206 | */
|
---|
207 | if (extent->serialNo != cr_server.currentSerialNo) {
|
---|
208 | cr_server.head_spu->dispatch_table.Scissor(extent->scissorBox.x1,
|
---|
209 | extent->scissorBox.y1,
|
---|
210 | extent->scissorBox.x2 - extent->scissorBox.x1,
|
---|
211 | extent->scissorBox.y2 - extent->scissorBox.y1);
|
---|
212 |
|
---|
213 | cr_server.head_spu->dispatch_table.Viewport(extent->viewport.x1,
|
---|
214 | extent->viewport.y1,
|
---|
215 | extent->viewport.x2 - extent->viewport.x1,
|
---|
216 | extent->viewport.y2 - extent->viewport.y1);
|
---|
217 |
|
---|
218 | crServerApplyBaseProjection(&(extent->baseProjection));
|
---|
219 | cr_server.currentSerialNo = extent->serialNo;
|
---|
220 | }
|
---|
221 | }
|
---|
222 |
|
---|
223 |
|
---|
224 | /*
|
---|
225 | * Pre-multiply the current projection matrix with the current client's
|
---|
226 | * base projection. I.e. P' = b * P. Note that OpenGL's glMultMatrix
|
---|
227 | * POST-multiplies.
|
---|
228 | */
|
---|
229 | void
|
---|
230 | crServerApplyBaseProjection(const CRmatrix *baseProj)
|
---|
231 | {
|
---|
232 | const CRmatrix *projMatrix;
|
---|
233 | if (cr_server.projectionOverride) {
|
---|
234 | int eye = crServerGetCurrentEye();
|
---|
235 | projMatrix = &cr_server.projectionMatrix[eye];
|
---|
236 | }
|
---|
237 | else
|
---|
238 | projMatrix = cr_server.curClient->currentCtx->transform.projectionStack.top;
|
---|
239 |
|
---|
240 | cr_server.head_spu->dispatch_table.PushAttrib( GL_TRANSFORM_BIT );
|
---|
241 | cr_server.head_spu->dispatch_table.MatrixMode( GL_PROJECTION );
|
---|
242 | cr_server.head_spu->dispatch_table.LoadMatrixf( (const GLfloat *) baseProj );
|
---|
243 | cr_server.head_spu->dispatch_table.MultMatrixf( cr_server.alignment_matrix );
|
---|
244 | cr_server.head_spu->dispatch_table.MultMatrixf( (const GLfloat *) projMatrix );
|
---|
245 | cr_server.head_spu->dispatch_table.PopAttrib();
|
---|
246 | }
|
---|
247 |
|
---|
248 |
|
---|
249 | void
|
---|
250 | crServerApplyViewMatrix(const CRmatrix *view)
|
---|
251 | {
|
---|
252 | const CRmatrix *modelview = cr_server.curClient->currentCtx->transform.modelViewStack.top;
|
---|
253 |
|
---|
254 | cr_server.head_spu->dispatch_table.PushAttrib( GL_TRANSFORM_BIT );
|
---|
255 | cr_server.head_spu->dispatch_table.MatrixMode( GL_MODELVIEW );
|
---|
256 | cr_server.head_spu->dispatch_table.LoadMatrixf( (const GLfloat *) view );
|
---|
257 | cr_server.head_spu->dispatch_table.MultMatrixf( (const GLfloat *) modelview );
|
---|
258 | cr_server.head_spu->dispatch_table.PopAttrib();
|
---|
259 | }
|
---|
260 |
|
---|
261 |
|
---|
262 | /*
|
---|
263 | * Called via unpacker module.
|
---|
264 | * Note: when there's a tilesort SPU upstream, the viewport dimensions
|
---|
265 | * will typically match the mural size. That is, the viewport dimensions
|
---|
266 | * probably won't be the same values that the application issues.
|
---|
267 | */
|
---|
268 | void SERVER_DISPATCH_APIENTRY crServerDispatchViewport( GLint x, GLint y, GLsizei width, GLsizei height )
|
---|
269 | {
|
---|
270 | CRMuralInfo *mural = cr_server.curClient->currentMural;
|
---|
271 | CRContext *ctx = crStateGetCurrent();
|
---|
272 |
|
---|
273 | if (ctx->viewport.viewportX != x ||
|
---|
274 | ctx->viewport.viewportY != y ||
|
---|
275 | ctx->viewport.viewportW != width ||
|
---|
276 | ctx->viewport.viewportH != height) {
|
---|
277 | /* Note -- If there are tiles, this will be overridden in the
|
---|
278 | * process of decoding the BoundsInfo packet, so no worries. */
|
---|
279 | crStateViewport( x, y, width, height );
|
---|
280 |
|
---|
281 | mural->viewportValidated = GL_FALSE;
|
---|
282 | }
|
---|
283 |
|
---|
284 | /* always dispatch to be safe */
|
---|
285 | cr_server.head_spu->dispatch_table.Viewport( x, y, width, height );
|
---|
286 | }
|
---|