Reorganized software rasterizer as a module which manages its own state,
[mesa.git] / src / mesa / swrast / s_zoom.c
1 /* $Id: s_zoom.c,v 1.2 2000/11/05 18:24:41 keithw Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.5
6 *
7 * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27 #include "glheader.h"
28 #include "macros.h"
29
30 #include "s_context.h"
31 #include "s_span.h"
32 #include "s_stencil.h"
33 #include "s_zoom.h"
34
35
36
37 /*
38 * Write a span of pixels to the frame buffer while applying a pixel zoom.
39 * This is only used by glDrawPixels and glCopyPixels.
40 * Input: n - number of pixels in input row
41 * x, y - destination of the span
42 * z - depth values for the span
43 * red, green, blue, alpha - array of colors
44 * y0 - location of first row in the image we're drawing.
45 */
46 void
47 gl_write_zoomed_rgba_span( GLcontext *ctx,
48 GLuint n, GLint x, GLint y, const GLdepth z[],
49 const GLfixed *fog,
50 CONST GLchan rgba[][4], GLint y0 )
51 {
52 GLint m;
53 GLint r0, r1, row, r;
54 GLint i, j, skipcol;
55 GLchan zrgba[MAX_WIDTH][4]; /* zoomed pixel colors */
56 GLdepth zdepth[MAX_WIDTH]; /* zoomed depth values */
57 GLfixed zfog[MAX_WIDTH]; /* zoomed fog values */
58 GLint maxwidth = MIN2( ctx->DrawBuffer->Width, MAX_WIDTH );
59 const GLuint *srcRGBA32 = (const GLuint *) rgba;
60 GLuint *dstRGBA32 = (GLuint *) zrgba;
61
62 /* compute width of output row */
63 m = (GLint) ABSF( n * ctx->Pixel.ZoomX );
64 if (m==0) {
65 return;
66 }
67 if (ctx->Pixel.ZoomX<0.0) {
68 /* adjust x coordinate for left/right mirroring */
69 x = x - m;
70 }
71
72 /* compute which rows to draw */
73 row = y-y0;
74 r0 = y0 + (GLint) (row * ctx->Pixel.ZoomY);
75 r1 = y0 + (GLint) ((row+1) * ctx->Pixel.ZoomY);
76 if (r0==r1) {
77 return;
78 }
79 else if (r1<r0) {
80 GLint rtmp = r1;
81 r1 = r0;
82 r0 = rtmp;
83 }
84
85 /* return early if r0...r1 is above or below window */
86 if (r0<0 && r1<0) {
87 /* below window */
88 return;
89 }
90 if (r0>=ctx->DrawBuffer->Height && r1>=ctx->DrawBuffer->Height) {
91 /* above window */
92 return;
93 }
94
95 /* check if left edge is outside window */
96 skipcol = 0;
97 if (x<0) {
98 skipcol = -x;
99 m += x;
100 }
101 /* make sure span isn't too long or short */
102 if (m>maxwidth) {
103 m = maxwidth;
104 }
105 else if (m<=0) {
106 return;
107 }
108
109 assert( m <= MAX_WIDTH );
110
111 /* zoom the span horizontally */
112 if (ctx->Pixel.ZoomX==-1.0F) {
113 /* n==m */
114 for (j=0;j<m;j++) {
115 i = n - (j+skipcol) - 1;
116 dstRGBA32[j] = srcRGBA32[i];
117 zdepth[j] = z[i];
118 }
119 if (fog && ctx->Fog.Enabled) {
120 for (j=0;j<m;j++) {
121 i = n - (j+skipcol) - 1;
122 zfog[j] = fog[i];
123 }
124 }
125 }
126 else {
127 GLfloat xscale = 1.0F / ctx->Pixel.ZoomX;
128 for (j=0;j<m;j++) {
129 i = (GLint) ((j+skipcol) * xscale);
130 if (i<0) i = n + i - 1;
131 dstRGBA32[j] = srcRGBA32[i];
132 zdepth[j] = z[i];
133 }
134 if (fog && ctx->Fog.Enabled) {
135 for (j=0;j<m;j++) {
136 i = (GLint) ((j+skipcol) * xscale);
137 if (i<0) i = n + i - 1;
138 zfog[j] = fog[i];
139 }
140 }
141 }
142
143 /* write the span */
144 for (r=r0; r<r1; r++) {
145 gl_write_rgba_span( ctx, m, x+skipcol, r, zdepth,
146 (fog ? zfog : 0),
147 zrgba, GL_BITMAP );
148 }
149 }
150
151
152
153 void
154 gl_write_zoomed_rgb_span( GLcontext *ctx,
155 GLuint n, GLint x, GLint y, const GLdepth z[],
156 const GLfixed *fog,
157 CONST GLchan rgb[][3], GLint y0 )
158 {
159 GLint m;
160 GLint r0, r1, row, r;
161 GLint i, j, skipcol;
162 GLchan zrgba[MAX_WIDTH][4]; /* zoomed pixel colors */
163 GLdepth zdepth[MAX_WIDTH]; /* zoomed depth values */
164 GLfixed zfog[MAX_WIDTH]; /* zoomed fog values */
165 GLint maxwidth = MIN2( ctx->DrawBuffer->Width, MAX_WIDTH );
166
167 /* compute width of output row */
168 m = (GLint) ABSF( n * ctx->Pixel.ZoomX );
169 if (m==0) {
170 return;
171 }
172 if (ctx->Pixel.ZoomX<0.0) {
173 /* adjust x coordinate for left/right mirroring */
174 x = x - m;
175 }
176
177 /* compute which rows to draw */
178 row = y-y0;
179 r0 = y0 + (GLint) (row * ctx->Pixel.ZoomY);
180 r1 = y0 + (GLint) ((row+1) * ctx->Pixel.ZoomY);
181 if (r0==r1) {
182 return;
183 }
184 else if (r1<r0) {
185 GLint rtmp = r1;
186 r1 = r0;
187 r0 = rtmp;
188 }
189
190 /* return early if r0...r1 is above or below window */
191 if (r0<0 && r1<0) {
192 /* below window */
193 return;
194 }
195 if (r0>=ctx->DrawBuffer->Height && r1>=ctx->DrawBuffer->Height) {
196 /* above window */
197 return;
198 }
199
200 /* check if left edge is outside window */
201 skipcol = 0;
202 if (x<0) {
203 skipcol = -x;
204 m += x;
205 }
206 /* make sure span isn't too long or short */
207 if (m>maxwidth) {
208 m = maxwidth;
209 }
210 else if (m<=0) {
211 return;
212 }
213
214 assert( m <= MAX_WIDTH );
215
216 /* zoom the span horizontally */
217 if (ctx->Pixel.ZoomX==-1.0F) {
218 /* n==m */
219 for (j=0;j<m;j++) {
220 i = n - (j+skipcol) - 1;
221 zrgba[j][0] = rgb[i][0];
222 zrgba[j][1] = rgb[i][1];
223 zrgba[j][2] = rgb[i][2];
224 zrgba[j][3] = CHAN_MAX;
225 zdepth[j] = z[i];
226 }
227 if (fog && ctx->Fog.Enabled) {
228 for (j=0;j<m;j++) {
229 i = n - (j+skipcol) - 1;
230 zfog[j] = fog[i];
231 }
232 }
233 }
234 else {
235 GLfloat xscale = 1.0F / ctx->Pixel.ZoomX;
236 for (j=0;j<m;j++) {
237 i = (GLint) ((j+skipcol) * xscale);
238 if (i<0) i = n + i - 1;
239 zrgba[j][0] = rgb[i][0];
240 zrgba[j][1] = rgb[i][1];
241 zrgba[j][2] = rgb[i][2];
242 zrgba[j][3] = CHAN_MAX;
243 zdepth[j] = z[i];
244 }
245 if (fog && ctx->Fog.Enabled) {
246 for (j=0;j<m;j++) {
247 i = (GLint) ((j+skipcol) * xscale);
248 if (i<0) i = n + i - 1;
249 zfog[j] = fog[i];
250 }
251 }
252 }
253
254 /* write the span */
255 for (r=r0; r<r1; r++) {
256 gl_write_rgba_span( ctx, m, x+skipcol, r, zdepth,
257 (fog ? zfog : 0), zrgba, GL_BITMAP );
258 }
259 }
260
261
262
263 /*
264 * As above, but write CI pixels.
265 */
266 void
267 gl_write_zoomed_index_span( GLcontext *ctx,
268 GLuint n, GLint x, GLint y, const GLdepth z[],
269 const GLfixed *fog,
270 const GLuint indexes[], GLint y0 )
271 {
272 GLint m;
273 GLint r0, r1, row, r;
274 GLint i, j, skipcol;
275 GLuint zindexes[MAX_WIDTH]; /* zoomed color indexes */
276 GLdepth zdepth[MAX_WIDTH]; /* zoomed depth values */
277 GLfixed zfog[MAX_WIDTH]; /* zoomed fog values */
278 GLint maxwidth = MIN2( ctx->DrawBuffer->Width, MAX_WIDTH );
279
280 /* compute width of output row */
281 m = (GLint) ABSF( n * ctx->Pixel.ZoomX );
282 if (m==0) {
283 return;
284 }
285 if (ctx->Pixel.ZoomX<0.0) {
286 /* adjust x coordinate for left/right mirroring */
287 x = x - m;
288 }
289
290 /* compute which rows to draw */
291 row = y-y0;
292 r0 = y0 + (GLint) (row * ctx->Pixel.ZoomY);
293 r1 = y0 + (GLint) ((row+1) * ctx->Pixel.ZoomY);
294 if (r0==r1) {
295 return;
296 }
297 else if (r1<r0) {
298 GLint rtmp = r1;
299 r1 = r0;
300 r0 = rtmp;
301 }
302
303 /* return early if r0...r1 is above or below window */
304 if (r0<0 && r1<0) {
305 /* below window */
306 return;
307 }
308 if (r0>=ctx->DrawBuffer->Height && r1>=ctx->DrawBuffer->Height) {
309 /* above window */
310 return;
311 }
312
313 /* check if left edge is outside window */
314 skipcol = 0;
315 if (x<0) {
316 skipcol = -x;
317 m += x;
318 }
319 /* make sure span isn't too long or short */
320 if (m>maxwidth) {
321 m = maxwidth;
322 }
323 else if (m<=0) {
324 return;
325 }
326
327 assert( m <= MAX_WIDTH );
328
329 /* zoom the span horizontally */
330 if (ctx->Pixel.ZoomX==-1.0F) {
331 /* n==m */
332 for (j=0;j<m;j++) {
333 i = n - (j+skipcol) - 1;
334 zindexes[j] = indexes[i];
335 zdepth[j] = z[i];
336 }
337 if (fog && ctx->Fog.Enabled) {
338 for (j=0;j<m;j++) {
339 i = n - (j+skipcol) - 1;
340 zfog[j] = fog[i];
341 }
342 }
343 }
344 else {
345 GLfloat xscale = 1.0F / ctx->Pixel.ZoomX;
346 for (j=0;j<m;j++) {
347 i = (GLint) ((j+skipcol) * xscale);
348 if (i<0) i = n + i - 1;
349 zindexes[j] = indexes[i];
350 zdepth[j] = z[i];
351 }
352 if (fog && ctx->Fog.Enabled) {
353 for (j=0;j<m;j++) {
354 i = (GLint) ((j+skipcol) * xscale);
355 if (i<0) i = n + i - 1;
356 zfog[j] = fog[i];
357 }
358 }
359 }
360
361 /* write the span */
362 for (r=r0; r<r1; r++) {
363 gl_write_index_span( ctx, m, x+skipcol, r, zdepth,
364 (fog ? zfog : 0), zindexes, GL_BITMAP );
365 }
366 }
367
368
369
370 /*
371 * As above, but write stencil values.
372 */
373 void
374 gl_write_zoomed_stencil_span( GLcontext *ctx,
375 GLuint n, GLint x, GLint y,
376 const GLstencil stencil[], GLint y0 )
377 {
378 GLint m;
379 GLint r0, r1, row, r;
380 GLint i, j, skipcol;
381 GLstencil zstencil[MAX_WIDTH]; /* zoomed stencil values */
382 GLint maxwidth = MIN2( ctx->DrawBuffer->Width, MAX_WIDTH );
383
384 /* compute width of output row */
385 m = (GLint) ABSF( n * ctx->Pixel.ZoomX );
386 if (m==0) {
387 return;
388 }
389 if (ctx->Pixel.ZoomX<0.0) {
390 /* adjust x coordinate for left/right mirroring */
391 x = x - m;
392 }
393
394 /* compute which rows to draw */
395 row = y-y0;
396 r0 = y0 + (GLint) (row * ctx->Pixel.ZoomY);
397 r1 = y0 + (GLint) ((row+1) * ctx->Pixel.ZoomY);
398 if (r0==r1) {
399 return;
400 }
401 else if (r1<r0) {
402 GLint rtmp = r1;
403 r1 = r0;
404 r0 = rtmp;
405 }
406
407 /* return early if r0...r1 is above or below window */
408 if (r0<0 && r1<0) {
409 /* below window */
410 return;
411 }
412 if (r0>=ctx->DrawBuffer->Height && r1>=ctx->DrawBuffer->Height) {
413 /* above window */
414 return;
415 }
416
417 /* check if left edge is outside window */
418 skipcol = 0;
419 if (x<0) {
420 skipcol = -x;
421 m += x;
422 }
423 /* make sure span isn't too long or short */
424 if (m>maxwidth) {
425 m = maxwidth;
426 }
427 else if (m<=0) {
428 return;
429 }
430
431 assert( m <= MAX_WIDTH );
432
433 /* zoom the span horizontally */
434 if (ctx->Pixel.ZoomX==-1.0F) {
435 /* n==m */
436 for (j=0;j<m;j++) {
437 i = n - (j+skipcol) - 1;
438 zstencil[j] = stencil[i];
439 }
440 }
441 else {
442 GLfloat xscale = 1.0F / ctx->Pixel.ZoomX;
443 for (j=0;j<m;j++) {
444 i = (GLint) ((j+skipcol) * xscale);
445 if (i<0) i = n + i - 1;
446 zstencil[j] = stencil[i];
447 }
448 }
449
450 /* write the span */
451 for (r=r0; r<r1; r++) {
452 _mesa_write_stencil_span( ctx, m, x+skipcol, r, zstencil );
453 }
454 }