drawpix.c revision 99796464c5f0fdb463c31a0e99b0896089b8bd80
1/* 2 * Mesa 3-D graphics library 3 * Version: 6.5 4 * 5 * Copyright (C) 1999-2005 Brian Paul All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25#include "glheader.h" 26#include "imports.h" 27#include "context.h" 28#include "drawpix.h" 29#include "feedback.h" 30#include "image.h" 31#include "state.h" 32 33 34/** 35 * Do error checking of the format/type parameters to glReadPixels and 36 * glDrawPixels. 37 * \param drawing if GL_TRUE do checking for DrawPixels, else do checking 38 * for ReadPixels. 39 * \return GL_TRUE if error detected, GL_FALSE if no errors 40 */ 41static GLboolean 42error_check_format_type(GLcontext *ctx, GLenum format, GLenum type, 43 GLboolean drawing) 44{ 45 const char *readDraw = drawing ? "Draw" : "Read"; 46 47 /* basic combinations test */ 48 if (!_mesa_is_legal_format_and_type(ctx, format, type)) { 49 _mesa_error(ctx, GL_INVALID_ENUM, 50 "gl%sPixels(format or type)", readDraw); 51 return GL_TRUE; 52 } 53 54 /* additional checks */ 55 switch (format) { 56 case GL_RED: 57 case GL_GREEN: 58 case GL_BLUE: 59 case GL_ALPHA: 60 case GL_LUMINANCE: 61 case GL_LUMINANCE_ALPHA: 62 case GL_RGB: 63 case GL_BGR: 64 case GL_RGBA: 65 case GL_BGRA: 66 case GL_ABGR_EXT: 67 if (drawing && !ctx->Visual.rgbMode) { 68 _mesa_error(ctx, GL_INVALID_OPERATION, 69 "glDrawPixels(drawing RGB pixels into color index buffer)"); 70 return GL_TRUE; 71 } 72 break; 73 case GL_COLOR_INDEX: 74 if (!drawing && ctx->Visual.rgbMode) { 75 _mesa_error(ctx, GL_INVALID_OPERATION, 76 "glReadPixels(reading color index format from RGB buffer"); 77 return GL_TRUE; 78 } 79 break; 80 case GL_STENCIL_INDEX: 81 if (ctx->DrawBuffer->Visual.stencilBits == 0) { 82 _mesa_error(ctx, GL_INVALID_OPERATION, 83 "gl%sPixels(no stencil buffer)", readDraw); 84 return GL_TRUE; 85 } 86 break; 87 case GL_DEPTH_COMPONENT: 88 if (ctx->DrawBuffer->Visual.depthBits == 0) { 89 _mesa_error(ctx, GL_INVALID_OPERATION, 90 "gl%sPixels(no depth buffer)", readDraw); 91 return GL_TRUE; 92 } 93 break; 94 default: 95 /* this should have been caught in _mesa_is_legal_format_type() */ 96 _mesa_problem(ctx, "unexpected format in _mesa_%sPixels", readDraw); 97 return GL_TRUE; 98 } 99 100 /* no errors */ 101 return GL_FALSE; 102} 103 104 105 106#if _HAVE_FULL_GL 107 108/* 109 * Execute glDrawPixels 110 */ 111void GLAPIENTRY 112_mesa_DrawPixels( GLsizei width, GLsizei height, 113 GLenum format, GLenum type, const GLvoid *pixels ) 114{ 115 GET_CURRENT_CONTEXT(ctx); 116 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 117 118 if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) { 119 _mesa_error(ctx, GL_INVALID_OPERATION, 120 "glDrawPixels (invalid fragment program)"); 121 return; 122 } 123 124 if (width < 0 || height < 0) { 125 _mesa_error( ctx, GL_INVALID_VALUE, "glDrawPixels(width or height < 0" ); 126 return; 127 } 128 129 if (error_check_format_type(ctx, format, type, GL_TRUE)) { 130 /* found an error */ 131 return; 132 } 133 134 if (!ctx->Current.RasterPosValid) { 135 return; /* not an error */ 136 } 137 138 if (ctx->NewState) { 139 _mesa_update_state(ctx); 140 } 141 142 if (ctx->RenderMode == GL_RENDER) { 143 /* Round, to satisfy conformance tests (matches SGI's OpenGL) */ 144 GLint x = IROUND(ctx->Current.RasterPos[0]); 145 GLint y = IROUND(ctx->Current.RasterPos[1]); 146 ctx->Driver.DrawPixels(ctx, x, y, width, height, format, type, 147 &ctx->Unpack, pixels); 148 } 149 else if (ctx->RenderMode == GL_FEEDBACK) { 150 /* Feedback the current raster pos info */ 151 FLUSH_CURRENT( ctx, 0 ); 152 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN ); 153 _mesa_feedback_vertex( ctx, 154 ctx->Current.RasterPos, 155 ctx->Current.RasterColor, 156 ctx->Current.RasterIndex, 157 ctx->Current.RasterTexCoords[0] ); 158 } 159 else { 160 ASSERT(ctx->RenderMode == GL_SELECT); 161 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 162 } 163} 164 165 166void GLAPIENTRY 167_mesa_CopyPixels( GLint srcx, GLint srcy, GLsizei width, GLsizei height, 168 GLenum type ) 169{ 170 GET_CURRENT_CONTEXT(ctx); 171 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 172 173 if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) { 174 _mesa_error(ctx, GL_INVALID_OPERATION, 175 "glCopyPixels (invalid fragment program)"); 176 return; 177 } 178 179 if (width < 0 || height < 0) { 180 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyPixels(width or height < 0)"); 181 return; 182 } 183 184 switch (type) { 185 case GL_COLOR: 186 /* OK */ 187 break; 188 case GL_DEPTH: 189 if (ctx->DrawBuffer->Visual.depthBits == 0 || 190 ctx->ReadBuffer->Visual.depthBits == 0) { 191 _mesa_error(ctx, GL_INVALID_OPERATION, 192 "glCopyPixels(no depth buffer)"); 193 return; 194 } 195 break; 196 case GL_STENCIL: 197 if (ctx->DrawBuffer->Visual.stencilBits == 0 || 198 ctx->ReadBuffer->Visual.stencilBits == 0) { 199 _mesa_error(ctx, GL_INVALID_OPERATION, 200 "glCopyPixels(no stencil buffer)"); 201 return; 202 } 203 break; 204 default: 205 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyPixels"); 206 return; 207 } 208 209 if (ctx->NewState) { 210 _mesa_update_state(ctx); 211 } 212 213 if (!ctx->Current.RasterPosValid) { 214 return; 215 } 216 217 if (ctx->RenderMode == GL_RENDER) { 218 /* Round to satisfy conformance tests (matches SGI's OpenGL) */ 219 GLint destx = IROUND(ctx->Current.RasterPos[0]); 220 GLint desty = IROUND(ctx->Current.RasterPos[1]); 221 ctx->Driver.CopyPixels( ctx, srcx, srcy, width, height, destx, desty, 222 type ); 223 } 224 else if (ctx->RenderMode == GL_FEEDBACK) { 225 FLUSH_CURRENT( ctx, 0 ); 226 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_COPY_PIXEL_TOKEN ); 227 _mesa_feedback_vertex( ctx, 228 ctx->Current.RasterPos, 229 ctx->Current.RasterColor, 230 ctx->Current.RasterIndex, 231 ctx->Current.RasterTexCoords[0] ); 232 } 233 else { 234 ASSERT(ctx->RenderMode == GL_SELECT); 235 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 236 } 237} 238 239#endif /* _HAVE_FULL_GL */ 240 241 242 243void GLAPIENTRY 244_mesa_ReadPixels( GLint x, GLint y, GLsizei width, GLsizei height, 245 GLenum format, GLenum type, GLvoid *pixels ) 246{ 247 GET_CURRENT_CONTEXT(ctx); 248 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 249 250 if (width < 0 || height < 0) { 251 _mesa_error( ctx, GL_INVALID_VALUE, 252 "glReadPixels(width=%d height=%d)", width, height ); 253 return; 254 } 255 256 if (error_check_format_type(ctx, format, type, GL_FALSE)) { 257 /* found an error */ 258 return; 259 } 260 261 if (ctx->NewState) 262 _mesa_update_state(ctx); 263 264 ctx->Driver.ReadPixels(ctx, x, y, width, height, 265 format, type, &ctx->Pack, pixels); 266} 267 268 269 270void GLAPIENTRY 271_mesa_Bitmap( GLsizei width, GLsizei height, 272 GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, 273 const GLubyte *bitmap ) 274{ 275 GET_CURRENT_CONTEXT(ctx); 276 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 277 278 if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) { 279 _mesa_error(ctx, GL_INVALID_OPERATION, 280 "glBitmap (invalid fragment program)"); 281 return; 282 } 283 284 if (width < 0 || height < 0) { 285 _mesa_error( ctx, GL_INVALID_VALUE, "glBitmap(width or height < 0)" ); 286 return; 287 } 288 289 if (!ctx->Current.RasterPosValid) { 290 return; /* do nothing */ 291 } 292 293 if (ctx->NewState) { 294 _mesa_update_state(ctx); 295 } 296 297 if (ctx->RenderMode == GL_RENDER) { 298 /* Truncate, to satisfy conformance tests (matches SGI's OpenGL). */ 299 GLint x = IFLOOR(ctx->Current.RasterPos[0] - xorig); 300 GLint y = IFLOOR(ctx->Current.RasterPos[1] - yorig); 301 ctx->Driver.Bitmap( ctx, x, y, width, height, &ctx->Unpack, bitmap ); 302 } 303#if _HAVE_FULL_GL 304 else if (ctx->RenderMode == GL_FEEDBACK) { 305 FLUSH_CURRENT(ctx, 0); 306 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_BITMAP_TOKEN ); 307 _mesa_feedback_vertex( ctx, 308 ctx->Current.RasterPos, 309 ctx->Current.RasterColor, 310 ctx->Current.RasterIndex, 311 ctx->Current.RasterTexCoords[0] ); 312 } 313 else { 314 ASSERT(ctx->RenderMode == GL_SELECT); 315 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 316 } 317#endif 318 319 /* update raster position */ 320 ctx->Current.RasterPos[0] += xmove; 321 ctx->Current.RasterPos[1] += ymove; 322} 323 324 325 326#if 0 /* experimental */ 327/* 328 * Execute glDrawDepthPixelsMESA(). This function accepts both a color 329 * image and depth (Z) image. Rasterization produces fragments with 330 * color and Z taken from these images. This function is intended for 331 * Z-compositing. Normally, this operation requires two glDrawPixels 332 * calls with stencil testing. 333 */ 334void GLAPIENTRY 335_mesa_DrawDepthPixelsMESA( GLsizei width, GLsizei height, 336 GLenum colorFormat, GLenum colorType, 337 const GLvoid *colors, 338 GLenum depthType, const GLvoid *depths ) 339{ 340 GET_CURRENT_CONTEXT(ctx); 341 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 342 343 if (width < 0 || height < 0) { 344 _mesa_error( ctx, GL_INVALID_VALUE, 345 "glDrawDepthPixelsMESA(width or height < 0" ); 346 return; 347 } 348 349 if (!ctx->Current.RasterPosValid) { 350 return; 351 } 352 353 if (ctx->NewState) { 354 _mesa_update_state(ctx); 355 } 356 357 if (ctx->RenderMode == GL_RENDER) { 358 /* Round, to satisfy conformance tests (matches SGI's OpenGL) */ 359 GLint x = IROUND(ctx->Current.RasterPos[0]); 360 GLint y = IROUND(ctx->Current.RasterPos[1]); 361 ctx->Driver.DrawDepthPixelsMESA(ctx, x, y, width, height, 362 colorFormat, colorType, colors, 363 depthType, depths, &ctx->Unpack); 364 } 365 else if (ctx->RenderMode == GL_FEEDBACK) { 366 /* Feedback the current raster pos info */ 367 FLUSH_CURRENT( ctx, 0 ); 368 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN ); 369 _mesa_feedback_vertex( ctx, 370 ctx->Current.RasterPos, 371 ctx->Current.RasterColor, 372 ctx->Current.RasterIndex, 373 ctx->Current.RasterTexCoords[0] ); 374 } 375 else { 376 ASSERT(ctx->RenderMode == GL_SELECT); 377 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 378 } 379} 380 381#endif 382