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