drawpix.c revision 7bf6efe78066b33c4ddd278d78ea44cfd12154cc
1/*
2 * Mesa 3-D graphics library
3 * Version:  7.1
4 *
5 * Copyright (C) 1999-2008  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 "bufferobj.h"
28#include "context.h"
29#include "drawpix.h"
30#include "enums.h"
31#include "feedback.h"
32#include "framebuffer.h"
33#include "image.h"
34#include "readpix.h"
35#include "state.h"
36
37
38
39/**
40 * If a fragment program is enabled, check that it's valid.
41 * \return GL_TRUE if valid, GL_FALSE otherwise
42 */
43static GLboolean
44valid_fragment_program(GLcontext *ctx)
45{
46   return !(ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled);
47}
48
49
50#if _HAVE_FULL_GL
51
52/*
53 * Execute glDrawPixels
54 */
55void GLAPIENTRY
56_mesa_DrawPixels( GLsizei width, GLsizei height,
57                  GLenum format, GLenum type, const GLvoid *pixels )
58{
59   GET_CURRENT_CONTEXT(ctx);
60   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
61
62   if (width < 0 || height < 0) {
63      _mesa_error( ctx, GL_INVALID_VALUE, "glDrawPixels(width or height < 0" );
64      return;
65   }
66
67   if (ctx->NewState) {
68      _mesa_update_state(ctx);
69   }
70
71   if (!valid_fragment_program(ctx)) {
72      _mesa_error(ctx, GL_INVALID_OPERATION,
73                  "glDrawPixels (invalid fragment program)");
74      return;
75   }
76
77   if (_mesa_error_check_format_type(ctx, format, type, GL_TRUE)) {
78      /* the error was already recorded */
79      return;
80   }
81
82   if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
83      _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
84                  "glDrawPixels(incomplete framebuffer)" );
85      return;
86   }
87
88   if (!ctx->Current.RasterPosValid) {
89      return; /* no-op, not an error */
90   }
91
92   if (ctx->RenderMode == GL_RENDER) {
93      if (width > 0 && height > 0) {
94         /* Round, to satisfy conformance tests (matches SGI's OpenGL) */
95         GLint x = IROUND(ctx->Current.RasterPos[0]);
96         GLint y = IROUND(ctx->Current.RasterPos[1]);
97
98         if (ctx->Unpack.BufferObj->Name) {
99            /* unpack from PBO */
100            if (!_mesa_validate_pbo_access(2, &ctx->Unpack, width, height, 1,
101                                           format, type, pixels)) {
102               _mesa_error(ctx, GL_INVALID_OPERATION,
103                           "glDrawPixels(invalid PBO access)");
104               return;
105            }
106            if (_mesa_bufferobj_mapped(ctx->Unpack.BufferObj)) {
107               /* buffer is mapped - that's an error */
108               _mesa_error(ctx, GL_INVALID_OPERATION,
109                           "glDrawPixels(PBO is mapped)");
110               return;
111            }
112         }
113
114         ctx->Driver.DrawPixels(ctx, x, y, width, height, format, type,
115                                &ctx->Unpack, pixels);
116      }
117   }
118   else if (ctx->RenderMode == GL_FEEDBACK) {
119      /* Feedback the current raster pos info */
120      FLUSH_CURRENT( ctx, 0 );
121      _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN );
122      _mesa_feedback_vertex( ctx,
123                             ctx->Current.RasterPos,
124                             ctx->Current.RasterColor,
125                             ctx->Current.RasterIndex,
126                             ctx->Current.RasterTexCoords[0] );
127   }
128   else {
129      ASSERT(ctx->RenderMode == GL_SELECT);
130      /* Do nothing.  See OpenGL Spec, Appendix B, Corollary 6. */
131   }
132}
133
134
135void GLAPIENTRY
136_mesa_CopyPixels( GLint srcx, GLint srcy, GLsizei width, GLsizei height,
137                  GLenum type )
138{
139   GET_CURRENT_CONTEXT(ctx);
140   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
141
142   if (width < 0 || height < 0) {
143      _mesa_error(ctx, GL_INVALID_VALUE, "glCopyPixels(width or height < 0)");
144      return;
145   }
146
147   if (type != GL_COLOR && type != GL_DEPTH && type != GL_STENCIL) {
148      _mesa_error(ctx, GL_INVALID_ENUM, "glCopyPixels(type=%s)",
149                  _mesa_lookup_enum_by_nr(type));
150      return;
151   }
152
153   if (ctx->NewState) {
154      _mesa_update_state(ctx);
155   }
156
157   if (!valid_fragment_program(ctx)) {
158      _mesa_error(ctx, GL_INVALID_OPERATION,
159                  "glCopyPixels (invalid fragment program)");
160      return;
161   }
162
163   if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT ||
164       ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
165      _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
166                  "glCopyPixels(incomplete framebuffer)" );
167      return;
168   }
169
170   if (!_mesa_source_buffer_exists(ctx, type) ||
171       !_mesa_dest_buffer_exists(ctx, type)) {
172      _mesa_error(ctx, GL_INVALID_OPERATION,
173                  "glCopyPixels(missing source or dest buffer)");
174      return;
175   }
176
177   if (!ctx->Current.RasterPosValid || width ==0 || height == 0) {
178      return; /* no-op, not an error */
179   }
180
181   if (ctx->RenderMode == GL_RENDER) {
182      /* Round to satisfy conformance tests (matches SGI's OpenGL) */
183      if (width > 0 && height > 0) {
184         GLint destx = IROUND(ctx->Current.RasterPos[0]);
185         GLint desty = IROUND(ctx->Current.RasterPos[1]);
186         ctx->Driver.CopyPixels( ctx, srcx, srcy, width, height, destx, desty,
187                                 type );
188      }
189   }
190   else if (ctx->RenderMode == GL_FEEDBACK) {
191      FLUSH_CURRENT( ctx, 0 );
192      _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_COPY_PIXEL_TOKEN );
193      _mesa_feedback_vertex( ctx,
194                             ctx->Current.RasterPos,
195                             ctx->Current.RasterColor,
196                             ctx->Current.RasterIndex,
197                             ctx->Current.RasterTexCoords[0] );
198   }
199   else {
200      ASSERT(ctx->RenderMode == GL_SELECT);
201      /* Do nothing.  See OpenGL Spec, Appendix B, Corollary 6. */
202   }
203}
204
205#endif /* _HAVE_FULL_GL */
206
207
208
209void GLAPIENTRY
210_mesa_Bitmap( GLsizei width, GLsizei height,
211              GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove,
212              const GLubyte *bitmap )
213{
214   GET_CURRENT_CONTEXT(ctx);
215   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
216
217   if (width < 0 || height < 0) {
218      _mesa_error( ctx, GL_INVALID_VALUE, "glBitmap(width or height < 0)" );
219      return;
220   }
221
222   if (!ctx->Current.RasterPosValid) {
223      return;    /* do nothing */
224   }
225
226   if (ctx->NewState) {
227      _mesa_update_state(ctx);
228   }
229
230   if (!valid_fragment_program(ctx)) {
231      _mesa_error(ctx, GL_INVALID_OPERATION,
232                  "glBitmap (invalid fragment program)");
233      return;
234   }
235
236   if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
237      _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
238                  "glBitmap(incomplete framebuffer)");
239      return;
240   }
241
242   if (ctx->RenderMode == GL_RENDER) {
243      /* Truncate, to satisfy conformance tests (matches SGI's OpenGL). */
244      const GLfloat epsilon = 0.0001F;
245      GLint x = IFLOOR(ctx->Current.RasterPos[0] + epsilon - xorig);
246      GLint y = IFLOOR(ctx->Current.RasterPos[1] + epsilon - yorig);
247
248      if (ctx->Unpack.BufferObj->Name) {
249         /* unpack from PBO */
250         if (!_mesa_validate_pbo_access(2, &ctx->Unpack, width, height, 1,
251                                        GL_COLOR_INDEX, GL_BITMAP,
252                                        (GLvoid *) bitmap)) {
253            _mesa_error(ctx, GL_INVALID_OPERATION,
254                        "glBitmap(invalid PBO access)");
255            return;
256         }
257         if (_mesa_bufferobj_mapped(ctx->Unpack.BufferObj)) {
258            /* buffer is mapped - that's an error */
259            _mesa_error(ctx, GL_INVALID_OPERATION, "glBitmap(PBO is mapped)");
260            return;
261         }
262      }
263
264      ctx->Driver.Bitmap( ctx, x, y, width, height, &ctx->Unpack, bitmap );
265   }
266#if _HAVE_FULL_GL
267   else if (ctx->RenderMode == GL_FEEDBACK) {
268      FLUSH_CURRENT(ctx, 0);
269      _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_BITMAP_TOKEN );
270      _mesa_feedback_vertex( ctx,
271                             ctx->Current.RasterPos,
272                             ctx->Current.RasterColor,
273                             ctx->Current.RasterIndex,
274                             ctx->Current.RasterTexCoords[0] );
275   }
276   else {
277      ASSERT(ctx->RenderMode == GL_SELECT);
278      /* Do nothing.  See OpenGL Spec, Appendix B, Corollary 6. */
279   }
280#endif
281
282   /* update raster position */
283   ctx->Current.RasterPos[0] += xmove;
284   ctx->Current.RasterPos[1] += ymove;
285}
286
287
288
289#if 0  /* experimental */
290/*
291 * Execute glDrawDepthPixelsMESA().  This function accepts both a color
292 * image and depth (Z) image.  Rasterization produces fragments with
293 * color and Z taken from these images.  This function is intended for
294 * Z-compositing.  Normally, this operation requires two glDrawPixels
295 * calls with stencil testing.
296 */
297void GLAPIENTRY
298_mesa_DrawDepthPixelsMESA( GLsizei width, GLsizei height,
299                           GLenum colorFormat, GLenum colorType,
300                           const GLvoid *colors,
301                           GLenum depthType, const GLvoid *depths )
302{
303   GET_CURRENT_CONTEXT(ctx);
304   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
305
306   if (width < 0 || height < 0) {
307      _mesa_error( ctx, GL_INVALID_VALUE,
308                   "glDrawDepthPixelsMESA(width or height < 0" );
309      return;
310   }
311
312   if (!ctx->Current.RasterPosValid) {
313      return;
314   }
315
316   if (ctx->NewState) {
317      _mesa_update_state(ctx);
318   }
319
320   if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
321      _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
322                  "glDrawDepthPixelsMESA(incomplete framebuffer)");
323      return;
324   }
325
326   if (ctx->RenderMode == GL_RENDER) {
327      /* Round, to satisfy conformance tests (matches SGI's OpenGL) */
328      GLint x = IROUND(ctx->Current.RasterPos[0]);
329      GLint y = IROUND(ctx->Current.RasterPos[1]);
330      ctx->Driver.DrawDepthPixelsMESA(ctx, x, y, width, height,
331                                      colorFormat, colorType, colors,
332                                      depthType, depths, &ctx->Unpack);
333   }
334   else if (ctx->RenderMode == GL_FEEDBACK) {
335      /* Feedback the current raster pos info */
336      FLUSH_CURRENT( ctx, 0 );
337      _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN );
338      _mesa_feedback_vertex( ctx,
339                             ctx->Current.RasterPos,
340                             ctx->Current.RasterColor,
341                             ctx->Current.RasterIndex,
342                             ctx->Current.RasterTexCoords[0] );
343   }
344   else {
345      ASSERT(ctx->RenderMode == GL_SELECT);
346      /* Do nothing.  See OpenGL Spec, Appendix B, Corollary 6. */
347   }
348}
349
350#endif
351