Merge commit 'origin/master' into gallium-0.2
[mesa.git] / src / mesa / main / drawpix.c
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 */
42 void 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
120 void 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
186 void 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 = 0.0001F;
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 */
274 void 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