fix GL_BACK color material bug
[mesa.git] / src / mesa / main / buffers.c
1
2 /*
3 * Mesa 3-D graphics library
4 * Version: 3.3
5 *
6 * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26
27 #ifdef PC_HEADER
28 #include "all.h"
29 #else
30 #include "glheader.h"
31 #include "accum.h"
32 #include "alphabuf.h"
33 #include "buffers.h"
34 #include "context.h"
35 #include "depth.h"
36 #include "enums.h"
37 #include "macros.h"
38 #include "masking.h"
39 #include "mem.h"
40 #include "stencil.h"
41 #include "state.h"
42 #include "types.h"
43 #endif
44
45
46
47 void
48 _mesa_ClearIndex( GLfloat c )
49 {
50 GET_CURRENT_CONTEXT(ctx);
51 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glClearIndex");
52 ctx->Color.ClearIndex = (GLuint) c;
53 if (!ctx->Visual->RGBAflag) {
54 /* it's OK to call glClearIndex in RGBA mode but it should be a NOP */
55 (*ctx->Driver.ClearIndex)( ctx, ctx->Color.ClearIndex );
56 }
57 }
58
59
60
61 void
62 _mesa_ClearColor( GLclampf red, GLclampf green,
63 GLclampf blue, GLclampf alpha )
64 {
65 GET_CURRENT_CONTEXT(ctx);
66 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glClearColor");
67
68 ctx->Color.ClearColor[0] = CLAMP( red, 0.0F, 1.0F );
69 ctx->Color.ClearColor[1] = CLAMP( green, 0.0F, 1.0F );
70 ctx->Color.ClearColor[2] = CLAMP( blue, 0.0F, 1.0F );
71 ctx->Color.ClearColor[3] = CLAMP( alpha, 0.0F, 1.0F );
72
73 if (ctx->Visual->RGBAflag) {
74 GLubyte r = (GLint) (ctx->Color.ClearColor[0] * 255.0F);
75 GLubyte g = (GLint) (ctx->Color.ClearColor[1] * 255.0F);
76 GLubyte b = (GLint) (ctx->Color.ClearColor[2] * 255.0F);
77 GLubyte a = (GLint) (ctx->Color.ClearColor[3] * 255.0F);
78 (*ctx->Driver.ClearColor)( ctx, r, g, b, a );
79 }
80 }
81
82
83
84
85 /*
86 * Clear the color buffer when glColorMask or glIndexMask is in effect.
87 */
88 static void
89 clear_color_buffer_with_masking( GLcontext *ctx )
90 {
91 const GLint x = ctx->DrawBuffer->Xmin;
92 const GLint y = ctx->DrawBuffer->Ymin;
93 const GLint height = ctx->DrawBuffer->Ymax - ctx->DrawBuffer->Ymin + 1;
94 const GLint width = ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin + 1;
95
96 if (ctx->Visual->RGBAflag) {
97 /* RGBA mode */
98 const GLubyte r = (GLint) (ctx->Color.ClearColor[0] * 255.0F);
99 const GLubyte g = (GLint) (ctx->Color.ClearColor[1] * 255.0F);
100 const GLubyte b = (GLint) (ctx->Color.ClearColor[2] * 255.0F);
101 const GLubyte a = (GLint) (ctx->Color.ClearColor[3] * 255.0F);
102 GLint i;
103 for (i = 0; i < height; i++) {
104 GLubyte rgba[MAX_WIDTH][4];
105 GLint j;
106 for (j=0; j<width; j++) {
107 rgba[j][RCOMP] = r;
108 rgba[j][GCOMP] = g;
109 rgba[j][BCOMP] = b;
110 rgba[j][ACOMP] = a;
111 }
112 _mesa_mask_rgba_span( ctx, width, x, y + i, rgba );
113 (*ctx->Driver.WriteRGBASpan)( ctx, width, x, y + i,
114 (CONST GLubyte (*)[4])rgba, NULL );
115 }
116 }
117 else {
118 /* Color index mode */
119 GLuint span[MAX_WIDTH];
120 GLubyte mask[MAX_WIDTH];
121 GLint i, j;
122 MEMSET( mask, 1, width );
123 for (i=0;i<height;i++) {
124 for (j=0;j<width;j++) {
125 span[j] = ctx->Color.ClearIndex;
126 }
127 _mesa_mask_index_span( ctx, width, x, y + i, span );
128 (*ctx->Driver.WriteCI32Span)( ctx, width, x, y + i, span, mask );
129 }
130 }
131 }
132
133
134
135 /*
136 * Clear a color buffer without index/channel masking.
137 */
138 static void
139 clear_color_buffer(GLcontext *ctx)
140 {
141 const GLint x = ctx->DrawBuffer->Xmin;
142 const GLint y = ctx->DrawBuffer->Ymin;
143 const GLint height = ctx->DrawBuffer->Ymax - ctx->DrawBuffer->Ymin + 1;
144 const GLint width = ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin + 1;
145
146 if (ctx->Visual->RGBAflag) {
147 /* RGBA mode */
148 const GLubyte r = (GLint) (ctx->Color.ClearColor[0] * 255.0F);
149 const GLubyte g = (GLint) (ctx->Color.ClearColor[1] * 255.0F);
150 const GLubyte b = (GLint) (ctx->Color.ClearColor[2] * 255.0F);
151 const GLubyte a = (GLint) (ctx->Color.ClearColor[3] * 255.0F);
152 GLubyte span[MAX_WIDTH][4];
153 GLint i;
154 ASSERT(ctx->Color.ColorMask[0] &&
155 ctx->Color.ColorMask[1] &&
156 ctx->Color.ColorMask[2] &&
157 ctx->Color.ColorMask[3]);
158 for (i = 0; i < width; i++) {
159 span[i][RCOMP] = r;
160 span[i][GCOMP] = g;
161 span[i][BCOMP] = b;
162 span[i][ACOMP] = a;
163 }
164 for (i = 0; i < height; i++) {
165 (*ctx->Driver.WriteRGBASpan)( ctx, width, x, y + i,
166 (CONST GLubyte (*)[4]) span, NULL );
167 }
168 }
169 else {
170 /* Color index mode */
171 ASSERT(ctx->Color.IndexMask == ~0);
172 if (ctx->Visual->IndexBits == 8) {
173 /* 8-bit clear */
174 GLubyte span[MAX_WIDTH];
175 GLint i;
176 MEMSET(span, ctx->Color.ClearIndex, width);
177 for (i = 0; i < height; i++) {
178 (*ctx->Driver.WriteCI8Span)( ctx, width, x, y + i, span, NULL );
179 }
180 }
181 else {
182 /* non 8-bit clear */
183 GLuint span[MAX_WIDTH];
184 GLint i;
185 for (i = 0; i < width; i++) {
186 span[i] = ctx->Color.ClearIndex;
187 }
188 for (i = 0; i < height; i++) {
189 (*ctx->Driver.WriteCI32Span)( ctx, width, x, y + i, span, NULL );
190 }
191 }
192 }
193 }
194
195
196
197 /*
198 * Clear the front/back/left/right color buffers.
199 * This function is usually only called if we need to clear the
200 * buffers with masking.
201 */
202 static void
203 clear_color_buffers(GLcontext *ctx)
204 {
205 GLuint bufferBit;
206
207 /* loop over four possible dest color buffers */
208 for (bufferBit = 1; bufferBit <= 8; bufferBit = bufferBit << 1) {
209 if (bufferBit & ctx->Color.DrawDestMask) {
210 if (bufferBit == FRONT_LEFT_BIT) {
211 (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_LEFT);
212 }
213 else if (bufferBit == FRONT_RIGHT_BIT) {
214 (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_RIGHT);
215 }
216 else if (bufferBit == BACK_LEFT_BIT) {
217 (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_LEFT);
218 }
219 else {
220 (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_RIGHT);
221 }
222
223 if (ctx->Color.SWmasking) {
224 clear_color_buffer_with_masking(ctx);
225 }
226 else {
227 clear_color_buffer(ctx);
228 }
229 }
230 }
231
232 /* restore default dest buffer */
233 (void) (*ctx->Driver.SetDrawBuffer)( ctx, ctx->Color.DriverDrawBuffer );
234 }
235
236
237
238 void
239 _mesa_Clear( GLbitfield mask )
240 {
241 GET_CURRENT_CONTEXT(ctx);
242 #ifdef PROFILE
243 GLdouble t0 = gl_time();
244 #endif
245 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glClear");
246
247 if (MESA_VERBOSE & VERBOSE_API)
248 fprintf(stderr, "glClear 0x%x\n", mask);
249
250 if (ctx->NewState) {
251 gl_update_state( ctx );
252 }
253
254 if (ctx->RenderMode==GL_RENDER) {
255 const GLint x = ctx->DrawBuffer->Xmin;
256 const GLint y = ctx->DrawBuffer->Ymin;
257 const GLint height = ctx->DrawBuffer->Ymax - ctx->DrawBuffer->Ymin + 1;
258 const GLint width = ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin + 1;
259 GLbitfield ddMask;
260 GLbitfield newMask;
261
262 /* don't clear depth buffer if depth writing disabled */
263 if (!ctx->Depth.Mask)
264 CLEAR_BITS(mask, GL_DEPTH_BUFFER_BIT);
265
266 /* Build bitmask to send to driver Clear function */
267 ddMask = mask & (GL_DEPTH_BUFFER_BIT |
268 GL_STENCIL_BUFFER_BIT |
269 GL_ACCUM_BUFFER_BIT);
270 if (mask & GL_COLOR_BUFFER_BIT) {
271 ddMask |= ctx->Color.DrawDestMask;
272 }
273
274 ASSERT(ctx->Driver.Clear);
275 newMask = (*ctx->Driver.Clear)( ctx, ddMask, !ctx->Scissor.Enabled,
276 x, y, width, height );
277
278 #ifdef DEBUG
279 {
280 GLbitfield legalBits = DD_FRONT_LEFT_BIT |
281 DD_FRONT_RIGHT_BIT |
282 DD_BACK_LEFT_BIT |
283 DD_BACK_RIGHT_BIT |
284 DD_DEPTH_BIT |
285 DD_STENCIL_BIT |
286 DD_ACCUM_BIT;
287 assert((newMask & (~legalBits)) == 0);
288 }
289 #endif
290
291 /* do software clearing here */
292 if (newMask) {
293 if (newMask & ctx->Color.DrawDestMask) clear_color_buffers(ctx);
294 if (newMask & GL_DEPTH_BUFFER_BIT) _mesa_clear_depth_buffer(ctx);
295 if (newMask & GL_ACCUM_BUFFER_BIT) _mesa_clear_accum_buffer(ctx);
296 if (newMask & GL_STENCIL_BUFFER_BIT) _mesa_clear_stencil_buffer(ctx);
297 }
298
299 /* clear software-based alpha buffer(s) */
300 if ( (mask & GL_COLOR_BUFFER_BIT)
301 && ctx->DrawBuffer->UseSoftwareAlphaBuffers
302 && ctx->Color.ColorMask[RCOMP]) {
303 _mesa_clear_alpha_buffers( ctx );
304 }
305
306 #ifdef PROFILE
307 ctx->ClearTime += gl_time() - t0;
308 ctx->ClearCount++;
309 #endif
310 }
311 }
312
313
314 void
315 _mesa_DrawBuffer( GLenum mode )
316 {
317 GET_CURRENT_CONTEXT(ctx);
318 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glDrawBuffer");
319
320 if (MESA_VERBOSE & VERBOSE_API)
321 fprintf(stderr, "glDrawBuffer %s\n", gl_lookup_enum_by_nr(mode));
322
323 switch (mode) {
324 case GL_AUX0:
325 case GL_AUX1:
326 case GL_AUX2:
327 case GL_AUX3:
328 /* AUX buffers not implemented in Mesa at this time */
329 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
330 return;
331 case GL_RIGHT:
332 if (!ctx->Visual->StereoFlag) {
333 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
334 return;
335 }
336 if (ctx->Visual->DBflag)
337 ctx->Color.DrawDestMask = FRONT_RIGHT_BIT | BACK_RIGHT_BIT;
338 else
339 ctx->Color.DrawDestMask = FRONT_RIGHT_BIT;
340 break;
341 case GL_FRONT_RIGHT:
342 if (!ctx->Visual->StereoFlag) {
343 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
344 return;
345 }
346 ctx->Color.DrawDestMask = FRONT_RIGHT_BIT;
347 break;
348 case GL_BACK_RIGHT:
349 if (!ctx->Visual->StereoFlag) {
350 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
351 return;
352 }
353 if (!ctx->Visual->DBflag) {
354 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
355 return;
356 }
357 ctx->Color.DrawDestMask = BACK_RIGHT_BIT;
358 break;
359 case GL_BACK_LEFT:
360 if (!ctx->Visual->DBflag) {
361 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
362 return;
363 }
364 ctx->Color.DrawDestMask = BACK_LEFT_BIT;
365 break;
366 case GL_FRONT_AND_BACK:
367 if (!ctx->Visual->DBflag) {
368 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
369 return;
370 }
371 if (ctx->Visual->StereoFlag)
372 ctx->Color.DrawDestMask = FRONT_LEFT_BIT | BACK_LEFT_BIT
373 | FRONT_RIGHT_BIT | BACK_RIGHT_BIT;
374 else
375 ctx->Color.DrawDestMask = FRONT_LEFT_BIT | BACK_LEFT_BIT;
376 break;
377 case GL_BACK:
378 if (!ctx->Visual->DBflag) {
379 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
380 return;
381 }
382 if (ctx->Visual->StereoFlag)
383 ctx->Color.DrawDestMask = BACK_LEFT_BIT | BACK_RIGHT_BIT;
384 else
385 ctx->Color.DrawDestMask = BACK_LEFT_BIT;
386 break;
387 case GL_LEFT:
388 /* never an error */
389 if (ctx->Visual->DBflag)
390 ctx->Color.DrawDestMask = FRONT_LEFT_BIT | BACK_LEFT_BIT;
391 else
392 ctx->Color.DrawDestMask = FRONT_LEFT_BIT;
393 break;
394 case GL_FRONT_LEFT:
395 /* never an error */
396 ctx->Color.DrawDestMask = FRONT_LEFT_BIT;
397 break;
398 case GL_FRONT:
399 /* never an error */
400 if (ctx->Visual->StereoFlag)
401 ctx->Color.DrawDestMask = FRONT_LEFT_BIT | FRONT_RIGHT_BIT;
402 else
403 ctx->Color.DrawDestMask = FRONT_LEFT_BIT;
404 break;
405 case GL_NONE:
406 /* never an error */
407 ctx->Color.DrawDestMask = 0;
408 break;
409 default:
410 gl_error( ctx, GL_INVALID_ENUM, "glDrawBuffer" );
411 return;
412 }
413
414 /*
415 * Make the dest buffer mode more precise if possible
416 */
417 if (mode == GL_LEFT && !ctx->Visual->DBflag)
418 ctx->Color.DriverDrawBuffer = GL_FRONT_LEFT;
419 else if (mode == GL_RIGHT && !ctx->Visual->DBflag)
420 ctx->Color.DriverDrawBuffer = GL_FRONT_RIGHT;
421 else if (mode == GL_FRONT && !ctx->Visual->StereoFlag)
422 ctx->Color.DriverDrawBuffer = GL_FRONT_LEFT;
423 else if (mode == GL_BACK && !ctx->Visual->StereoFlag)
424 ctx->Color.DriverDrawBuffer = GL_BACK_LEFT;
425 else
426 ctx->Color.DriverDrawBuffer = mode;
427
428 /*
429 * Set current alpha buffer pointer
430 */
431 if (ctx->DrawBuffer->UseSoftwareAlphaBuffers) {
432 if (ctx->Color.DriverDrawBuffer == GL_FRONT_LEFT)
433 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->FrontLeftAlpha;
434 else if (ctx->Color.DriverDrawBuffer == GL_BACK_LEFT)
435 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->BackLeftAlpha;
436 else if (ctx->Color.DriverDrawBuffer == GL_FRONT_RIGHT)
437 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->FrontRightAlpha;
438 else if (ctx->Color.DriverDrawBuffer == GL_BACK_RIGHT)
439 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->BackRightAlpha;
440 }
441
442 /*
443 * If we get here there can't have been an error.
444 * Now see if device driver can implement the drawing to the target
445 * buffer(s). The driver may not be able to do GL_FRONT_AND_BACK mode
446 * for example. We'll take care of that in the core code by looping
447 * over the individual buffers.
448 */
449 ASSERT(ctx->Driver.SetDrawBuffer);
450 if ( (*ctx->Driver.SetDrawBuffer)(ctx, ctx->Color.DriverDrawBuffer) ) {
451 /* All OK, the driver will do all buffer writes */
452 ctx->Color.MultiDrawBuffer = GL_FALSE;
453 }
454 else {
455 /* We'll have to loop over the multiple draw buffer targets */
456 ctx->Color.MultiDrawBuffer = GL_TRUE;
457 /* Set drawing buffer to front for now */
458 (void) (*ctx->Driver.SetDrawBuffer)(ctx, GL_FRONT_LEFT);
459 }
460
461 ctx->Color.DrawBuffer = mode;
462 ctx->NewState |= NEW_RASTER_OPS;
463 }
464
465
466
467 void
468 _mesa_ReadBuffer( GLenum mode )
469 {
470 GET_CURRENT_CONTEXT(ctx);
471 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glReadBuffer");
472
473 if (MESA_VERBOSE & VERBOSE_API)
474 fprintf(stderr, "glReadBuffer %s\n", gl_lookup_enum_by_nr(mode));
475
476 switch (mode) {
477 case GL_AUX0:
478 case GL_AUX1:
479 case GL_AUX2:
480 case GL_AUX3:
481 /* AUX buffers not implemented in Mesa at this time */
482 gl_error( ctx, GL_INVALID_OPERATION, "glReadBuffer" );
483 return;
484 case GL_LEFT:
485 case GL_FRONT:
486 case GL_FRONT_LEFT:
487 /* Front-Left buffer, always exists */
488 ctx->Pixel.DriverReadBuffer = GL_FRONT_LEFT;
489 break;
490 case GL_BACK:
491 case GL_BACK_LEFT:
492 /* Back-Left buffer, requires double buffering */
493 if (!ctx->Visual->DBflag) {
494 gl_error( ctx, GL_INVALID_OPERATION, "glReadBuffer" );
495 return;
496 }
497 ctx->Pixel.DriverReadBuffer = GL_BACK_LEFT;
498 break;
499 case GL_FRONT_RIGHT:
500 case GL_RIGHT:
501 if (!ctx->Visual->StereoFlag) {
502 gl_error( ctx, GL_INVALID_OPERATION, "glReadBuffer" );
503 return;
504 }
505 ctx->Pixel.DriverReadBuffer = GL_FRONT_RIGHT;
506 break;
507 case GL_BACK_RIGHT:
508 if (!ctx->Visual->StereoFlag || !ctx->Visual->DBflag) {
509 gl_error( ctx, GL_INVALID_OPERATION, "glReadBuffer" );
510 return;
511 }
512 ctx->Pixel.DriverReadBuffer = GL_BACK_RIGHT;
513 break;
514 default:
515 gl_error( ctx, GL_INVALID_ENUM, "glReadBuffer" );
516 return;
517 }
518
519 ctx->Pixel.ReadBuffer = mode;
520 ctx->NewState |= NEW_RASTER_OPS;
521 }
522
523
524 /*
525 * GL_MESA_resize_buffers extension
526 */
527 void
528 _mesa_ResizeBuffersMESA( void )
529 {
530 GLcontext *ctx = gl_get_current_context();
531
532 GLuint buf_width, buf_height;
533
534 if (MESA_VERBOSE & VERBOSE_API)
535 fprintf(stderr, "glResizeBuffersMESA\n");
536
537 /* ask device driver for size of output buffer */
538 (*ctx->Driver.GetBufferSize)( ctx, &buf_width, &buf_height );
539
540 /* see if size of device driver's color buffer (window) has changed */
541 if (ctx->DrawBuffer->Width == (GLint) buf_width &&
542 ctx->DrawBuffer->Height == (GLint) buf_height)
543 return;
544
545 ctx->NewState |= NEW_RASTER_OPS; /* to update scissor / window bounds */
546
547 /* save buffer size */
548 ctx->DrawBuffer->Width = buf_width;
549 ctx->DrawBuffer->Height = buf_height;
550
551 /* Reallocate other buffers if needed. */
552 if (ctx->DrawBuffer->UseSoftwareDepthBuffer) {
553 _mesa_alloc_depth_buffer( ctx );
554 }
555 if (ctx->DrawBuffer->UseSoftwareStencilBuffer) {
556 _mesa_alloc_stencil_buffer( ctx );
557 }
558 if (ctx->DrawBuffer->UseSoftwareAccumBuffer) {
559 _mesa_alloc_accum_buffer( ctx );
560 }
561 if (ctx->DrawBuffer->UseSoftwareAlphaBuffers) {
562 _mesa_alloc_alpha_buffers( ctx );
563 }
564 }