📄 s_blend.c
字号:
/* * Mesa 3-D graphics library * Version: 7.1 * * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *//** * \file swrast/s_blend.c * \brief software blending. * \author Brian Paul * * Only a few blend modes have been optimized (min, max, transparency, add) * more optimized cases can easily be added if needed. * Celestia uses glBlendFunc(GL_SRC_ALPHA, GL_ONE), for example. */#include "glheader.h"#include "context.h"#include "colormac.h"#include "macros.h"#include "s_blend.h"#include "s_context.h"#include "s_span.h"#if defined(USE_MMX_ASM)#include "x86/mmx.h"#include "x86/common_x86_asm.h"#define _BLENDAPI _ASMAPI#else#define _BLENDAPI#endif/** * Integer divide by 255 * Declare "int divtemp" before using. * This satisfies Glean and should be reasonably fast. * Contributed by Nathan Hand. */#define DIV255(X) (divtemp = (X), ((divtemp << 8) + divtemp + 256) >> 16)/** * Special case for glBlendFunc(GL_ZERO, GL_ONE). * No-op means the framebuffer values remain unchanged. * Any chanType ok. */static void _BLENDAPIblend_noop(GLcontext *ctx, GLuint n, const GLubyte mask[], GLvoid *src, const GLvoid *dst, GLenum chanType){ GLint bytes; ASSERT(ctx->Color.BlendEquationRGB == GL_FUNC_ADD); ASSERT(ctx->Color.BlendEquationA == GL_FUNC_ADD); ASSERT(ctx->Color.BlendSrcRGB == GL_ZERO); ASSERT(ctx->Color.BlendDstRGB == GL_ONE); (void) ctx; /* just memcpy */ if (chanType == GL_UNSIGNED_BYTE) bytes = 4 * n * sizeof(GLubyte); else if (chanType == GL_UNSIGNED_SHORT) bytes = 4 * n * sizeof(GLushort); else bytes = 4 * n * sizeof(GLfloat); _mesa_memcpy(src, dst, bytes);}/** * Special case for glBlendFunc(GL_ONE, GL_ZERO) * Any chanType ok. */static void _BLENDAPIblend_replace(GLcontext *ctx, GLuint n, const GLubyte mask[], GLvoid *src, const GLvoid *dst, GLenum chanType){ ASSERT(ctx->Color.BlendEquationRGB == GL_FUNC_ADD); ASSERT(ctx->Color.BlendEquationA == GL_FUNC_ADD); ASSERT(ctx->Color.BlendSrcRGB == GL_ONE); ASSERT(ctx->Color.BlendDstRGB == GL_ZERO); (void) ctx; (void) n; (void) mask; (void) src; (void) dst;}/** * Common transparency blending mode: * glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA). */static void _BLENDAPIblend_transparency_ubyte(GLcontext *ctx, GLuint n, const GLubyte mask[], GLvoid *src, const GLvoid *dst, GLenum chanType){ GLubyte (*rgba)[4] = (GLubyte (*)[4]) src; const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst; GLuint i; ASSERT(ctx->Color.BlendEquationRGB == GL_FUNC_ADD); ASSERT(ctx->Color.BlendEquationA == GL_FUNC_ADD); ASSERT(ctx->Color.BlendSrcRGB == GL_SRC_ALPHA); ASSERT(ctx->Color.BlendSrcA == GL_SRC_ALPHA); ASSERT(ctx->Color.BlendDstRGB == GL_ONE_MINUS_SRC_ALPHA); ASSERT(ctx->Color.BlendDstA == GL_ONE_MINUS_SRC_ALPHA); ASSERT(chanType == GL_UNSIGNED_BYTE); (void) ctx; for (i = 0; i < n; i++) { if (mask[i]) { const GLint t = rgba[i][ACOMP]; /* t is in [0, 255] */ if (t == 0) { /* 0% alpha */ COPY_4UBV(rgba[i], dest[i]); } else if (t != 255) { GLint divtemp; const GLint r = DIV255((rgba[i][RCOMP] - dest[i][RCOMP]) * t) + dest[i][RCOMP]; const GLint g = DIV255((rgba[i][GCOMP] - dest[i][GCOMP]) * t) + dest[i][GCOMP]; const GLint b = DIV255((rgba[i][BCOMP] - dest[i][BCOMP]) * t) + dest[i][BCOMP]; const GLint a = DIV255((rgba[i][ACOMP] - dest[i][ACOMP]) * t) + dest[i][ACOMP]; ASSERT(r <= 255); ASSERT(g <= 255); ASSERT(b <= 255); ASSERT(a <= 255); rgba[i][RCOMP] = (GLubyte) r; rgba[i][GCOMP] = (GLubyte) g; rgba[i][BCOMP] = (GLubyte) b; rgba[i][ACOMP] = (GLubyte) a; } } }}static void _BLENDAPIblend_transparency_ushort(GLcontext *ctx, GLuint n, const GLubyte mask[], GLvoid *src, const GLvoid *dst, GLenum chanType){ GLushort (*rgba)[4] = (GLushort (*)[4]) src; const GLushort (*dest)[4] = (const GLushort (*)[4]) dst; GLuint i; ASSERT(ctx->Color.BlendEquationRGB == GL_FUNC_ADD); ASSERT(ctx->Color.BlendEquationA == GL_FUNC_ADD); ASSERT(ctx->Color.BlendSrcRGB == GL_SRC_ALPHA); ASSERT(ctx->Color.BlendSrcA == GL_SRC_ALPHA); ASSERT(ctx->Color.BlendDstRGB == GL_ONE_MINUS_SRC_ALPHA); ASSERT(ctx->Color.BlendDstA == GL_ONE_MINUS_SRC_ALPHA); ASSERT(chanType == GL_UNSIGNED_SHORT); (void) ctx; for (i = 0; i < n; i++) { if (mask[i]) { const GLint t = rgba[i][ACOMP]; if (t == 0) { /* 0% alpha */ COPY_4V(rgba[i], dest[i]); } else if (t != 65535) { const GLfloat tt = (GLfloat) t / 65535.0F; GLushort r = (GLushort) ((rgba[i][RCOMP] - dest[i][RCOMP]) * tt + dest[i][RCOMP]); GLushort g = (GLushort) ((rgba[i][GCOMP] - dest[i][GCOMP]) * tt + dest[i][GCOMP]); GLushort b = (GLushort) ((rgba[i][BCOMP] - dest[i][BCOMP]) * tt + dest[i][BCOMP]); GLushort a = (GLushort) ((rgba[i][ACOMP] - dest[i][ACOMP]) * tt + dest[i][ACOMP]); ASSIGN_4V(rgba[i], r, g, b, a); } } }}static void _BLENDAPIblend_transparency_float(GLcontext *ctx, GLuint n, const GLubyte mask[], GLvoid *src, const GLvoid *dst, GLenum chanType){ GLfloat (*rgba)[4] = (GLfloat (*)[4]) src; const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst; GLuint i; ASSERT(ctx->Color.BlendEquationRGB == GL_FUNC_ADD); ASSERT(ctx->Color.BlendEquationA == GL_FUNC_ADD); ASSERT(ctx->Color.BlendSrcRGB == GL_SRC_ALPHA); ASSERT(ctx->Color.BlendSrcA == GL_SRC_ALPHA); ASSERT(ctx->Color.BlendDstRGB == GL_ONE_MINUS_SRC_ALPHA); ASSERT(ctx->Color.BlendDstA == GL_ONE_MINUS_SRC_ALPHA); ASSERT(chanType == GL_FLOAT); (void) ctx; for (i = 0; i < n; i++) { if (mask[i]) { const GLfloat t = rgba[i][ACOMP]; /* t in [0, 1] */ if (t == 0.0F) { /* 0% alpha */ COPY_4V(rgba[i], dest[i]); } else if (t != 1.0F) { GLfloat r = (rgba[i][RCOMP] - dest[i][RCOMP]) * t + dest[i][RCOMP]; GLfloat g = (rgba[i][GCOMP] - dest[i][GCOMP]) * t + dest[i][GCOMP]; GLfloat b = (rgba[i][BCOMP] - dest[i][BCOMP]) * t + dest[i][BCOMP]; GLfloat a = (rgba[i][ACOMP] - dest[i][ACOMP]) * t + dest[i][ACOMP]; ASSIGN_4V(rgba[i], r, g, b, a); } } }}/** * Add src and dest: glBlendFunc(GL_ONE, GL_ONE). * Any chanType ok. */static void _BLENDAPIblend_add(GLcontext *ctx, GLuint n, const GLubyte mask[], GLvoid *src, const GLvoid *dst, GLenum chanType){ GLuint i; ASSERT(ctx->Color.BlendEquationRGB == GL_FUNC_ADD); ASSERT(ctx->Color.BlendEquationA == GL_FUNC_ADD); ASSERT(ctx->Color.BlendSrcRGB == GL_ONE); ASSERT(ctx->Color.BlendDstRGB == GL_ONE); (void) ctx; if (chanType == GL_UNSIGNED_BYTE) { GLubyte (*rgba)[4] = (GLubyte (*)[4]) src; const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst; for (i=0;i<n;i++) { if (mask[i]) { GLint r = rgba[i][RCOMP] + dest[i][RCOMP]; GLint g = rgba[i][GCOMP] + dest[i][GCOMP]; GLint b = rgba[i][BCOMP] + dest[i][BCOMP]; GLint a = rgba[i][ACOMP] + dest[i][ACOMP]; rgba[i][RCOMP] = (GLubyte) MIN2( r, 255 ); rgba[i][GCOMP] = (GLubyte) MIN2( g, 255 ); rgba[i][BCOMP] = (GLubyte) MIN2( b, 255 ); rgba[i][ACOMP] = (GLubyte) MIN2( a, 255 ); } } } else if (chanType == GL_UNSIGNED_SHORT) { GLushort (*rgba)[4] = (GLushort (*)[4]) src; const GLushort (*dest)[4] = (const GLushort (*)[4]) dst; for (i=0;i<n;i++) { if (mask[i]) { GLint r = rgba[i][RCOMP] + dest[i][RCOMP]; GLint g = rgba[i][GCOMP] + dest[i][GCOMP]; GLint b = rgba[i][BCOMP] + dest[i][BCOMP]; GLint a = rgba[i][ACOMP] + dest[i][ACOMP]; rgba[i][RCOMP] = (GLshort) MIN2( r, 255 ); rgba[i][GCOMP] = (GLshort) MIN2( g, 255 ); rgba[i][BCOMP] = (GLshort) MIN2( b, 255 ); rgba[i][ACOMP] = (GLshort) MIN2( a, 255 ); } } } else { GLfloat (*rgba)[4] = (GLfloat (*)[4]) src; const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst; ASSERT(chanType == GL_FLOAT); for (i=0;i<n;i++) { if (mask[i]) { /* don't RGB clamp to max */ rgba[i][RCOMP] += dest[i][RCOMP]; rgba[i][GCOMP] += dest[i][GCOMP]; rgba[i][BCOMP] += dest[i][BCOMP]; rgba[i][ACOMP] += dest[i][ACOMP]; } } }}/** * Blend min function. * Any chanType ok. */static void _BLENDAPIblend_min(GLcontext *ctx, GLuint n, const GLubyte mask[], GLvoid *src, const GLvoid *dst, GLenum chanType){ GLuint i; ASSERT(ctx->Color.BlendEquationRGB == GL_MIN); ASSERT(ctx->Color.BlendEquationA == GL_MIN); (void) ctx; if (chanType == GL_UNSIGNED_BYTE) { GLubyte (*rgba)[4] = (GLubyte (*)[4]) src; const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst; for (i=0;i<n;i++) { if (mask[i]) { rgba[i][RCOMP] = MIN2( rgba[i][RCOMP], dest[i][RCOMP] ); rgba[i][GCOMP] = MIN2( rgba[i][GCOMP], dest[i][GCOMP] ); rgba[i][BCOMP] = MIN2( rgba[i][BCOMP], dest[i][BCOMP] ); rgba[i][ACOMP] = MIN2( rgba[i][ACOMP], dest[i][ACOMP] ); } } } else if (chanType == GL_UNSIGNED_SHORT) { GLushort (*rgba)[4] = (GLushort (*)[4]) src; const GLushort (*dest)[4] = (const GLushort (*)[4]) dst; for (i=0;i<n;i++) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -