blob: 63dfd053dff73d3a55d048378ef33d79e956e6eb [file] [log] [blame]
Brian Paulf7b57072000-03-20 14:37:52 +00001/* $Id: teximage.c,v 1.20 2000/03/20 14:37:54 brianp Exp $ */
jtgafb833d1999-08-19 00:55:39 +00002
3/*
4 * Mesa 3-D graphics library
Brian Paulfbd8f211999-11-11 01:22:25 +00005 * Version: 3.3
jtgafb833d1999-08-19 00:55:39 +00006 *
Brian Paul663049a2000-01-31 23:10:16 +00007 * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
jtgafb833d1999-08-19 00:55:39 +00008 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27
28#ifdef PC_HEADER
29#include "all.h"
30#else
Brian Paulfbd8f211999-11-11 01:22:25 +000031#include "glheader.h"
jtgafb833d1999-08-19 00:55:39 +000032#include "context.h"
33#include "image.h"
Brian Paulfbd8f211999-11-11 01:22:25 +000034#include "mem.h"
jtgafb833d1999-08-19 00:55:39 +000035#include "mmath.h"
36#include "span.h"
37#include "teximage.h"
38#include "texstate.h"
39#include "types.h"
jtgafb833d1999-08-19 00:55:39 +000040#endif
41
42
43/*
44 * NOTES:
45 *
Brian Paulc3f0a511999-11-03 17:27:05 +000046 * Mesa's native texture datatype is GLubyte. Native formats are
47 * GL_ALPHA, GL_LUMINANCE, GL_LUMANCE_ALPHA, GL_INTENSITY, GL_RGB, GL_RGBA,
48 * and GL_COLOR_INDEX.
49 * Device drivers are free to implement any internal format they want.
jtgafb833d1999-08-19 00:55:39 +000050 */
51
52
Brian Paulf7b57072000-03-20 14:37:52 +000053/*
54 * Default pixel packing of Mesa's internal texture images:
55 */
56static struct gl_pixelstore_attrib DefaultPacking = {
57 1, /* Alignment */
58 0, /* RowLength */
59 0, /* SkipPixels */
60 0, /* SkipRows */
61 0, /* ImageHeight */
62 0, /* SkipImages */
63 GL_FALSE, /* SwapBytes */
64 GL_FALSE /* LsbFirst */
65};
66
67
jtgafb833d1999-08-19 00:55:39 +000068
jtgafb833d1999-08-19 00:55:39 +000069/*
70 * Compute log base 2 of n.
71 * If n isn't an exact power of two return -1.
72 * If n<0 return -1.
73 */
Brian Paulfbd8f211999-11-11 01:22:25 +000074static int
75logbase2( int n )
jtgafb833d1999-08-19 00:55:39 +000076{
77 GLint i = 1;
78 GLint log2 = 0;
79
80 if (n<0) {
81 return -1;
82 }
83
84 while ( n > i ) {
85 i *= 2;
86 log2++;
87 }
88 if (i != n) {
89 return -1;
90 }
91 else {
92 return log2;
93 }
94}
95
96
97
98/*
99 * Given an internal texture format enum or 1, 2, 3, 4 return the
100 * corresponding _base_ internal format: GL_ALPHA, GL_LUMINANCE,
Brian Paulc3f0a511999-11-03 17:27:05 +0000101 * GL_LUMANCE_ALPHA, GL_INTENSITY, GL_RGB, or GL_RGBA.
102 * Return -1 if invalid enum.
jtgafb833d1999-08-19 00:55:39 +0000103 */
Brian Paulfbd8f211999-11-11 01:22:25 +0000104static GLint
105decode_internal_format( GLint format )
jtgafb833d1999-08-19 00:55:39 +0000106{
107 switch (format) {
108 case GL_ALPHA:
109 case GL_ALPHA4:
110 case GL_ALPHA8:
111 case GL_ALPHA12:
112 case GL_ALPHA16:
113 return GL_ALPHA;
114 case 1:
115 case GL_LUMINANCE:
116 case GL_LUMINANCE4:
117 case GL_LUMINANCE8:
118 case GL_LUMINANCE12:
119 case GL_LUMINANCE16:
120 return GL_LUMINANCE;
121 case 2:
122 case GL_LUMINANCE_ALPHA:
123 case GL_LUMINANCE4_ALPHA4:
124 case GL_LUMINANCE6_ALPHA2:
125 case GL_LUMINANCE8_ALPHA8:
126 case GL_LUMINANCE12_ALPHA4:
127 case GL_LUMINANCE12_ALPHA12:
128 case GL_LUMINANCE16_ALPHA16:
129 return GL_LUMINANCE_ALPHA;
130 case GL_INTENSITY:
131 case GL_INTENSITY4:
132 case GL_INTENSITY8:
133 case GL_INTENSITY12:
134 case GL_INTENSITY16:
135 return GL_INTENSITY;
136 case 3:
137 case GL_RGB:
138 case GL_R3_G3_B2:
139 case GL_RGB4:
140 case GL_RGB5:
141 case GL_RGB8:
142 case GL_RGB10:
143 case GL_RGB12:
144 case GL_RGB16:
145 return GL_RGB;
146 case 4:
147 case GL_RGBA:
148 case GL_RGBA2:
149 case GL_RGBA4:
150 case GL_RGB5_A1:
151 case GL_RGBA8:
152 case GL_RGB10_A2:
153 case GL_RGBA12:
154 case GL_RGBA16:
155 return GL_RGBA;
156 case GL_COLOR_INDEX:
157 case GL_COLOR_INDEX1_EXT:
158 case GL_COLOR_INDEX2_EXT:
159 case GL_COLOR_INDEX4_EXT:
160 case GL_COLOR_INDEX8_EXT:
161 case GL_COLOR_INDEX12_EXT:
162 case GL_COLOR_INDEX16_EXT:
163 return GL_COLOR_INDEX;
164 default:
165 return -1; /* error */
166 }
167}
168
169
170
171/*
172 * Given an internal texture format enum or 1, 2, 3, 4 return the
173 * corresponding _base_ internal format: GL_ALPHA, GL_LUMINANCE,
174 * GL_LUMANCE_ALPHA, GL_INTENSITY, GL_RGB, or GL_RGBA. Return the
175 * number of components for the format. Return -1 if invalid enum.
176 */
Brian Paulfbd8f211999-11-11 01:22:25 +0000177static GLint
178components_in_intformat( GLint format )
jtgafb833d1999-08-19 00:55:39 +0000179{
180 switch (format) {
181 case GL_ALPHA:
182 case GL_ALPHA4:
183 case GL_ALPHA8:
184 case GL_ALPHA12:
185 case GL_ALPHA16:
186 return 1;
187 case 1:
188 case GL_LUMINANCE:
189 case GL_LUMINANCE4:
190 case GL_LUMINANCE8:
191 case GL_LUMINANCE12:
192 case GL_LUMINANCE16:
193 return 1;
194 case 2:
195 case GL_LUMINANCE_ALPHA:
196 case GL_LUMINANCE4_ALPHA4:
197 case GL_LUMINANCE6_ALPHA2:
198 case GL_LUMINANCE8_ALPHA8:
199 case GL_LUMINANCE12_ALPHA4:
200 case GL_LUMINANCE12_ALPHA12:
201 case GL_LUMINANCE16_ALPHA16:
202 return 2;
203 case GL_INTENSITY:
204 case GL_INTENSITY4:
205 case GL_INTENSITY8:
206 case GL_INTENSITY12:
207 case GL_INTENSITY16:
208 return 1;
209 case 3:
210 case GL_RGB:
211 case GL_R3_G3_B2:
212 case GL_RGB4:
213 case GL_RGB5:
214 case GL_RGB8:
215 case GL_RGB10:
216 case GL_RGB12:
217 case GL_RGB16:
218 return 3;
219 case 4:
220 case GL_RGBA:
221 case GL_RGBA2:
222 case GL_RGBA4:
223 case GL_RGB5_A1:
224 case GL_RGBA8:
225 case GL_RGB10_A2:
226 case GL_RGBA12:
227 case GL_RGBA16:
228 return 4;
229 case GL_COLOR_INDEX:
230 case GL_COLOR_INDEX1_EXT:
231 case GL_COLOR_INDEX2_EXT:
232 case GL_COLOR_INDEX4_EXT:
233 case GL_COLOR_INDEX8_EXT:
234 case GL_COLOR_INDEX12_EXT:
235 case GL_COLOR_INDEX16_EXT:
236 return 1;
237 default:
238 return -1; /* error */
239 }
240}
241
242
243
Brian Paulfbd8f211999-11-11 01:22:25 +0000244struct gl_texture_image *
245gl_alloc_texture_image( void )
jtgafb833d1999-08-19 00:55:39 +0000246{
Brian Paulbd5cdaf1999-10-13 18:42:49 +0000247 return CALLOC_STRUCT(gl_texture_image);
jtgafb833d1999-08-19 00:55:39 +0000248}
249
250
251
Brian Paulfbd8f211999-11-11 01:22:25 +0000252void
253gl_free_texture_image( struct gl_texture_image *teximage )
jtgafb833d1999-08-19 00:55:39 +0000254{
255 if (teximage->Data) {
Brian Paulbd5cdaf1999-10-13 18:42:49 +0000256 FREE( teximage->Data );
Brian Paul91baaa31999-10-17 23:24:16 +0000257 teximage->Data = NULL;
jtgafb833d1999-08-19 00:55:39 +0000258 }
Brian Paulbd5cdaf1999-10-13 18:42:49 +0000259 FREE( teximage );
jtgafb833d1999-08-19 00:55:39 +0000260}
261
262
263
264/*
265 * Examine the texImage->Format field and set the Red, Green, Blue, etc
266 * texel component sizes to default values.
267 * These fields are set only here by core Mesa but device drivers may
268 * overwritting these fields to indicate true texel resolution.
269 */
Brian Paulfbd8f211999-11-11 01:22:25 +0000270static void
271set_teximage_component_sizes( struct gl_texture_image *texImage )
jtgafb833d1999-08-19 00:55:39 +0000272{
273 switch (texImage->Format) {
274 case GL_ALPHA:
275 texImage->RedBits = 0;
276 texImage->GreenBits = 0;
277 texImage->BlueBits = 0;
278 texImage->AlphaBits = 8;
279 texImage->IntensityBits = 0;
280 texImage->LuminanceBits = 0;
281 texImage->IndexBits = 0;
282 break;
283 case GL_LUMINANCE:
284 texImage->RedBits = 0;
285 texImage->GreenBits = 0;
286 texImage->BlueBits = 0;
287 texImage->AlphaBits = 0;
288 texImage->IntensityBits = 0;
289 texImage->LuminanceBits = 8;
290 texImage->IndexBits = 0;
291 break;
292 case GL_LUMINANCE_ALPHA:
293 texImage->RedBits = 0;
294 texImage->GreenBits = 0;
295 texImage->BlueBits = 0;
296 texImage->AlphaBits = 8;
297 texImage->IntensityBits = 0;
298 texImage->LuminanceBits = 8;
299 texImage->IndexBits = 0;
300 break;
301 case GL_INTENSITY:
302 texImage->RedBits = 0;
303 texImage->GreenBits = 0;
304 texImage->BlueBits = 0;
305 texImage->AlphaBits = 0;
306 texImage->IntensityBits = 8;
307 texImage->LuminanceBits = 0;
308 texImage->IndexBits = 0;
309 break;
Brian Paul91baaa31999-10-17 23:24:16 +0000310 case GL_RED:
311 texImage->RedBits = 8;
312 texImage->GreenBits = 0;
313 texImage->BlueBits = 0;
314 texImage->AlphaBits = 0;
315 texImage->IntensityBits = 0;
316 texImage->LuminanceBits = 0;
317 texImage->IndexBits = 0;
318 break;
319 case GL_GREEN:
320 texImage->RedBits = 0;
321 texImage->GreenBits = 8;
322 texImage->BlueBits = 0;
323 texImage->AlphaBits = 0;
324 texImage->IntensityBits = 0;
325 texImage->LuminanceBits = 0;
326 texImage->IndexBits = 0;
327 break;
328 case GL_BLUE:
329 texImage->RedBits = 0;
330 texImage->GreenBits = 0;
331 texImage->BlueBits = 8;
332 texImage->AlphaBits = 0;
333 texImage->IntensityBits = 0;
334 texImage->LuminanceBits = 0;
335 texImage->IndexBits = 0;
336 break;
jtgafb833d1999-08-19 00:55:39 +0000337 case GL_RGB:
Brian Pauld53573d1999-10-19 20:36:20 +0000338 case GL_BGR:
jtgafb833d1999-08-19 00:55:39 +0000339 texImage->RedBits = 8;
340 texImage->GreenBits = 8;
341 texImage->BlueBits = 8;
342 texImage->AlphaBits = 0;
343 texImage->IntensityBits = 0;
344 texImage->LuminanceBits = 0;
345 texImage->IndexBits = 0;
346 break;
347 case GL_RGBA:
Brian Pauld53573d1999-10-19 20:36:20 +0000348 case GL_BGRA:
349 case GL_ABGR_EXT:
jtgafb833d1999-08-19 00:55:39 +0000350 texImage->RedBits = 8;
351 texImage->GreenBits = 8;
352 texImage->BlueBits = 8;
353 texImage->AlphaBits = 8;
354 texImage->IntensityBits = 0;
355 texImage->LuminanceBits = 0;
356 texImage->IndexBits = 0;
357 break;
358 case GL_COLOR_INDEX:
359 texImage->RedBits = 0;
360 texImage->GreenBits = 0;
361 texImage->BlueBits = 0;
362 texImage->AlphaBits = 0;
363 texImage->IntensityBits = 0;
364 texImage->LuminanceBits = 0;
365 texImage->IndexBits = 8;
366 break;
367 default:
368 gl_problem(NULL, "unexpected format in set_teximage_component_sizes");
369 }
370}
371
372
373/* Need this to prevent an out-of-bounds memory access when using
374 * X86 optimized code.
375 */
376#ifdef USE_X86_ASM
377# define EXTRA_BYTE 1
378#else
379# define EXTRA_BYTE 0
380#endif
381
382
Brian Paulc3f0a511999-11-03 17:27:05 +0000383
jtgafb833d1999-08-19 00:55:39 +0000384/*
Brian Paulc3f0a511999-11-03 17:27:05 +0000385 * This is called by glTexImage[123]D in order to build a gl_texture_image
386 * object given the client's parameters and image data.
387 *
388 * NOTES: Width, height and depth should include the border.
389 * All texture image parameters should have already been error checked.
jtgafb833d1999-08-19 00:55:39 +0000390 */
391static struct gl_texture_image *
Brian Paulc3f0a511999-11-03 17:27:05 +0000392make_texture_image( GLcontext *ctx, GLint internalFormat,
393 GLint width, GLint height, GLint depth, GLint border,
394 GLenum srcFormat, GLenum srcType, const GLvoid *pixels,
395 const struct gl_pixelstore_attrib *unpacking)
jtgafb833d1999-08-19 00:55:39 +0000396{
Brian Paulc3f0a511999-11-03 17:27:05 +0000397 GLint components, numPixels;
jtgafb833d1999-08-19 00:55:39 +0000398 struct gl_texture_image *texImage;
jtgafb833d1999-08-19 00:55:39 +0000399
Brian Paulc3f0a511999-11-03 17:27:05 +0000400 assert(width > 0);
401 assert(height > 0);
402 assert(depth > 0);
403 assert(border == 0 || border == 1);
404 assert(pixels);
405 assert(unpacking);
jtgafb833d1999-08-19 00:55:39 +0000406
jtgafb833d1999-08-19 00:55:39 +0000407
Brian Paulc3f0a511999-11-03 17:27:05 +0000408 /*
409 * Allocate and initialize the texture_image struct
410 */
jtgafb833d1999-08-19 00:55:39 +0000411 texImage = gl_alloc_texture_image();
412 if (!texImage)
413 return NULL;
414
415 texImage->Format = (GLenum) decode_internal_format(internalFormat);
416 set_teximage_component_sizes( texImage );
417 texImage->IntFormat = (GLenum) internalFormat;
418 texImage->Border = border;
Brian Paulc3f0a511999-11-03 17:27:05 +0000419 texImage->Width = width;
420 texImage->Height = height;
421 texImage->Depth = depth;
422 texImage->WidthLog2 = logbase2(width - 2 * border);
423 if (height == 1) /* 1-D texture */
jtgafb833d1999-08-19 00:55:39 +0000424 texImage->HeightLog2 = 0;
425 else
Brian Paulc3f0a511999-11-03 17:27:05 +0000426 texImage->HeightLog2 = logbase2(height - 2 * border);
427 if (depth == 1) /* 2-D texture */
jtgafb833d1999-08-19 00:55:39 +0000428 texImage->DepthLog2 = 0;
429 else
Brian Paulc3f0a511999-11-03 17:27:05 +0000430 texImage->DepthLog2 = logbase2(depth - 2 * border);
jtgafb833d1999-08-19 00:55:39 +0000431 texImage->Width2 = 1 << texImage->WidthLog2;
432 texImage->Height2 = 1 << texImage->HeightLog2;
433 texImage->Depth2 = 1 << texImage->DepthLog2;
Brian Paulc3f0a511999-11-03 17:27:05 +0000434 texImage->MaxLog2 = MAX2(texImage->WidthLog2, texImage->HeightLog2);
435
436 components = components_in_intformat(internalFormat);
437 numPixels = texImage->Width * texImage->Height * texImage->Depth;
438
439 texImage->Data = (GLubyte *) MALLOC(numPixels * components + EXTRA_BYTE);
jtgafb833d1999-08-19 00:55:39 +0000440
441 if (!texImage->Data) {
442 /* out of memory */
Brian Paulc3f0a511999-11-03 17:27:05 +0000443 gl_free_texture_image(texImage);
jtgafb833d1999-08-19 00:55:39 +0000444 return NULL;
445 }
446
Brian Paulc3f0a511999-11-03 17:27:05 +0000447
448 /*
449 * OK, the texture image struct has been initialized and the texture
450 * image memory has been allocated.
451 * Now fill in the texture image from the source data.
452 * This includes applying the pixel transfer operations.
453 */
454
455 /* try common 2D texture cases first */
456 if (!ctx->Pixel.ScaleOrBiasRGBA && !ctx->Pixel.MapColorFlag
457 && !ctx->Pixel.IndexOffset && !ctx->Pixel.IndexShift
458 && srcType == GL_UNSIGNED_BYTE && depth == 1) {
459
460 if (srcFormat == internalFormat) {
461 /* This will cover the common GL_RGB, GL_RGBA, GL_ALPHA,
462 * GL_LUMINANCE_ALPHA, etc. texture formats.
463 */
Brian Paul959f8022000-03-19 01:10:11 +0000464 const GLubyte *src = (const GLubyte *) gl_pixel_addr_in_image(unpacking,
Brian Paulc3f0a511999-11-03 17:27:05 +0000465 pixels, width, height, srcFormat, srcType, 0, 0, 0);
Brian Paul959f8022000-03-19 01:10:11 +0000466 const GLubyte *src1 = (const GLubyte *) gl_pixel_addr_in_image(unpacking,
Brian Paulc3f0a511999-11-03 17:27:05 +0000467 pixels, width, height, srcFormat, srcType, 0, 1, 0);
468 const GLint srcStride = src1 - src;
469 GLubyte *dst = texImage->Data;
470 GLint dstBytesPerRow = width * components * sizeof(GLubyte);
471 if (srcStride == dstBytesPerRow) {
472 MEMCPY(dst, src, height * dstBytesPerRow);
473 }
474 else {
475 GLint i;
476 for (i = 0; i < height; i++) {
477 MEMCPY(dst, src, dstBytesPerRow);
478 src += srcStride;
479 dst += dstBytesPerRow;
480 }
481 }
482 return texImage; /* all done */
483 }
484 else if (srcFormat == GL_RGBA && internalFormat == GL_RGB) {
485 /* commonly used by Quake */
Brian Paul959f8022000-03-19 01:10:11 +0000486 const GLubyte *src = (const GLubyte *) gl_pixel_addr_in_image(unpacking,
Brian Paulc3f0a511999-11-03 17:27:05 +0000487 pixels, width, height, srcFormat, srcType, 0, 0, 0);
Brian Paul959f8022000-03-19 01:10:11 +0000488 const GLubyte *src1 = (const GLubyte *) gl_pixel_addr_in_image(unpacking,
Brian Paulc3f0a511999-11-03 17:27:05 +0000489 pixels, width, height, srcFormat, srcType, 0, 1, 0);
490 const GLint srcStride = src1 - src;
491 GLubyte *dst = texImage->Data;
492 GLint i, j;
493 for (i = 0; i < height; i++) {
494 const GLubyte *s = src;
495 for (j = 0; j < width; j++) {
496 *dst++ = *s++; /*red*/
497 *dst++ = *s++; /*green*/
498 *dst++ = *s++; /*blue*/
499 s++; /*alpha*/
500 }
501 src += srcStride;
502 }
503 return texImage; /* all done */
504 }
505 }
506
507
508 /*
509 * General case solutions
510 */
511 if (texImage->Format == GL_COLOR_INDEX) {
512 /* color index texture */
513 const GLint destBytesPerRow = width * components * sizeof(GLubyte);
514 const GLenum dstType = GL_UNSIGNED_BYTE;
515 GLubyte *dest = texImage->Data;
516 GLint img, row;
517 for (img = 0; img < depth; img++) {
518 for (row = 0; row < height; row++) {
519 const GLvoid *source = gl_pixel_addr_in_image(unpacking,
520 pixels, width, height, srcFormat, srcType, img, row, 0);
521 _mesa_unpack_index_span(ctx, width, dstType, dest,
522 srcType, source, unpacking, GL_TRUE);
523 dest += destBytesPerRow;
524 }
525 }
jtgafb833d1999-08-19 00:55:39 +0000526 }
527 else {
Brian Paulc3f0a511999-11-03 17:27:05 +0000528 /* regular, color texture */
529 const GLint destBytesPerRow = width * components * sizeof(GLubyte);
530 const GLenum dstFormat = texImage->Format;
531 GLubyte *dest = texImage->Data;
532 GLint img, row;
533 for (img = 0; img < depth; img++) {
534 for (row = 0; row < height; row++) {
535 const GLvoid *source = gl_pixel_addr_in_image(unpacking,
536 pixels, width, height, srcFormat, srcType, img, row, 0);
537 _mesa_unpack_ubyte_color_span(ctx, width, dstFormat, dest,
538 srcFormat, srcType, source, unpacking, GL_TRUE);
539 dest += destBytesPerRow;
540 }
541 }
jtgafb833d1999-08-19 00:55:39 +0000542 }
543
Brian Paulc3f0a511999-11-03 17:27:05 +0000544 return texImage; /* All done! */
jtgafb833d1999-08-19 00:55:39 +0000545}
546
547
548
549/*
550 * glTexImage[123]D can accept a NULL image pointer. In this case we
551 * create a texture image with unspecified image contents per the OpenGL
552 * spec.
553 */
554static struct gl_texture_image *
555make_null_texture( GLcontext *ctx, GLenum internalFormat,
556 GLsizei width, GLsizei height, GLsizei depth, GLint border )
557{
558 GLint components;
559 struct gl_texture_image *texImage;
560 GLint numPixels;
561 (void) ctx;
562
563 /*internalFormat = decode_internal_format(internalFormat);*/
564 components = components_in_intformat(internalFormat);
565 numPixels = width * height * depth;
566
567 texImage = gl_alloc_texture_image();
568 if (!texImage)
569 return NULL;
570
571 texImage->Format = (GLenum) decode_internal_format(internalFormat);
572 set_teximage_component_sizes( texImage );
573 texImage->IntFormat = internalFormat;
574 texImage->Border = border;
575 texImage->Width = width;
576 texImage->Height = height;
577 texImage->Depth = depth;
578 texImage->WidthLog2 = logbase2(width - 2*border);
579 if (height==1) /* 1-D texture */
580 texImage->HeightLog2 = 0;
581 else
582 texImage->HeightLog2 = logbase2(height - 2*border);
583 if (depth==1) /* 2-D texture */
584 texImage->DepthLog2 = 0;
585 else
586 texImage->DepthLog2 = logbase2(depth - 2*border);
587 texImage->Width2 = 1 << texImage->WidthLog2;
588 texImage->Height2 = 1 << texImage->HeightLog2;
589 texImage->Depth2 = 1 << texImage->DepthLog2;
590 texImage->MaxLog2 = MAX2( texImage->WidthLog2, texImage->HeightLog2 );
591
592 /* XXX should we really allocate memory for the image or let it be NULL? */
593 /*texImage->Data = NULL;*/
594
Brian Paulbd5cdaf1999-10-13 18:42:49 +0000595 texImage->Data = (GLubyte *) MALLOC( numPixels * components + EXTRA_BYTE );
jtgafb833d1999-08-19 00:55:39 +0000596
597 /*
598 * Let's see if anyone finds this. If glTexImage2D() is called with
599 * a NULL image pointer then load the texture image with something
600 * interesting instead of leaving it indeterminate.
601 */
602 if (texImage->Data) {
Brian Paul65d54602000-03-01 23:28:20 +0000603 static const char message[8][32] = {
jtgafb833d1999-08-19 00:55:39 +0000604 " X X XXXXX XXX X ",
605 " XX XX X X X X X ",
606 " X X X X X X X ",
607 " X X XXXX XXX XXXXX ",
608 " X X X X X X ",
609 " X X X X X X X ",
610 " X X XXXXX XXX X X ",
611 " "
612 };
613
614 GLubyte *imgPtr = texImage->Data;
615 GLint i, j, k;
616 for (i=0;i<height;i++) {
617 GLint srcRow = 7 - i % 8;
618 for (j=0;j<width;j++) {
619 GLint srcCol = j % 32;
Brian Paul5b37c321999-11-05 06:43:10 +0000620 GLint texel = (message[srcRow][srcCol]=='X') ? 255 : 70;
jtgafb833d1999-08-19 00:55:39 +0000621 for (k=0;k<components;k++) {
Brian Paul5b37c321999-11-05 06:43:10 +0000622 *imgPtr++ = (GLubyte) texel;
jtgafb833d1999-08-19 00:55:39 +0000623 }
624 }
625 }
626 }
627
628 return texImage;
629}
630
631
632
633/*
Brian Paulc3f0a511999-11-03 17:27:05 +0000634 * Test glTexImage[123]D() parameters for errors.
jtgafb833d1999-08-19 00:55:39 +0000635 * Input:
636 * dimensions - must be 1 or 2 or 3
637 * Return: GL_TRUE = an error was detected, GL_FALSE = no errors
638 */
Brian Paulc3f0a511999-11-03 17:27:05 +0000639static GLboolean
640texture_error_check( GLcontext *ctx, GLenum target,
641 GLint level, GLint internalFormat,
642 GLenum format, GLenum type,
Brian Paul5b37c321999-11-05 06:43:10 +0000643 GLuint dimensions,
Brian Paulc3f0a511999-11-03 17:27:05 +0000644 GLint width, GLint height,
645 GLint depth, GLint border )
jtgafb833d1999-08-19 00:55:39 +0000646{
647 GLboolean isProxy;
648 GLint iformat;
649
650 if (dimensions == 1) {
Brian Paul5b37c321999-11-05 06:43:10 +0000651 isProxy = (GLboolean) (target == GL_PROXY_TEXTURE_1D);
jtgafb833d1999-08-19 00:55:39 +0000652 if (target != GL_TEXTURE_1D && !isProxy) {
653 gl_error( ctx, GL_INVALID_ENUM, "glTexImage1D(target)" );
654 return GL_TRUE;
655 }
656 }
657 else if (dimensions == 2) {
Brian Paul5b37c321999-11-05 06:43:10 +0000658 isProxy = (GLboolean) (target == GL_PROXY_TEXTURE_2D);
jtgafb833d1999-08-19 00:55:39 +0000659 if (target != GL_TEXTURE_2D && !isProxy) {
660 gl_error( ctx, GL_INVALID_ENUM, "glTexImage2D(target)" );
661 return GL_TRUE;
662 }
663 }
664 else if (dimensions == 3) {
Brian Paul5b37c321999-11-05 06:43:10 +0000665 isProxy = (GLboolean) (target == GL_PROXY_TEXTURE_3D);
jtgafb833d1999-08-19 00:55:39 +0000666 if (target != GL_TEXTURE_3D && !isProxy) {
667 gl_error( ctx, GL_INVALID_ENUM, "glTexImage3D(target)" );
668 return GL_TRUE;
669 }
670 }
671 else {
672 gl_problem( ctx, "bad dims in texture_error_check" );
673 return GL_TRUE;
674 }
675
676 /* Border */
677 if (border!=0 && border!=1) {
678 if (!isProxy) {
Brian Paulc3f0a511999-11-03 17:27:05 +0000679 char message[100];
680 sprintf(message, "glTexImage%dD(border)", dimensions);
681 gl_error(ctx, GL_INVALID_VALUE, message);
jtgafb833d1999-08-19 00:55:39 +0000682 }
683 return GL_TRUE;
684 }
685
686 /* Width */
687 if (width < 2 * border || width > 2 + ctx->Const.MaxTextureSize
688 || logbase2( width - 2 * border ) < 0) {
689 if (!isProxy) {
Brian Paulc3f0a511999-11-03 17:27:05 +0000690 char message[100];
691 sprintf(message, "glTexImage%dD(width)", dimensions);
692 gl_error(ctx, GL_INVALID_VALUE, message);
jtgafb833d1999-08-19 00:55:39 +0000693 }
694 return GL_TRUE;
695 }
696
697 /* Height */
698 if (dimensions >= 2) {
699 if (height < 2 * border || height > 2 + ctx->Const.MaxTextureSize
700 || logbase2( height - 2 * border ) < 0) {
701 if (!isProxy) {
Brian Paulc3f0a511999-11-03 17:27:05 +0000702 char message[100];
703 sprintf(message, "glTexImage%dD(height)", dimensions);
704 gl_error(ctx, GL_INVALID_VALUE, message);
jtgafb833d1999-08-19 00:55:39 +0000705 }
Brian Paulc3f0a511999-11-03 17:27:05 +0000706 return GL_TRUE;
jtgafb833d1999-08-19 00:55:39 +0000707 }
708 }
709
710 /* Depth */
711 if (dimensions >= 3) {
712 if (depth < 2 * border || depth > 2 + ctx->Const.MaxTextureSize
713 || logbase2( depth - 2 * border ) < 0) {
714 if (!isProxy) {
715 gl_error( ctx, GL_INVALID_VALUE, "glTexImage3D(depth)" );
716 }
717 return GL_TRUE;
718 }
719 }
720
721 /* Level */
722 if (level<0 || level>=ctx->Const.MaxTextureLevels) {
Brian Paulc3f0a511999-11-03 17:27:05 +0000723 if (!isProxy) {
724 char message[100];
725 sprintf(message, "glTexImage%dD(level)", dimensions);
726 gl_error(ctx, GL_INVALID_VALUE, message);
727 }
jtgafb833d1999-08-19 00:55:39 +0000728 return GL_TRUE;
729 }
730
731 iformat = decode_internal_format( internalFormat );
732 if (iformat < 0) {
Brian Paulc3f0a511999-11-03 17:27:05 +0000733 if (!isProxy) {
734 char message[100];
735 sprintf(message, "glTexImage%dD(internalFormat)", dimensions);
736 gl_error(ctx, GL_INVALID_VALUE, message);
737 }
jtgafb833d1999-08-19 00:55:39 +0000738 return GL_TRUE;
739 }
740
741 if (!gl_is_legal_format_and_type( format, type )) {
Brian Pauld53573d1999-10-19 20:36:20 +0000742 /* Yes, generate GL_INVALID_OPERATION, not GL_INVALID_ENUM, if there
743 * is a type/format mismatch. See 1.2 spec page 94, sec 3.6.4.
744 */
Brian Paulc3f0a511999-11-03 17:27:05 +0000745 if (!isProxy) {
746 char message[100];
747 sprintf(message, "glTexImage%dD(format or type)", dimensions);
748 gl_error(ctx, GL_INVALID_OPERATION, message);
749 }
jtgafb833d1999-08-19 00:55:39 +0000750 return GL_TRUE;
751 }
752
753 /* if we get here, the parameters are OK */
754 return GL_FALSE;
755}
756
757
758
759/*
Brian Paulc3f0a511999-11-03 17:27:05 +0000760 * Test glTexSubImage[123]D() parameters for errors.
761 * Input:
762 * dimensions - must be 1 or 2 or 3
763 * Return: GL_TRUE = an error was detected, GL_FALSE = no errors
764 */
765static GLboolean
Brian Paulfbd8f211999-11-11 01:22:25 +0000766subtexture_error_check( GLcontext *ctx, GLuint dimensions,
Brian Paulc3f0a511999-11-03 17:27:05 +0000767 GLenum target, GLint level,
768 GLint xoffset, GLint yoffset, GLint zoffset,
769 GLint width, GLint height, GLint depth,
770 GLenum format, GLenum type )
771{
772 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
773 struct gl_texture_image *destTex;
774
775 if (dimensions == 1) {
776 if (target != GL_TEXTURE_1D) {
777 gl_error( ctx, GL_INVALID_ENUM, "glTexSubImage1D(target)" );
778 return GL_TRUE;
779 }
780 }
781 else if (dimensions == 2) {
782 if (target != GL_TEXTURE_2D) {
783 gl_error( ctx, GL_INVALID_ENUM, "glTexSubImage2D(target)" );
784 return GL_TRUE;
785 }
786 }
787 else if (dimensions == 3) {
788 if (target != GL_TEXTURE_3D) {
789 gl_error( ctx, GL_INVALID_ENUM, "glTexSubImage3D(target)" );
790 return GL_TRUE;
791 }
792 }
793 else {
794 gl_problem( ctx, "bad dims in texture_error_check" );
795 return GL_TRUE;
796 }
797
798 if (level < 0 || level >= ctx->Const.MaxTextureLevels) {
799 gl_error(ctx, GL_INVALID_ENUM, "glTexSubImage2D(level)");
800 return GL_TRUE;
801 }
802
803 if (width < 0) {
804 char message[100];
805 sprintf(message, "glTexSubImage%dD(width)", dimensions);
806 gl_error(ctx, GL_INVALID_VALUE, message);
807 return GL_TRUE;
808 }
809 if (height < 0 && dimensions > 1) {
810 char message[100];
811 sprintf(message, "glTexSubImage%dD(height)", dimensions);
812 gl_error(ctx, GL_INVALID_VALUE, message);
813 return GL_TRUE;
814 }
815 if (depth < 0 && dimensions > 2) {
816 char message[100];
817 sprintf(message, "glTexSubImage%dD(depth)", dimensions);
818 gl_error(ctx, GL_INVALID_VALUE, message);
819 return GL_TRUE;
820 }
821
822 destTex = texUnit->CurrentD[2]->Image[level];
823 if (!destTex) {
824 gl_error(ctx, GL_INVALID_OPERATION, "glTexSubImage2D");
825 return GL_TRUE;
826 }
827
828 if (xoffset < -((GLint)destTex->Border)) {
829 gl_error(ctx, GL_INVALID_VALUE, "glTexSubImage1/2/3D(xoffset)");
830 return GL_TRUE;
831 }
832 if (xoffset + width > (GLint) (destTex->Width + destTex->Border)) {
833 gl_error(ctx, GL_INVALID_VALUE, "glTexSubImage1/2/3D(xoffset+width)");
834 return GL_TRUE;
835 }
836 if (dimensions > 1) {
837 if (yoffset < -((GLint)destTex->Border)) {
838 gl_error(ctx, GL_INVALID_VALUE, "glTexSubImage2/3D(yoffset)");
839 return GL_TRUE;
840 }
841 if (yoffset + height > (GLint) (destTex->Height + destTex->Border)) {
842 gl_error(ctx, GL_INVALID_VALUE, "glTexSubImage2/3D(yoffset+height)");
843 return GL_TRUE;
844 }
845 }
846 if (dimensions > 2) {
847 if (zoffset < -((GLint)destTex->Border)) {
848 gl_error(ctx, GL_INVALID_VALUE, "glTexSubImage3D(zoffset)");
849 return GL_TRUE;
850 }
851 if (zoffset + depth > (GLint) (destTex->Depth+destTex->Border)) {
852 gl_error(ctx, GL_INVALID_VALUE, "glTexSubImage3D(zoffset+depth)");
853 return GL_TRUE;
854 }
855 }
856
857 if (!gl_is_legal_format_and_type(format, type)) {
858 char message[100];
859 sprintf(message, "glTexSubImage%dD(format or type)", dimensions);
860 gl_error(ctx, GL_INVALID_ENUM, message);
861 return GL_TRUE;
862 }
863
864 return GL_FALSE;
865}
866
867
868/*
869 * Test glCopyTexImage[12]D() parameters for errors.
870 * Input: dimensions - must be 1 or 2 or 3
871 * Return: GL_TRUE = an error was detected, GL_FALSE = no errors
872 */
873static GLboolean
Brian Paulfbd8f211999-11-11 01:22:25 +0000874copytexture_error_check( GLcontext *ctx, GLuint dimensions,
Brian Paulc3f0a511999-11-03 17:27:05 +0000875 GLenum target, GLint level, GLint internalFormat,
876 GLint width, GLint height, GLint border )
877{
878 GLint iformat;
879
880 if (target != GL_TEXTURE_1D && target != GL_TEXTURE_2D) {
881 gl_error( ctx, GL_INVALID_ENUM, "glCopyTexImage1/2D(target)" );
882 return GL_TRUE;
883 }
884
885 if (dimensions == 1 && target != GL_TEXTURE_1D) {
886 gl_error( ctx, GL_INVALID_ENUM, "glCopyTexImage1D(target)" );
887 return GL_TRUE;
888 }
889 else if (dimensions == 2 && target != GL_TEXTURE_2D) {
890 gl_error( ctx, GL_INVALID_ENUM, "glCopyTexImage2D(target)" );
891 return GL_TRUE;
892 }
893
894 /* Border */
895 if (border!=0 && border!=1) {
896 char message[100];
897 sprintf(message, "glCopyTexImage%dD(border)", dimensions);
898 gl_error(ctx, GL_INVALID_VALUE, message);
899 return GL_TRUE;
900 }
901
902 /* Width */
903 if (width < 2 * border || width > 2 + ctx->Const.MaxTextureSize
904 || logbase2( width - 2 * border ) < 0) {
905 char message[100];
906 sprintf(message, "glCopyTexImage%dD(width)", dimensions);
907 gl_error(ctx, GL_INVALID_VALUE, message);
908 return GL_TRUE;
909 }
910
911 /* Height */
912 if (dimensions >= 2) {
913 if (height < 2 * border || height > 2 + ctx->Const.MaxTextureSize
914 || logbase2( height - 2 * border ) < 0) {
915 char message[100];
916 sprintf(message, "glCopyTexImage%dD(height)", dimensions);
917 gl_error(ctx, GL_INVALID_VALUE, message);
918 return GL_TRUE;
919 }
920 }
921
922 /* Level */
923 if (level<0 || level>=ctx->Const.MaxTextureLevels) {
924 char message[100];
925 sprintf(message, "glCopyTexImage%dD(level)", dimensions);
926 gl_error(ctx, GL_INVALID_VALUE, message);
927 return GL_TRUE;
928 }
929
930 iformat = decode_internal_format( internalFormat );
931 if (iformat < 0) {
932 char message[100];
933 sprintf(message, "glCopyTexImage%dD(internalFormat)", dimensions);
934 gl_error(ctx, GL_INVALID_VALUE, message);
935 return GL_TRUE;
936 }
937
938 /* if we get here, the parameters are OK */
939 return GL_FALSE;
940}
941
942
943static GLboolean
Brian Paulfbd8f211999-11-11 01:22:25 +0000944copytexsubimage_error_check( GLcontext *ctx, GLuint dimensions,
Brian Paulc3f0a511999-11-03 17:27:05 +0000945 GLenum target, GLint level,
946 GLint xoffset, GLint yoffset, GLint zoffset,
Brian Paul5b37c321999-11-05 06:43:10 +0000947 GLsizei width, GLsizei height )
Brian Paulc3f0a511999-11-03 17:27:05 +0000948{
949 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
950 struct gl_texture_image *teximage;
951
952 if (dimensions == 1 && target != GL_TEXTURE_1D) {
953 gl_error( ctx, GL_INVALID_ENUM, "glCopyTexSubImage1D(target)" );
954 return GL_TRUE;
955 }
956 else if (dimensions == 2 && target != GL_TEXTURE_2D) {
957 gl_error( ctx, GL_INVALID_ENUM, "glCopyTexSubImage2D(target)" );
958 return GL_TRUE;
959 }
960 else if (dimensions == 3 && target != GL_TEXTURE_3D) {
961 gl_error( ctx, GL_INVALID_ENUM, "glCopyTexSubImage3D(target)" );
962 return GL_TRUE;
963 }
964
965 if (level < 0 || level >= ctx->Const.MaxTextureLevels) {
966 char message[100];
967 sprintf(message, "glCopyTexSubImage%dD(level)", dimensions);
968 gl_error(ctx, GL_INVALID_VALUE, message);
969 return GL_TRUE;
970 }
971
972 if (width < 0) {
973 char message[100];
974 sprintf(message, "glCopyTexSubImage%dD(width)", dimensions );
975 gl_error(ctx, GL_INVALID_VALUE, message);
976 return GL_TRUE;
977 }
978 if (dimensions > 1 && height < 0) {
979 char message[100];
980 sprintf(message, "glCopyTexSubImage%dD(height)", dimensions );
981 gl_error(ctx, GL_INVALID_VALUE, message);
982 return GL_TRUE;
983 }
984
Brian Pauldf6a28d2000-02-21 16:34:21 +0000985 teximage = texUnit->CurrentD[dimensions]->Image[level];
Brian Paulc3f0a511999-11-03 17:27:05 +0000986 if (!teximage) {
987 char message[100];
988 sprintf(message, "glCopyTexSubImage%dD(undefined texture)", dimensions);
989 gl_error(ctx, GL_INVALID_OPERATION, message);
990 return GL_TRUE;
991 }
992
993 if (xoffset < -((GLint)teximage->Border)) {
994 char message[100];
995 sprintf(message, "glCopyTexSubImage%dD(xoffset)", dimensions);
996 gl_error(ctx, GL_INVALID_VALUE, message);
997 return GL_TRUE;
998 }
999 if (xoffset+width > (GLint) (teximage->Width+teximage->Border)) {
1000 char message[100];
1001 sprintf(message, "glCopyTexSubImage%dD(xoffset+width)", dimensions);
1002 gl_error(ctx, GL_INVALID_VALUE, message);
1003 return GL_TRUE;
1004 }
1005 if (dimensions > 1) {
1006 if (yoffset < -((GLint)teximage->Border)) {
1007 char message[100];
1008 sprintf(message, "glCopyTexSubImage%dD(yoffset)", dimensions);
1009 gl_error(ctx, GL_INVALID_VALUE, message);
1010 return GL_TRUE;
1011 }
1012 /* NOTE: we're adding the border here, not subtracting! */
1013 if (yoffset+height > (GLint) (teximage->Height+teximage->Border)) {
1014 char message[100];
1015 sprintf(message, "glCopyTexSubImage%dD(yoffset+height)", dimensions);
1016 gl_error(ctx, GL_INVALID_VALUE, message);
1017 return GL_TRUE;
1018 }
1019 }
1020
1021 if (dimensions > 2) {
1022 if (zoffset < -((GLint)teximage->Border)) {
1023 char message[100];
1024 sprintf(message, "glCopyTexSubImage%dD(zoffset)", dimensions);
1025 gl_error(ctx, GL_INVALID_VALUE, message);
1026 return GL_TRUE;
1027 }
1028 if (zoffset > (GLint) (teximage->Depth+teximage->Border)) {
1029 char message[100];
1030 sprintf(message, "glCopyTexSubImage%dD(zoffset+depth)", dimensions);
1031 gl_error(ctx, GL_INVALID_VALUE, message);
1032 return GL_TRUE;
1033 }
1034 }
1035
1036 /* if we get here, the parameters are OK */
1037 return GL_FALSE;
1038}
1039
1040
1041
1042
1043/*
jtgafb833d1999-08-19 00:55:39 +00001044 * Called from the API. Note that width includes the border.
1045 */
Brian Paulfbd8f211999-11-11 01:22:25 +00001046void
1047_mesa_TexImage1D( GLenum target, GLint level, GLint internalformat,
1048 GLsizei width, GLint border, GLenum format,
1049 GLenum type, const GLvoid *pixels )
jtgafb833d1999-08-19 00:55:39 +00001050{
Brian Paulfbd8f211999-11-11 01:22:25 +00001051 GET_CURRENT_CONTEXT(ctx);
jtgafb833d1999-08-19 00:55:39 +00001052 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glTexImage1D");
1053
1054 if (target==GL_TEXTURE_1D) {
Brian Paulf7b57072000-03-20 14:37:52 +00001055 struct gl_texture_unit *texUnit;
jtgafb833d1999-08-19 00:55:39 +00001056 struct gl_texture_image *teximage;
Brian Paulf7b57072000-03-20 14:37:52 +00001057
jtgafb833d1999-08-19 00:55:39 +00001058 if (texture_error_check( ctx, target, level, internalformat,
1059 format, type, 1, width, 1, 1, border )) {
Brian Paulf7b57072000-03-20 14:37:52 +00001060 return; /* error in texture image was detected */
jtgafb833d1999-08-19 00:55:39 +00001061 }
1062
Brian Paulf7b57072000-03-20 14:37:52 +00001063 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
1064
jtgafb833d1999-08-19 00:55:39 +00001065 /* free current texture image, if any */
1066 if (texUnit->CurrentD[1]->Image[level]) {
1067 gl_free_texture_image( texUnit->CurrentD[1]->Image[level] );
1068 }
1069
1070 /* make new texture from source image */
Brian Paulc3f0a511999-11-03 17:27:05 +00001071 if (pixels) {
1072 teximage = make_texture_image(ctx, internalformat, width, 1, 1,
1073 border, format, type, pixels, &ctx->Unpack);
jtgafb833d1999-08-19 00:55:39 +00001074 }
1075 else {
1076 teximage = make_null_texture(ctx, (GLenum) internalformat,
1077 width, 1, 1, border);
1078 }
1079
1080 /* install new texture image */
jtgafb833d1999-08-19 00:55:39 +00001081 texUnit->CurrentD[1]->Image[level] = teximage;
1082 gl_put_texobj_on_dirty_list( ctx, texUnit->CurrentD[1] );
1083 ctx->NewState |= NEW_TEXTURING;
1084
jtgafb833d1999-08-19 00:55:39 +00001085 /* tell driver about change */
1086 if (ctx->Driver.TexImage) {
1087 (*ctx->Driver.TexImage)( ctx, GL_TEXTURE_1D,
1088 texUnit->CurrentD[1],
1089 level, internalformat, teximage );
1090 }
1091 }
1092 else if (target==GL_PROXY_TEXTURE_1D) {
1093 /* Proxy texture: check for errors and update proxy state */
1094 if (texture_error_check( ctx, target, level, internalformat,
1095 format, type, 1, width, 1, 1, border )) {
1096 if (level>=0 && level<ctx->Const.MaxTextureLevels) {
1097 MEMSET( ctx->Texture.Proxy1D->Image[level], 0,
1098 sizeof(struct gl_texture_image) );
1099 }
1100 }
1101 else {
1102 ctx->Texture.Proxy1D->Image[level]->Format = (GLenum) format;
1103 set_teximage_component_sizes( ctx->Texture.Proxy1D->Image[level] );
1104 ctx->Texture.Proxy1D->Image[level]->IntFormat = (GLenum) internalformat;
1105 ctx->Texture.Proxy1D->Image[level]->Border = border;
1106 ctx->Texture.Proxy1D->Image[level]->Width = width;
1107 ctx->Texture.Proxy1D->Image[level]->Height = 1;
1108 ctx->Texture.Proxy1D->Image[level]->Depth = 1;
1109 }
jtgafb833d1999-08-19 00:55:39 +00001110 }
1111 else {
1112 gl_error( ctx, GL_INVALID_ENUM, "glTexImage1D(target)" );
1113 return;
1114 }
1115}
1116
1117
Brian Paulfbd8f211999-11-11 01:22:25 +00001118void
1119_mesa_TexImage2D( GLenum target, GLint level, GLint internalformat,
1120 GLsizei width, GLsizei height, GLint border,
1121 GLenum format, GLenum type,
1122 const GLvoid *pixels )
jtgafb833d1999-08-19 00:55:39 +00001123{
Brian Paulfbd8f211999-11-11 01:22:25 +00001124 GET_CURRENT_CONTEXT(ctx);
jtgafb833d1999-08-19 00:55:39 +00001125 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glTexImage2D");
1126
1127 if (target==GL_TEXTURE_2D) {
Brian Paulf7b57072000-03-20 14:37:52 +00001128 struct gl_texture_unit *texUnit;
jtgafb833d1999-08-19 00:55:39 +00001129 struct gl_texture_image *teximage;
Brian Paulf7b57072000-03-20 14:37:52 +00001130
jtgafb833d1999-08-19 00:55:39 +00001131 if (texture_error_check( ctx, target, level, internalformat,
1132 format, type, 2, width, height, 1, border )) {
Brian Paulf7b57072000-03-20 14:37:52 +00001133 return; /* error in texture image was detected */
jtgafb833d1999-08-19 00:55:39 +00001134 }
1135
Brian Paulf7b57072000-03-20 14:37:52 +00001136 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
1137
jtgafb833d1999-08-19 00:55:39 +00001138 /* free current texture image, if any */
1139 if (texUnit->CurrentD[2]->Image[level]) {
1140 gl_free_texture_image( texUnit->CurrentD[2]->Image[level] );
1141 }
1142
1143 /* make new texture from source image */
Brian Paulc3f0a511999-11-03 17:27:05 +00001144 if (pixels) {
1145 teximage = make_texture_image(ctx, internalformat, width, height, 1,
1146 border, format, type, pixels, &ctx->Unpack);
jtgafb833d1999-08-19 00:55:39 +00001147 }
1148 else {
1149 teximage = make_null_texture(ctx, (GLenum) internalformat,
1150 width, height, 1, border);
1151 }
1152
1153 /* install new texture image */
1154 texUnit->CurrentD[2]->Image[level] = teximage;
1155 gl_put_texobj_on_dirty_list( ctx, texUnit->CurrentD[2] );
1156 ctx->NewState |= NEW_TEXTURING;
1157
jtgafb833d1999-08-19 00:55:39 +00001158 /* tell driver about change */
1159 if (ctx->Driver.TexImage) {
1160 (*ctx->Driver.TexImage)( ctx, GL_TEXTURE_2D,
1161 texUnit->CurrentD[2],
1162 level, internalformat, teximage );
1163 }
1164 }
1165 else if (target==GL_PROXY_TEXTURE_2D) {
1166 /* Proxy texture: check for errors and update proxy state */
1167 if (texture_error_check( ctx, target, level, internalformat,
1168 format, type, 2, width, height, 1, border )) {
1169 if (level>=0 && level<ctx->Const.MaxTextureLevels) {
1170 MEMSET( ctx->Texture.Proxy2D->Image[level], 0,
1171 sizeof(struct gl_texture_image) );
1172 }
1173 }
1174 else {
1175 ctx->Texture.Proxy2D->Image[level]->Format = (GLenum) format;
1176 set_teximage_component_sizes( ctx->Texture.Proxy2D->Image[level] );
1177 ctx->Texture.Proxy2D->Image[level]->IntFormat = (GLenum) internalformat;
1178 ctx->Texture.Proxy2D->Image[level]->Border = border;
1179 ctx->Texture.Proxy2D->Image[level]->Width = width;
1180 ctx->Texture.Proxy2D->Image[level]->Height = height;
1181 ctx->Texture.Proxy2D->Image[level]->Depth = 1;
1182 }
jtgafb833d1999-08-19 00:55:39 +00001183 }
1184 else {
1185 gl_error( ctx, GL_INVALID_ENUM, "glTexImage2D(target)" );
1186 return;
1187 }
1188}
1189
1190
1191
1192/*
1193 * Called by the API or display list executor.
1194 * Note that width and height include the border.
1195 */
Brian Paulfbd8f211999-11-11 01:22:25 +00001196void
1197_mesa_TexImage3D( GLenum target, GLint level, GLint internalformat,
1198 GLsizei width, GLsizei height, GLsizei depth,
1199 GLint border, GLenum format, GLenum type,
1200 const GLvoid *pixels )
jtgafb833d1999-08-19 00:55:39 +00001201{
Brian Paulfbd8f211999-11-11 01:22:25 +00001202 GET_CURRENT_CONTEXT(ctx);
Brian Paulf7b57072000-03-20 14:37:52 +00001203 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glTexImage3D");
jtgafb833d1999-08-19 00:55:39 +00001204
Brian Paulfbd8f211999-11-11 01:22:25 +00001205 if (target==GL_TEXTURE_3D_EXT) {
Brian Paulf7b57072000-03-20 14:37:52 +00001206 struct gl_texture_unit *texUnit;
jtgafb833d1999-08-19 00:55:39 +00001207 struct gl_texture_image *teximage;
1208 if (texture_error_check( ctx, target, level, internalformat,
1209 format, type, 3, width, height, depth,
1210 border )) {
Brian Paulf7b57072000-03-20 14:37:52 +00001211 return; /* error in texture image was detected */
jtgafb833d1999-08-19 00:55:39 +00001212 }
1213
Brian Paulf7b57072000-03-20 14:37:52 +00001214 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
1215
jtgafb833d1999-08-19 00:55:39 +00001216 /* free current texture image, if any */
1217 if (texUnit->CurrentD[3]->Image[level]) {
1218 gl_free_texture_image( texUnit->CurrentD[3]->Image[level] );
1219 }
1220
1221 /* make new texture from source image */
Brian Paulc3f0a511999-11-03 17:27:05 +00001222 if (pixels) {
1223 teximage = make_texture_image(ctx, internalformat, width, height,
1224 depth, border, format, type, pixels, &ctx->Unpack);
jtgafb833d1999-08-19 00:55:39 +00001225 }
1226 else {
1227 teximage = make_null_texture(ctx, (GLenum) internalformat,
1228 width, height, depth, border);
1229 }
1230
1231 /* install new texture image */
1232 texUnit->CurrentD[3]->Image[level] = teximage;
1233 gl_put_texobj_on_dirty_list( ctx, texUnit->CurrentD[3] );
1234 ctx->NewState |= NEW_TEXTURING;
1235
jtgafb833d1999-08-19 00:55:39 +00001236 /* tell driver about change */
1237 if (ctx->Driver.TexImage) {
1238 (*ctx->Driver.TexImage)( ctx, GL_TEXTURE_3D_EXT,
1239 texUnit->CurrentD[3],
1240 level, internalformat, teximage );
1241 }
1242 }
1243 else if (target==GL_PROXY_TEXTURE_3D_EXT) {
1244 /* Proxy texture: check for errors and update proxy state */
1245 if (texture_error_check( ctx, target, level, internalformat,
1246 format, type, 3, width, height, depth,
1247 border )) {
1248 if (level>=0 && level<ctx->Const.MaxTextureLevels) {
1249 MEMSET( ctx->Texture.Proxy3D->Image[level], 0,
1250 sizeof(struct gl_texture_image) );
1251 }
1252 }
1253 else {
1254 ctx->Texture.Proxy3D->Image[level]->Format = (GLenum) format;
1255 set_teximage_component_sizes( ctx->Texture.Proxy3D->Image[level] );
1256 ctx->Texture.Proxy3D->Image[level]->IntFormat = (GLenum) internalformat;
1257 ctx->Texture.Proxy3D->Image[level]->Border = border;
1258 ctx->Texture.Proxy3D->Image[level]->Width = width;
1259 ctx->Texture.Proxy3D->Image[level]->Height = height;
1260 ctx->Texture.Proxy3D->Image[level]->Depth = depth;
1261 }
jtgafb833d1999-08-19 00:55:39 +00001262 }
1263 else {
Brian Paulc3f0a511999-11-03 17:27:05 +00001264 gl_error( ctx, GL_INVALID_ENUM, "glTexImage3D(target)" );
jtgafb833d1999-08-19 00:55:39 +00001265 return;
1266 }
1267}
1268
1269
Brian Paul663049a2000-01-31 23:10:16 +00001270void
1271_mesa_TexImage3DEXT( GLenum target, GLint level, GLenum internalformat,
1272 GLsizei width, GLsizei height, GLsizei depth,
1273 GLint border, GLenum format, GLenum type,
1274 const GLvoid *pixels )
1275{
1276 _mesa_TexImage3D(target, level, (GLint) internalformat, width, height,
1277 depth, border, format, type, pixels);
1278}
1279
1280
Brian Paulf7b57072000-03-20 14:37:52 +00001281/*
1282 * Fetch a texture image from the device driver.
1283 * Store the results in the given texture object at the given mipmap level.
1284 */
1285static void
1286get_teximage_from_driver( GLcontext *ctx, GLenum target, GLint level,
1287 const struct gl_texture_object *texObj )
1288{
1289 GLvoid *image;
1290 GLenum imgFormat, imgType;
1291 GLboolean freeImage;
1292 struct gl_texture_image *texImage;
1293 GLint destComponents, numPixels, srcBytesPerTexel;
1294
1295 if (!ctx->Driver.GetTexImage)
1296 return;
1297
1298 image = (*ctx->Driver.GetTexImage)( ctx, target, level,
1299 &imgFormat, &imgType, &freeImage);
1300 if (!image)
1301 return;
1302
1303 texImage = texObj->Image[level];
1304 ASSERT(texImage);
1305 if (!texImage)
1306 return;
1307
1308 destComponents = components_in_intformat(texImage->Format);
1309 assert(destComponents > 0);
1310 numPixels = texImage->Width * texImage->Height * texImage->Depth;
1311 assert(numPixels > 0);
1312 srcBytesPerTexel = gl_bytes_per_pixel(imgFormat, imgType);
1313 assert(srcBytesPerTexel > 0);
1314
1315 if (!texImage->Data) {
1316 /* Allocate memory for the texture image data */
1317 texImage->Data = (GLubyte *) MALLOC(numPixels * destComponents + EXTRA_BYTE);
1318 }
1319
1320 if (imgFormat == texImage->Format && imgType == GL_UNSIGNED_BYTE) {
1321 /* We got lucky! The driver's format and type match Mesa's format. */
1322 if (texImage->Data) {
1323 MEMCPY(texImage->Data, image, numPixels * destComponents);
1324 }
1325 }
1326 else {
1327 /* Convert the texture image from the driver's format to Mesa's
1328 * internal format.
1329 */
1330 const GLint width = texImage->Width;
1331 const GLint height = texImage->Height;
1332 const GLint depth = texImage->Depth;
1333 const GLint destBytesPerRow = width * destComponents * sizeof(GLchan);
1334 const GLint srcBytesPerRow = width * srcBytesPerTexel;
1335 const GLenum dstType = GL_UNSIGNED_BYTE;
1336 const GLenum dstFormat = texImage->Format;
1337 const GLubyte *srcPtr = (const GLubyte *) image;
1338 GLubyte *destPtr = texImage->Data;
1339
1340 if (texImage->Format == GL_COLOR_INDEX) {
1341 /* color index texture */
1342 GLint img, row;
1343 assert(imgFormat == GL_COLOR_INDEX);
1344 for (img = 0; img < depth; img++) {
1345 for (row = 0; row < height; row++) {
1346 _mesa_unpack_index_span(ctx, width, dstType, destPtr,
1347 imgType, srcPtr, &DefaultPacking, GL_FALSE);
1348 destPtr += destBytesPerRow;
1349 srcPtr += srcBytesPerRow;
1350 }
1351 }
1352 }
1353 else {
1354 /* color texture */
1355 GLint img, row;
1356 for (img = 0; img < depth; img++) {
1357 for (row = 0; row < height; row++) {
1358 _mesa_unpack_ubyte_color_span(ctx, width, dstFormat, destPtr,
1359 imgFormat, imgType, srcPtr, &DefaultPacking, GL_FALSE);
1360 destPtr += destBytesPerRow;
1361 srcPtr += srcBytesPerRow;
1362 }
1363 }
1364 }
1365 }
1366
1367 if (freeImage)
1368 FREE(image);
1369}
1370
jtgafb833d1999-08-19 00:55:39 +00001371
Brian Paulfbd8f211999-11-11 01:22:25 +00001372void
1373_mesa_GetTexImage( GLenum target, GLint level, GLenum format,
1374 GLenum type, GLvoid *pixels )
jtgafb833d1999-08-19 00:55:39 +00001375{
Brian Paulfbd8f211999-11-11 01:22:25 +00001376 GET_CURRENT_CONTEXT(ctx);
jtgafb833d1999-08-19 00:55:39 +00001377 const struct gl_texture_object *texObj;
Brian Paulf7b57072000-03-20 14:37:52 +00001378 struct gl_texture_image *texImage;
1379 GLboolean discardImage;
jtgafb833d1999-08-19 00:55:39 +00001380
1381 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGetTexImage");
1382
1383 if (level < 0 || level >= ctx->Const.MaxTextureLevels) {
1384 gl_error( ctx, GL_INVALID_VALUE, "glGetTexImage(level)" );
1385 return;
1386 }
1387
1388 if (gl_sizeof_type(type) <= 0) {
1389 gl_error( ctx, GL_INVALID_ENUM, "glGetTexImage(type)" );
1390 return;
1391 }
1392
1393 if (gl_components_in_format(format) <= 0) {
1394 gl_error( ctx, GL_INVALID_ENUM, "glGetTexImage(format)" );
1395 return;
1396 }
1397
1398 if (!pixels)
Brian Paulf7b57072000-03-20 14:37:52 +00001399 return;
jtgafb833d1999-08-19 00:55:39 +00001400
1401 switch (target) {
1402 case GL_TEXTURE_1D:
1403 texObj = ctx->Texture.Unit[ctx->Texture.CurrentUnit].CurrentD[1];
1404 break;
1405 case GL_TEXTURE_2D:
1406 texObj = ctx->Texture.Unit[ctx->Texture.CurrentUnit].CurrentD[2];
1407 break;
1408 case GL_TEXTURE_3D:
1409 texObj = ctx->Texture.Unit[ctx->Texture.CurrentUnit].CurrentD[3];
1410 break;
1411 default:
1412 gl_error( ctx, GL_INVALID_ENUM, "glGetTexImage(target)" );
1413 return;
1414 }
1415
Brian Paulf7b57072000-03-20 14:37:52 +00001416 texImage = texObj->Image[level];
1417 if (!texImage) {
1418 /* invalid mipmap level */
1419 return;
1420 }
1421
1422 if (!texImage->Data) {
1423 /* try to get the texture image from the device driver */
1424 get_teximage_from_driver(ctx, target, level, texObj);
1425 discardImage = GL_TRUE;
1426 }
1427 else {
1428 discardImage = GL_FALSE;
1429 }
1430
1431 if (texImage->Data) {
jtgafb833d1999-08-19 00:55:39 +00001432 GLint width = texImage->Width;
1433 GLint height = texImage->Height;
1434 GLint row;
1435
1436 for (row = 0; row < height; row++) {
1437 /* compute destination address in client memory */
1438 GLvoid *dest = gl_pixel_addr_in_image( &ctx->Unpack, pixels,
1439 width, height,
1440 format, type, 0, row, 0);
1441
1442 assert(dest);
1443 if (texImage->Format == GL_RGBA) {
1444 const GLubyte *src = texImage->Data + row * width * 4 * sizeof(GLubyte);
Brian Paul959f8022000-03-19 01:10:11 +00001445 gl_pack_rgba_span( ctx, width, (CONST GLubyte (*)[4]) src,
1446 format, type, dest,
jtgafb833d1999-08-19 00:55:39 +00001447 &ctx->Pack, GL_TRUE );
1448 }
1449 else {
1450 /* fetch RGBA row from texture image then pack it in client mem */
1451 GLubyte rgba[MAX_WIDTH][4];
1452 GLint i;
1453 const GLubyte *src;
1454 switch (texImage->Format) {
1455 case GL_ALPHA:
1456 src = texImage->Data + row * width * sizeof(GLubyte);
1457 for (i = 0; i < width; i++) {
1458 rgba[i][RCOMP] = 255;
1459 rgba[i][GCOMP] = 255;
1460 rgba[i][BCOMP] = 255;
1461 rgba[i][ACOMP] = src[i];
1462 }
1463 break;
1464 case GL_LUMINANCE:
1465 src = texImage->Data + row * width * sizeof(GLubyte);
1466 for (i = 0; i < width; i++) {
1467 rgba[i][RCOMP] = src[i];
1468 rgba[i][GCOMP] = src[i];
1469 rgba[i][BCOMP] = src[i];
1470 rgba[i][ACOMP] = 255;
1471 }
1472 break;
1473 case GL_LUMINANCE_ALPHA:
1474 src = texImage->Data + row * 2 * width * sizeof(GLubyte);
1475 for (i = 0; i < width; i++) {
1476 rgba[i][RCOMP] = src[i*2+0];
1477 rgba[i][GCOMP] = src[i*2+0];
1478 rgba[i][BCOMP] = src[i*2+0];
1479 rgba[i][ACOMP] = src[i*2+1];
1480 }
1481 break;
1482 case GL_INTENSITY:
1483 src = texImage->Data + row * width * sizeof(GLubyte);
1484 for (i = 0; i < width; i++) {
1485 rgba[i][RCOMP] = src[i];
1486 rgba[i][GCOMP] = src[i];
1487 rgba[i][BCOMP] = src[i];
1488 rgba[i][ACOMP] = 255;
1489 }
1490 break;
1491 case GL_RGB:
1492 src = texImage->Data + row * 3 * width * sizeof(GLubyte);
1493 for (i = 0; i < width; i++) {
1494 rgba[i][RCOMP] = src[i*3+0];
1495 rgba[i][GCOMP] = src[i*3+1];
1496 rgba[i][BCOMP] = src[i*3+2];
1497 rgba[i][ACOMP] = 255;
1498 }
1499 break;
1500 case GL_RGBA:
1501 /* this special case should have been handled above! */
1502 gl_problem( ctx, "error 1 in gl_GetTexImage" );
1503 break;
1504 case GL_COLOR_INDEX:
1505 gl_problem( ctx, "GL_COLOR_INDEX not implemented in gl_GetTexImage" );
1506 break;
1507 default:
1508 gl_problem( ctx, "bad format in gl_GetTexImage" );
1509 }
1510 gl_pack_rgba_span( ctx, width, (const GLubyte (*)[4])rgba,
1511 format, type, dest, &ctx->Pack, GL_TRUE );
1512 }
1513 }
Brian Paulf7b57072000-03-20 14:37:52 +00001514
1515 /* if we got the teximage from the device driver we'll discard it now */
1516 if (discardImage) {
1517 FREE(texImage->Data);
1518 texImage->Data = NULL;
1519 }
jtgafb833d1999-08-19 00:55:39 +00001520 }
1521}
1522
1523
1524
Brian Paulfbd8f211999-11-11 01:22:25 +00001525void
1526_mesa_TexSubImage1D( GLenum target, GLint level,
1527 GLint xoffset, GLsizei width,
1528 GLenum format, GLenum type,
1529 const GLvoid *pixels )
jtgafb833d1999-08-19 00:55:39 +00001530{
Brian Paulfbd8f211999-11-11 01:22:25 +00001531 GET_CURRENT_CONTEXT(ctx);
jtgafb833d1999-08-19 00:55:39 +00001532 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
1533 struct gl_texture_image *destTex;
1534
Brian Paulc3f0a511999-11-03 17:27:05 +00001535 if (subtexture_error_check(ctx, 1, target, level, xoffset, 0, 0,
1536 width, 1, 1, format, type)) {
Brian Paulf7b57072000-03-20 14:37:52 +00001537 return; /* error was detected */
jtgafb833d1999-08-19 00:55:39 +00001538 }
1539
1540 destTex = texUnit->CurrentD[1]->Image[level];
Brian Paulc3f0a511999-11-03 17:27:05 +00001541 assert(destTex);
jtgafb833d1999-08-19 00:55:39 +00001542
Brian Paulc3f0a511999-11-03 17:27:05 +00001543 if (width == 0 || !pixels)
1544 return; /* no-op, not an error */
jtgafb833d1999-08-19 00:55:39 +00001545
Brian Paulc3f0a511999-11-03 17:27:05 +00001546
1547 /*
1548 * Replace the texture subimage
1549 */
1550 {
1551 const GLint texComponents = components_in_intformat(destTex->Format);
1552 const GLenum texFormat = destTex->Format;
Brian Paul91baaa31999-10-17 23:24:16 +00001553 const GLint xoffsetb = xoffset + destTex->Border;
Brian Paulc3f0a511999-11-03 17:27:05 +00001554 GLubyte *dst = destTex->Data + xoffsetb * texComponents;
1555 if (texFormat == GL_COLOR_INDEX) {
1556 /* color index texture */
1557 const GLvoid *src = gl_pixel_addr_in_image(&ctx->Unpack, pixels,
1558 width, 1, format, type, 0, 0, 0);
1559 _mesa_unpack_index_span(ctx, width, GL_UNSIGNED_BYTE, dst,
1560 type, src, &ctx->Unpack, GL_TRUE);
jtgafb833d1999-08-19 00:55:39 +00001561 }
1562 else {
Brian Paulc3f0a511999-11-03 17:27:05 +00001563 /* color texture */
1564 const GLvoid *src = gl_pixel_addr_in_image(&ctx->Unpack, pixels,
1565 width, 1, format, type, 0, 0, 0);
1566 _mesa_unpack_ubyte_color_span(ctx, width, texFormat, dst,
1567 format, type, src, &ctx->Unpack, GL_TRUE);
jtgafb833d1999-08-19 00:55:39 +00001568 }
Brian Paulc3f0a511999-11-03 17:27:05 +00001569 }
jtgafb833d1999-08-19 00:55:39 +00001570
Brian Paulc3f0a511999-11-03 17:27:05 +00001571 gl_put_texobj_on_dirty_list( ctx, texUnit->CurrentD[1] );
jtgafb833d1999-08-19 00:55:39 +00001572
Brian Paulc3f0a511999-11-03 17:27:05 +00001573 /*
1574 * Inform device driver of texture image change.
1575 */
1576 if (ctx->Driver.TexSubImage) {
1577 (*ctx->Driver.TexSubImage)(ctx, GL_TEXTURE_1D, texUnit->CurrentD[1],
1578 level, xoffset, 0, width, 1,
1579 texUnit->CurrentD[1]->Image[level]->IntFormat,
1580 destTex );
jtgafb833d1999-08-19 00:55:39 +00001581 }
1582 else {
Brian Paulc3f0a511999-11-03 17:27:05 +00001583 if (ctx->Driver.TexImage) {
1584 (*ctx->Driver.TexImage)(ctx, GL_TEXTURE_1D, texUnit->CurrentD[1],
1585 level,
1586 texUnit->CurrentD[1]->Image[level]->IntFormat,
1587 destTex );
jtgafb833d1999-08-19 00:55:39 +00001588 }
jtgafb833d1999-08-19 00:55:39 +00001589 }
1590}
1591
1592
Brian Paulfbd8f211999-11-11 01:22:25 +00001593void
1594_mesa_TexSubImage2D( GLenum target, GLint level,
1595 GLint xoffset, GLint yoffset,
1596 GLsizei width, GLsizei height,
1597 GLenum format, GLenum type,
1598 const GLvoid *pixels )
jtgafb833d1999-08-19 00:55:39 +00001599{
Brian Paulfbd8f211999-11-11 01:22:25 +00001600 GET_CURRENT_CONTEXT(ctx);
jtgafb833d1999-08-19 00:55:39 +00001601 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
1602 struct gl_texture_image *destTex;
1603
Brian Paulc3f0a511999-11-03 17:27:05 +00001604 if (subtexture_error_check(ctx, 2, target, level, xoffset, yoffset, 0,
1605 width, height, 1, format, type)) {
Brian Paulf7b57072000-03-20 14:37:52 +00001606 return; /* error was detected */
jtgafb833d1999-08-19 00:55:39 +00001607 }
1608
1609 destTex = texUnit->CurrentD[2]->Image[level];
Brian Paulc3f0a511999-11-03 17:27:05 +00001610 assert(destTex);
jtgafb833d1999-08-19 00:55:39 +00001611
Brian Paulc3f0a511999-11-03 17:27:05 +00001612 if (width == 0 || height == 0 || !pixels)
1613 return; /* no-op, not an error */
jtgafb833d1999-08-19 00:55:39 +00001614
Brian Paulc3f0a511999-11-03 17:27:05 +00001615
1616 /*
1617 * Replace the texture subimage
1618 */
1619 {
1620 const GLint texComponents = components_in_intformat(destTex->Format);
1621 const GLenum texFormat = destTex->Format;
Brian Paul91baaa31999-10-17 23:24:16 +00001622 const GLint xoffsetb = xoffset + destTex->Border;
1623 const GLint yoffsetb = yoffset + destTex->Border;
Brian Paulc3f0a511999-11-03 17:27:05 +00001624 GLubyte *dst = destTex->Data
1625 + (yoffsetb * destTex->Width + xoffsetb) * texComponents;
1626 if (texFormat == GL_COLOR_INDEX) {
1627 /* color index texture */
1628 const GLint stride = destTex->Width * sizeof(GLubyte);
1629 GLint row;
1630 for (row = 0; row < height; row++) {
1631 const GLvoid *src = gl_pixel_addr_in_image(&ctx->Unpack, pixels,
1632 width, height, format, type, 0, row, 0);
1633 _mesa_unpack_index_span(ctx, width, GL_UNSIGNED_BYTE, dst,
1634 type, src, &ctx->Unpack, GL_TRUE);
1635 dst += stride;
Brian Paul64a79b21999-10-22 10:43:35 +00001636 }
1637 }
jtgafb833d1999-08-19 00:55:39 +00001638 else {
Brian Paulc3f0a511999-11-03 17:27:05 +00001639 /* color texture */
1640 const GLint stride = destTex->Width * texComponents * sizeof(GLubyte);
1641 GLint row;
1642 for (row = 0; row < height; row++) {
1643 const GLvoid *src = gl_pixel_addr_in_image(&ctx->Unpack, pixels,
1644 width, height, format, type, 0, row, 0);
1645 _mesa_unpack_ubyte_color_span(ctx, width, texFormat, dst,
1646 format, type, src, &ctx->Unpack, GL_TRUE);
1647 dst += stride;
jtgafb833d1999-08-19 00:55:39 +00001648 }
jtgafb833d1999-08-19 00:55:39 +00001649 }
1650 }
jtgafb833d1999-08-19 00:55:39 +00001651
Brian Paulc3f0a511999-11-03 17:27:05 +00001652 gl_put_texobj_on_dirty_list( ctx, texUnit->CurrentD[2] );
1653
1654 /*
1655 * Inform device driver of texture image change.
1656 */
1657 if (ctx->Driver.TexSubImage) {
1658 (*ctx->Driver.TexSubImage)(ctx, GL_TEXTURE_2D, texUnit->CurrentD[2],
1659 level, xoffset, yoffset, width, height,
1660 texUnit->CurrentD[2]->Image[level]->IntFormat,
1661 destTex );
1662 }
1663 else {
1664 if (ctx->Driver.TexImage) {
1665 (*ctx->Driver.TexImage)(ctx, GL_TEXTURE_2D, texUnit->CurrentD[2],
1666 level,
1667 texUnit->CurrentD[2]->Image[level]->IntFormat,
1668 destTex );
jtgafb833d1999-08-19 00:55:39 +00001669 }
jtgafb833d1999-08-19 00:55:39 +00001670 }
1671}
1672
1673
1674
Brian Paulfbd8f211999-11-11 01:22:25 +00001675void
1676_mesa_TexSubImage3D( GLenum target, GLint level,
1677 GLint xoffset, GLint yoffset, GLint zoffset,
1678 GLsizei width, GLsizei height, GLsizei depth,
1679 GLenum format, GLenum type,
1680 const GLvoid *pixels )
jtgafb833d1999-08-19 00:55:39 +00001681{
Brian Paulfbd8f211999-11-11 01:22:25 +00001682 GET_CURRENT_CONTEXT(ctx);
jtgafb833d1999-08-19 00:55:39 +00001683 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
1684 struct gl_texture_image *destTex;
1685
Brian Paulc3f0a511999-11-03 17:27:05 +00001686 if (subtexture_error_check(ctx, 3, target, level, xoffset, yoffset, zoffset,
1687 width, height, depth, format, type)) {
Brian Paulf7b57072000-03-20 14:37:52 +00001688 return; /* error was detected */
jtgafb833d1999-08-19 00:55:39 +00001689 }
1690
1691 destTex = texUnit->CurrentD[3]->Image[level];
Brian Paulc3f0a511999-11-03 17:27:05 +00001692 assert(destTex);
jtgafb833d1999-08-19 00:55:39 +00001693
Brian Paulc3f0a511999-11-03 17:27:05 +00001694 if (width == 0 || height == 0 || height == 0 || !pixels)
1695 return; /* no-op, not an error */
jtgafb833d1999-08-19 00:55:39 +00001696
Brian Paulc3f0a511999-11-03 17:27:05 +00001697 /*
1698 * Replace the texture subimage
1699 */
1700 {
1701 const GLint texComponents = components_in_intformat(destTex->Format);
1702 const GLenum texFormat = destTex->Format;
Brian Paul91baaa31999-10-17 23:24:16 +00001703 const GLint xoffsetb = xoffset + destTex->Border;
1704 const GLint yoffsetb = yoffset + destTex->Border;
1705 const GLint zoffsetb = zoffset + destTex->Border;
Brian Paulc3f0a511999-11-03 17:27:05 +00001706 GLint dstRectArea = destTex->Width * destTex->Height;
1707 GLubyte *dst = destTex->Data
1708 + (zoffsetb * dstRectArea + yoffsetb * destTex->Width + xoffsetb)
1709 * texComponents;
jtgafb833d1999-08-19 00:55:39 +00001710
Brian Paulc3f0a511999-11-03 17:27:05 +00001711 if (texFormat == GL_COLOR_INDEX) {
1712 /* color index texture */
1713 const GLint stride = destTex->Width * sizeof(GLubyte);
1714 GLint img, row;
1715 for (img = 0; img < depth; img++) {
1716 for (row = 0; row < height; row++) {
1717 const GLvoid *src = gl_pixel_addr_in_image(&ctx->Unpack, pixels,
1718 width, height, format, type, img, row, 0);
1719 _mesa_unpack_index_span(ctx, width, GL_UNSIGNED_BYTE, dst,
1720 type, src, &ctx->Unpack, GL_TRUE);
1721 dst += stride;
1722 }
jtgafb833d1999-08-19 00:55:39 +00001723 }
1724 }
1725 else {
Brian Paulc3f0a511999-11-03 17:27:05 +00001726 /* color texture */
1727 const GLint stride = destTex->Width * texComponents * sizeof(GLubyte);
1728 GLint img, row;
1729 for (img = 0; img < depth; img++) {
1730 for (row = 0; row < height; row++) {
1731 const GLvoid *src = gl_pixel_addr_in_image(&ctx->Unpack, pixels,
1732 width, height, format, type, img, row, 0);
1733 _mesa_unpack_ubyte_color_span(ctx, width, texFormat, dst,
1734 format, type, src, &ctx->Unpack, GL_TRUE);
1735 dst += stride;
1736 }
jtgafb833d1999-08-19 00:55:39 +00001737 }
jtgafb833d1999-08-19 00:55:39 +00001738 }
1739 }
jtgafb833d1999-08-19 00:55:39 +00001740
Brian Paulc3f0a511999-11-03 17:27:05 +00001741 gl_put_texobj_on_dirty_list( ctx, texUnit->CurrentD[1] );
1742
1743 /*
1744 * Inform device driver of texture image change.
1745 */
1746 /* XXX todo */
jtgafb833d1999-08-19 00:55:39 +00001747}
1748
1749
1750
1751/*
1752 * Read an RGBA image from the frame buffer.
Brian Paulc3f0a511999-11-03 17:27:05 +00001753 * This is used by glCopyTexSubImage[12]D().
jtgafb833d1999-08-19 00:55:39 +00001754 * Input: ctx - the context
1755 * x, y - lower left corner
1756 * width, height - size of region to read
Brian Paulc3f0a511999-11-03 17:27:05 +00001757 * Return: pointer to block of GL_RGBA, GLubyte data.
jtgafb833d1999-08-19 00:55:39 +00001758 */
Brian Paulc3f0a511999-11-03 17:27:05 +00001759static GLubyte *
1760read_color_image( GLcontext *ctx, GLint x, GLint y,
1761 GLsizei width, GLsizei height )
jtgafb833d1999-08-19 00:55:39 +00001762{
Brian Paulc3f0a511999-11-03 17:27:05 +00001763 GLint stride, i;
1764 GLubyte *image, *dst;
jtgafb833d1999-08-19 00:55:39 +00001765
Brian Paul959f8022000-03-19 01:10:11 +00001766 image = (GLubyte *) MALLOC(width * height * 4 * sizeof(GLubyte));
Brian Paulc3f0a511999-11-03 17:27:05 +00001767 if (!image)
jtgafb833d1999-08-19 00:55:39 +00001768 return NULL;
jtgafb833d1999-08-19 00:55:39 +00001769
1770 /* Select buffer to read from */
Brian Paulcea0e8e1999-11-25 17:36:48 +00001771 (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
1772 ctx->Pixel.DriverReadBuffer );
jtgafb833d1999-08-19 00:55:39 +00001773
Brian Paulc3f0a511999-11-03 17:27:05 +00001774 dst = image;
1775 stride = width * 4 * sizeof(GLubyte);
1776 for (i = 0; i < height; i++) {
Brian Paul3f02f901999-11-24 18:48:30 +00001777 gl_read_rgba_span( ctx, ctx->ReadBuffer, width, x, y + i,
1778 (GLubyte (*)[4]) dst );
Brian Paulc3f0a511999-11-03 17:27:05 +00001779 dst += stride;
1780 }
jtgafb833d1999-08-19 00:55:39 +00001781
Brian Paulcea0e8e1999-11-25 17:36:48 +00001782 /* Read from draw buffer (the default) */
1783 (*ctx->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
1784 ctx->Color.DriverDrawBuffer );
jtgafb833d1999-08-19 00:55:39 +00001785
1786 return image;
1787}
1788
1789
1790
Brian Paulfbd8f211999-11-11 01:22:25 +00001791void
1792_mesa_CopyTexImage1D( GLenum target, GLint level,
1793 GLenum internalFormat,
1794 GLint x, GLint y,
1795 GLsizei width, GLint border )
jtgafb833d1999-08-19 00:55:39 +00001796{
Brian Paulfbd8f211999-11-11 01:22:25 +00001797 GET_CURRENT_CONTEXT(ctx);
jtgafb833d1999-08-19 00:55:39 +00001798 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glCopyTexImage1D");
jtgafb833d1999-08-19 00:55:39 +00001799
Brian Paulf7b57072000-03-20 14:37:52 +00001800 if (copytexture_error_check(ctx, 1, target, level, internalFormat,
1801 width, 1, border))
1802 return;
1803
1804 if (ctx->Pixel.MapColorFlag || ctx->Pixel.ScaleOrBiasRGBA
1805 || !ctx->Driver.CopyTexImage1D
1806 || !(*ctx->Driver.CopyTexImage1D)(ctx, target, level,
1807 internalFormat, x, y, width, border))
1808 {
Brian Paulc3f0a511999-11-03 17:27:05 +00001809 GLubyte *image = read_color_image( ctx, x, y, width, 1 );
1810 if (!image) {
1811 gl_error( ctx, GL_OUT_OF_MEMORY, "glCopyTexImage1D" );
1812 return;
1813 }
Brian Paul3ab6bbe2000-02-12 17:26:15 +00001814 (*ctx->Exec->TexImage1D)( target, level, internalFormat, width,
Brian Paulf7b57072000-03-20 14:37:52 +00001815 border, GL_RGBA, GL_UNSIGNED_BYTE, image );
Brian Paulc3f0a511999-11-03 17:27:05 +00001816 FREE(image);
jtgafb833d1999-08-19 00:55:39 +00001817 }
jtgafb833d1999-08-19 00:55:39 +00001818}
1819
1820
1821
Brian Paulfbd8f211999-11-11 01:22:25 +00001822void
1823_mesa_CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat,
1824 GLint x, GLint y, GLsizei width, GLsizei height,
1825 GLint border )
jtgafb833d1999-08-19 00:55:39 +00001826{
Brian Paulfbd8f211999-11-11 01:22:25 +00001827 GET_CURRENT_CONTEXT(ctx);
jtgafb833d1999-08-19 00:55:39 +00001828 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glCopyTexImage2D");
jtgafb833d1999-08-19 00:55:39 +00001829
Brian Paulf7b57072000-03-20 14:37:52 +00001830 if (copytexture_error_check(ctx, 2, target, level, internalFormat,
1831 width, height, border))
1832 return;
1833
1834 if (ctx->Pixel.MapColorFlag || ctx->Pixel.ScaleOrBiasRGBA
1835 || !ctx->Driver.CopyTexImage2D
1836 || !(*ctx->Driver.CopyTexImage2D)(ctx, target, level,
1837 internalFormat, x, y, width, height, border))
1838 {
Brian Paulc3f0a511999-11-03 17:27:05 +00001839 GLubyte *image = read_color_image( ctx, x, y, width, height );
1840 if (!image) {
1841 gl_error( ctx, GL_OUT_OF_MEMORY, "glCopyTexImage2D" );
1842 return;
1843 }
Brian Paul3ab6bbe2000-02-12 17:26:15 +00001844 (ctx->Exec->TexImage2D)( target, level, internalFormat, width,
Brian Paulf7b57072000-03-20 14:37:52 +00001845 height, border, GL_RGBA, GL_UNSIGNED_BYTE, image );
Brian Paulc3f0a511999-11-03 17:27:05 +00001846 FREE(image);
jtgafb833d1999-08-19 00:55:39 +00001847 }
jtgafb833d1999-08-19 00:55:39 +00001848}
1849
1850
1851
jtgafb833d1999-08-19 00:55:39 +00001852/*
1853 * Do the work of glCopyTexSubImage[123]D.
jtgafb833d1999-08-19 00:55:39 +00001854 */
Brian Paulc3f0a511999-11-03 17:27:05 +00001855static void
1856copy_tex_sub_image( GLcontext *ctx, struct gl_texture_image *dest,
1857 GLint width, GLint height,
1858 GLint srcx, GLint srcy,
1859 GLint dstx, GLint dsty, GLint dstz )
jtgafb833d1999-08-19 00:55:39 +00001860{
Brian Paulc3f0a511999-11-03 17:27:05 +00001861 static struct gl_pixelstore_attrib packing = {
1862 1, /* Alignment */
1863 0, /* RowLength */
1864 0, /* SkipPixels */
1865 0, /* SkipRows */
1866 0, /* ImageHeight */
1867 0, /* SkipImages */
1868 GL_FALSE, /* SwapBytes */
1869 GL_FALSE /* LsbFirst */
1870 };
1871
1872 GLint i;
jtgafb833d1999-08-19 00:55:39 +00001873 GLint format, components, rectarea;
Brian Paul91baaa31999-10-17 23:24:16 +00001874 GLint texwidth, texheight, zoffset;
jtgafb833d1999-08-19 00:55:39 +00001875
Brian Paul91baaa31999-10-17 23:24:16 +00001876 /* dst[xyz] may be negative if we have a texture border! */
1877 dstx += dest->Border;
1878 dsty += dest->Border;
1879 dstz += dest->Border;
jtgafb833d1999-08-19 00:55:39 +00001880 texwidth = dest->Width;
1881 texheight = dest->Height;
1882 rectarea = texwidth * texheight;
Brian Paul91baaa31999-10-17 23:24:16 +00001883 zoffset = dstz * rectarea;
jtgafb833d1999-08-19 00:55:39 +00001884 format = dest->Format;
1885 components = components_in_intformat( format );
1886
1887 /* Select buffer to read from */
Brian Paulcea0e8e1999-11-25 17:36:48 +00001888 (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
1889 ctx->Pixel.DriverReadBuffer );
jtgafb833d1999-08-19 00:55:39 +00001890
Brian Paulc3f0a511999-11-03 17:27:05 +00001891 for (i = 0;i < height; i++) {
jtgafb833d1999-08-19 00:55:39 +00001892 GLubyte rgba[MAX_WIDTH][4];
Brian Paulc3f0a511999-11-03 17:27:05 +00001893 GLubyte *dst;
Brian Paul3f02f901999-11-24 18:48:30 +00001894 gl_read_rgba_span( ctx, ctx->ReadBuffer, width, srcx, srcy + i, rgba );
Brian Paulc3f0a511999-11-03 17:27:05 +00001895 dst = dest->Data + ( zoffset + (dsty+i) * texwidth + dstx) * components;
1896 _mesa_unpack_ubyte_color_span(ctx, width, format, dst,
1897 GL_RGBA, GL_UNSIGNED_BYTE, rgba,
1898 &packing, GL_TRUE);
1899 }
jtgafb833d1999-08-19 00:55:39 +00001900
Brian Paulcea0e8e1999-11-25 17:36:48 +00001901 /* Read from draw buffer (the default) */
1902 (*ctx->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
1903 ctx->Color.DriverDrawBuffer );
jtgafb833d1999-08-19 00:55:39 +00001904}
1905
1906
1907
1908
Brian Paulfbd8f211999-11-11 01:22:25 +00001909void
1910_mesa_CopyTexSubImage1D( GLenum target, GLint level,
1911 GLint xoffset, GLint x, GLint y, GLsizei width )
jtgafb833d1999-08-19 00:55:39 +00001912{
Brian Paulfbd8f211999-11-11 01:22:25 +00001913 GET_CURRENT_CONTEXT(ctx);
jtgafb833d1999-08-19 00:55:39 +00001914 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glCopyTexSubImage1D");
jtgafb833d1999-08-19 00:55:39 +00001915
Brian Paulf7b57072000-03-20 14:37:52 +00001916 if (copytexsubimage_error_check(ctx, 1, target, level,
1917 xoffset, 0, 0, width, 1))
1918 return;
1919
1920 if (ctx->Pixel.MapColorFlag || ctx->Pixel.ScaleOrBiasRGBA
1921 || !ctx->Driver.CopyTexSubImage1D
1922 || !(*ctx->Driver.CopyTexSubImage1D)(ctx, target, level,
1923 xoffset, x, y, width)) {
Brian Paulc3f0a511999-11-03 17:27:05 +00001924 struct gl_texture_unit *texUnit;
1925 struct gl_texture_image *teximage;
1926 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
1927 teximage = texUnit->CurrentD[1]->Image[level];
1928 assert(teximage);
jtgafb833d1999-08-19 00:55:39 +00001929 if (teximage->Data) {
Brian Paulc3f0a511999-11-03 17:27:05 +00001930 copy_tex_sub_image(ctx, teximage, width, 1, x, y, xoffset, 0, 0);
Brian Paulf7b57072000-03-20 14:37:52 +00001931 /* tell driver about the change */
1932 if (ctx->Driver.TexImage) {
1933 (*ctx->Driver.TexImage)( ctx, GL_TEXTURE_1D,
1934 texUnit->CurrentD[1],
1935 level, teximage->IntFormat, teximage );
1936 }
jtgafb833d1999-08-19 00:55:39 +00001937 }
1938 }
Brian Paulc3f0a511999-11-03 17:27:05 +00001939}
1940
1941
1942
Brian Paulfbd8f211999-11-11 01:22:25 +00001943void
1944_mesa_CopyTexSubImage2D( GLenum target, GLint level,
1945 GLint xoffset, GLint yoffset,
1946 GLint x, GLint y, GLsizei width, GLsizei height )
Brian Paulc3f0a511999-11-03 17:27:05 +00001947{
Brian Paulfbd8f211999-11-11 01:22:25 +00001948 GET_CURRENT_CONTEXT(ctx);
Brian Paulc3f0a511999-11-03 17:27:05 +00001949 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glCopyTexSubImage2D");
1950
Brian Paulf7b57072000-03-20 14:37:52 +00001951 if (copytexsubimage_error_check(ctx, 2, target, level,
1952 xoffset, yoffset, 0, width, height))
1953 return;
1954
1955 if (ctx->Pixel.MapColorFlag || ctx->Pixel.ScaleOrBiasRGBA
1956 || !ctx->Driver.CopyTexSubImage2D
1957 || !(*ctx->Driver.CopyTexSubImage2D)(ctx, target, level,
1958 xoffset, yoffset, x, y, width, height )) {
Brian Paulc3f0a511999-11-03 17:27:05 +00001959 struct gl_texture_unit *texUnit;
1960 struct gl_texture_image *teximage;
1961 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
1962 teximage = texUnit->CurrentD[2]->Image[level];
1963 assert(teximage);
1964 if (teximage->Data) {
1965 copy_tex_sub_image(ctx, teximage, width, height,
1966 x, y, xoffset, yoffset, 0);
Brian Paulf7b57072000-03-20 14:37:52 +00001967 /* tell driver about the change */
1968 if (ctx->Driver.TexImage) {
1969 (*ctx->Driver.TexImage)( ctx, GL_TEXTURE_2D,
1970 texUnit->CurrentD[2],
1971 level, teximage->IntFormat, teximage );
Brian Paulc3f0a511999-11-03 17:27:05 +00001972 }
1973 }
1974 }
1975}
1976
1977
1978
Brian Paulfbd8f211999-11-11 01:22:25 +00001979void
1980_mesa_CopyTexSubImage3D( GLenum target, GLint level,
1981 GLint xoffset, GLint yoffset, GLint zoffset,
1982 GLint x, GLint y, GLsizei width, GLsizei height )
Brian Paulc3f0a511999-11-03 17:27:05 +00001983{
Brian Paulfbd8f211999-11-11 01:22:25 +00001984 GET_CURRENT_CONTEXT(ctx);
Brian Paulc3f0a511999-11-03 17:27:05 +00001985 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glCopyTexSubImage3D");
1986
Brian Paulf7b57072000-03-20 14:37:52 +00001987 if (copytexsubimage_error_check(ctx, 3, target, level,
1988 xoffset, yoffset, zoffset, width, height))
1989 return;
1990
1991 if (ctx->Pixel.MapColorFlag || ctx->Pixel.ScaleOrBiasRGBA
1992 || !ctx->Driver.CopyTexSubImage3D
1993 || !(*ctx->Driver.CopyTexSubImage3D)(ctx, target, level,
1994 xoffset, yoffset, zoffset, x, y, width, height )) {
1995 struct gl_texture_unit *texUnit;
1996 struct gl_texture_image *teximage;
1997 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
1998 teximage = texUnit->CurrentD[3]->Image[level];
1999 assert(teximage);
2000 if (teximage->Data) {
2001 copy_tex_sub_image(ctx, teximage, width, height,
Brian Paulc3f0a511999-11-03 17:27:05 +00002002 x, y, xoffset, yoffset, zoffset);
Brian Paulf7b57072000-03-20 14:37:52 +00002003 /* tell driver about the change */
2004 if (ctx->Driver.TexImage) {
2005 (*ctx->Driver.TexImage)( ctx, GL_TEXTURE_3D,
2006 texUnit->CurrentD[3],
2007 level, teximage->IntFormat, teximage );
2008 }
Brian Paulc3f0a511999-11-03 17:27:05 +00002009 }
jtgafb833d1999-08-19 00:55:39 +00002010 }
2011}