📄 mipmap.c
字号:
/* allocate storage for uncompressed GL_RGB or GL_RGBA images */ size = _mesa_bytes_per_pixel(srcImage->_BaseFormat, CHAN_TYPE) * srcImage->Width * srcImage->Height * srcImage->Depth + 20; /* 20 extra bytes, just be safe when calling last FetchTexel */ srcData = (GLubyte *) _mesa_malloc(size); if (!srcData) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps"); return; } dstData = (GLubyte *) _mesa_malloc(size / 2); /* 1/4 would probably be OK */ if (!dstData) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps"); _mesa_free((void *) srcData); return; } /* decompress base image here */ dst = (GLchan *) srcData; for (row = 0; row < srcImage->Height; row++) { GLuint col; for (col = 0; col < srcImage->Width; col++) { srcImage->FetchTexelc(srcImage, col, row, 0, dst); dst += components; } } } else { /* uncompressed */ convertFormat = srcImage->TexFormat; } for (level = texObj->BaseLevel; level < texObj->MaxLevel && level < maxLevels - 1; level++) { /* generate image[level+1] from image[level] */ const struct gl_texture_image *srcImage; struct gl_texture_image *dstImage; GLint srcWidth, srcHeight, srcDepth; GLint dstWidth, dstHeight, dstDepth; GLint border, bytesPerTexel; /* get src image parameters */ srcImage = _mesa_select_tex_image(ctx, texObj, target, level); ASSERT(srcImage); srcWidth = srcImage->Width; srcHeight = srcImage->Height; srcDepth = srcImage->Depth; border = srcImage->Border; /* compute next (level+1) image size */ if (srcWidth - 2 * border > 1) { dstWidth = (srcWidth - 2 * border) / 2 + 2 * border; } else { dstWidth = srcWidth; /* can't go smaller */ } if ((srcHeight - 2 * border > 1) && (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT)) { dstHeight = (srcHeight - 2 * border) / 2 + 2 * border; } else { dstHeight = srcHeight; /* can't go smaller */ } if ((srcDepth - 2 * border > 1) && (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT)) { dstDepth = (srcDepth - 2 * border) / 2 + 2 * border; } else { dstDepth = srcDepth; /* can't go smaller */ } if (dstWidth == srcWidth && dstHeight == srcHeight && dstDepth == srcDepth) { /* all done */ if (srcImage->IsCompressed) { _mesa_free((void *) srcData); _mesa_free(dstData); } return; } /* get dest gl_texture_image */ dstImage = _mesa_get_tex_image(ctx, texObj, target, level + 1); if (!dstImage) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps"); return; } if (dstImage->ImageOffsets) _mesa_free(dstImage->ImageOffsets); /* Free old image data */ if (dstImage->Data) ctx->Driver.FreeTexImageData(ctx, dstImage); /* initialize new image */ _mesa_init_teximage_fields(ctx, target, dstImage, dstWidth, dstHeight, dstDepth, border, srcImage->InternalFormat); dstImage->DriverData = NULL; dstImage->TexFormat = srcImage->TexFormat; dstImage->FetchTexelc = srcImage->FetchTexelc; dstImage->FetchTexelf = srcImage->FetchTexelf; dstImage->IsCompressed = srcImage->IsCompressed; if (dstImage->IsCompressed) { dstImage->CompressedSize = ctx->Driver.CompressedTextureSize(ctx, dstImage->Width, dstImage->Height, dstImage->Depth, dstImage->TexFormat->MesaFormat); ASSERT(dstImage->CompressedSize > 0); } ASSERT(dstImage->TexFormat); ASSERT(dstImage->FetchTexelc); ASSERT(dstImage->FetchTexelf); /* Alloc new teximage data buffer. * Setup src and dest data pointers. */ if (dstImage->IsCompressed) { dstImage->Data = _mesa_alloc_texmemory(dstImage->CompressedSize); if (!dstImage->Data) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps"); return; } /* srcData and dstData are already set */ ASSERT(srcData); ASSERT(dstData); } else { bytesPerTexel = dstImage->TexFormat->TexelBytes; ASSERT(dstWidth * dstHeight * dstDepth * bytesPerTexel > 0); dstImage->Data = _mesa_alloc_texmemory(dstWidth * dstHeight * dstDepth * bytesPerTexel); if (!dstImage->Data) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps"); return; } srcData = (const GLubyte *) srcImage->Data; dstData = (GLubyte *) dstImage->Data; } /* * We use simple 2x2 averaging to compute the next mipmap level. */ switch (target) { case GL_TEXTURE_1D: make_1d_mipmap(convertFormat, border, srcWidth, srcData, dstWidth, dstData); break; case GL_TEXTURE_2D: case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB: case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB: case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB: case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB: case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB: case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB: make_2d_mipmap(convertFormat, border, srcWidth, srcHeight, srcData, srcImage->RowStride, dstWidth, dstHeight, dstData, dstImage->RowStride); break; case GL_TEXTURE_3D: make_3d_mipmap(convertFormat, border, srcWidth, srcHeight, srcDepth, srcData, srcImage->RowStride, dstWidth, dstHeight, dstDepth, dstData, dstImage->RowStride); break; case GL_TEXTURE_1D_ARRAY_EXT: make_1d_stack_mipmap(convertFormat, border, srcWidth, srcData, srcImage->RowStride, dstWidth, dstHeight, dstData, dstImage->RowStride); break; case GL_TEXTURE_2D_ARRAY_EXT: make_2d_stack_mipmap(convertFormat, border, srcWidth, srcHeight, srcData, srcImage->RowStride, dstWidth, dstHeight, dstDepth, dstData, dstImage->RowStride); break; case GL_TEXTURE_RECTANGLE_NV: /* no mipmaps, do nothing */ break; default: _mesa_problem(ctx, "bad dimensions in _mesa_generate_mipmaps"); return; } if (dstImage->IsCompressed) { GLubyte *temp; /* compress image from dstData into dstImage->Data */ const GLenum srcFormat = convertFormat->BaseFormat; GLint dstRowStride = _mesa_compressed_row_stride(dstImage->TexFormat->MesaFormat, dstWidth); ASSERT(srcFormat == GL_RGB || srcFormat == GL_RGBA); dstImage->TexFormat->StoreImage(ctx, 2, dstImage->_BaseFormat, dstImage->TexFormat, dstImage->Data, 0, 0, 0, /* dstX/Y/Zoffset */ dstRowStride, 0, /* strides */ dstWidth, dstHeight, 1, /* size */ srcFormat, CHAN_TYPE, dstData, /* src data, actually */ &ctx->DefaultPacking); /* swap src and dest pointers */ temp = (GLubyte *) srcData; srcData = dstData; dstData = temp; } } /* loop over mipmap levels */}/** * Helper function for drivers which need to rescale texture images to * certain aspect ratios. * Nearest filtering only (for broken hardware that can't support * all aspect ratios). This can be made a lot faster, but I don't * really care enough... */void_mesa_rescale_teximage2d(GLuint bytesPerPixel, GLuint srcStrideInPixels, GLuint dstRowStride, GLint srcWidth, GLint srcHeight, GLint dstWidth, GLint dstHeight, const GLvoid *srcImage, GLvoid *dstImage){ GLint row, col;#define INNER_LOOP( TYPE, HOP, WOP ) \ for ( row = 0 ; row < dstHeight ; row++ ) { \ GLint srcRow = row HOP hScale; \ for ( col = 0 ; col < dstWidth ; col++ ) { \ GLint srcCol = col WOP wScale; \ dst[col] = src[srcRow * srcStrideInPixels + srcCol]; \ } \ dst = (TYPE *) ((GLubyte *) dst + dstRowStride); \ } \#define RESCALE_IMAGE( TYPE ) \do { \ const TYPE *src = (const TYPE *)srcImage; \ TYPE *dst = (TYPE *)dstImage; \ \ if ( srcHeight < dstHeight ) { \ const GLint hScale = dstHeight / srcHeight; \ if ( srcWidth < dstWidth ) { \ const GLint wScale = dstWidth / srcWidth; \ INNER_LOOP( TYPE, /, / ); \ } \ else { \ const GLint wScale = srcWidth / dstWidth; \ INNER_LOOP( TYPE, /, * ); \ } \ } \ else { \ const GLint hScale = srcHeight / dstHeight; \ if ( srcWidth < dstWidth ) { \ const GLint wScale = dstWidth / srcWidth; \ INNER_LOOP( TYPE, *, / ); \ } \ else { \ const GLint wScale = srcWidth / dstWidth; \ INNER_LOOP( TYPE, *, * ); \ } \ } \} while (0) switch ( bytesPerPixel ) { case 4: RESCALE_IMAGE( GLuint ); break; case 2: RESCALE_IMAGE( GLushort ); break; case 1: RESCALE_IMAGE( GLubyte ); break; default: _mesa_problem(NULL,"unexpected bytes/pixel in _mesa_rescale_teximage2d"); }}/** * Upscale an image by replication, not (typical) stretching. * We use this when the image width or height is less than a * certain size (4, 8) and we need to upscale an image. */void_mesa_upscale_teximage2d(GLsizei inWidth, GLsizei inHeight, GLsizei outWidth, GLsizei outHeight, GLint comps, const GLchan *src, GLint srcRowStride, GLchan *dest ){ GLint i, j, k; ASSERT(outWidth >= inWidth); ASSERT(outHeight >= inHeight);#if 0 ASSERT(inWidth == 1 || inWidth == 2 || inHeight == 1 || inHeight == 2); ASSERT((outWidth & 3) == 0); ASSERT((outHeight & 3) == 0);#endif for (i = 0; i < outHeight; i++) { const GLint ii = i % inHeight; for (j = 0; j < outWidth; j++) { const GLint jj = j % inWidth; for (k = 0; k < comps; k++) { dest[(i * outWidth + j) * comps + k] = src[ii * srcRowStride + jj * comps + k]; } } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -