static SDL_bool GLES_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode) { GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata; SDL_BlendFactor srcColorFactor = SDL_GetBlendModeSrcColorFactor(blendMode); SDL_BlendFactor srcAlphaFactor = SDL_GetBlendModeSrcAlphaFactor(blendMode); SDL_BlendOperation colorOperation = SDL_GetBlendModeColorOperation(blendMode); SDL_BlendFactor dstColorFactor = SDL_GetBlendModeDstColorFactor(blendMode); SDL_BlendFactor dstAlphaFactor = SDL_GetBlendModeDstAlphaFactor(blendMode); SDL_BlendOperation alphaOperation = SDL_GetBlendModeAlphaOperation(blendMode); if (GetBlendFunc(srcColorFactor) == GL_INVALID_ENUM || GetBlendFunc(srcAlphaFactor) == GL_INVALID_ENUM || GetBlendEquation(colorOperation) == GL_INVALID_ENUM || GetBlendFunc(dstColorFactor) == GL_INVALID_ENUM || GetBlendFunc(dstAlphaFactor) == GL_INVALID_ENUM || GetBlendEquation(alphaOperation) == GL_INVALID_ENUM) { return SDL_FALSE; } if ((srcColorFactor != srcAlphaFactor || dstColorFactor != dstAlphaFactor) && !data->GL_OES_blend_func_separate_supported) { return SDL_FALSE; } if (colorOperation != alphaOperation && !data->GL_OES_blend_equation_separate_supported) { return SDL_FALSE; } if (colorOperation != SDL_BLENDOPERATION_ADD && !data->GL_OES_blend_subtract_supported) { return SDL_FALSE; } return SDL_TRUE; }
static void GLES_SetBlendMode(GLES_RenderData * data, SDL_BlendMode blendMode) { if (blendMode != data->current.blendMode) { if (blendMode == SDL_BLENDMODE_NONE) { data->glDisable(GL_BLEND); } else { data->glEnable(GL_BLEND); if (data->GL_OES_blend_func_separate_supported) { data->glBlendFuncSeparateOES(GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blendMode)), GetBlendFunc(SDL_GetBlendModeDstColorFactor(blendMode)), GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blendMode)), GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blendMode))); } else { data->glBlendFunc(GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blendMode)), GetBlendFunc(SDL_GetBlendModeDstColorFactor(blendMode))); } if (data->GL_OES_blend_equation_separate_supported) { data->glBlendEquationSeparateOES(GetBlendEquation(SDL_GetBlendModeColorOperation(blendMode)), GetBlendEquation(SDL_GetBlendModeAlphaOperation(blendMode))); } else if (data->GL_OES_blend_subtract_supported) { data->glBlendEquationOES(GetBlendEquation(SDL_GetBlendModeColorOperation(blendMode))); } } data->current.blendMode = blendMode; } }
void CG3DGraphicsGL::ApplySet(CG3DGlobalSet::SetType type) { switch (type) { case CG3DGlobalSet::COLOUR: { CG3DColourSet* set = (CG3DColourSet*)m_Stacks[type].m_Value; if (set->m_DoClear) m_ClearEnabled |= GL_COLOR_BUFFER_BIT; else m_ClearEnabled &= ~GL_COLOR_BUFFER_BIT; CG3DVector4 cfloat = set->m_Clear.Get4f(); glClearColor(cfloat.x, cfloat.y, cfloat.z, cfloat.w); glColorMask(set->m_UseR, set->m_UseG, set->m_UseB, set->m_UseA); } break; case CG3DGlobalSet::DEPTH: { CG3DDepthSet* set = (CG3DDepthSet*)m_Stacks[type].m_Value; if (set->m_DoClear) m_ClearEnabled |= GL_DEPTH_BUFFER_BIT; else m_ClearEnabled &= ~GL_DEPTH_BUFFER_BIT; glClearDepthf(set->m_Clear); glDepthMask(set->m_WriteDepth); switch (set->m_Test) { case CG3DDepthSet::ALWAYS: glDisable(GL_DEPTH_TEST); break; case CG3DDepthSet::NEVER: glEnable(GL_DEPTH_TEST); glDepthFunc(GL_NEVER); break; case CG3DDepthSet::LESS: glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); break; case CG3DDepthSet::LEQUAL: glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); break; case CG3DDepthSet::EQUAL: glEnable(GL_DEPTH_TEST); glDepthFunc(GL_EQUAL); break; case CG3DDepthSet::GREATER: glEnable(GL_DEPTH_TEST); glDepthFunc(GL_GREATER); break; case CG3DDepthSet::GEQUAL: glEnable(GL_DEPTH_TEST); glDepthFunc(GL_GEQUAL); break; case CG3DDepthSet::NOTEQUAL: glEnable(GL_DEPTH_TEST); glDepthFunc(GL_NOTEQUAL); break; } } break; case CG3DGlobalSet::STENCIL: { CG3DStencilSet* set = (CG3DStencilSet*)m_Stacks[type].m_Value; if (set->m_DoClear) m_ClearEnabled |= GL_STENCIL_BUFFER_BIT; else m_ClearEnabled &= ~GL_STENCIL_BUFFER_BIT; glClearStencil(set->m_Clear); ApplyStencil(set); } break; case CG3DGlobalSet::CULL: { CG3DCullSet* set = (CG3DCullSet*)m_Stacks[type].m_Value; switch (set->m_Cull) { case CG3DCullSet::CULL_NONE: glDisable(GL_CULL_FACE); break; case CG3DCullSet::CULL_FRONT: glEnable(GL_CULL_FACE); glCullFace(GL_FRONT); break; case CG3DCullSet::CULL_BACK: glEnable(GL_CULL_FACE); glCullFace(GL_BACK); break; } //if (set->m_FrontIsCCW != CG3DCullSet::NO) glFrontFace(GL_CCW); //else // glFrontFace(GL_CW); } break; case CG3DGlobalSet::VIEWPORT: { CG3DViewportSet* set = (CG3DViewportSet*)m_Stacks[type].m_Value; glViewport((int)set->m_Rect.x, (int)set->m_Rect.y, (int)set->m_Rect.z, (int)set->m_Rect.w); glDepthRangef(set->m_NearZ, set->m_FarZ); } break; case CG3DGlobalSet::SCISSOR: { CG3DScissorSet* set = (CG3DScissorSet*)m_Stacks[type].m_Value; if (set->m_Do) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST); glScissor((int)set->m_Rect.x, (int)set->m_Rect.y, (int)set->m_Rect.z, (int)set->m_Rect.w); } break; case CG3DGlobalSet::BLEND: { CG3DBlendSet* set = (CG3DBlendSet*)m_Stacks[type].m_Value; CG3DVector4 col = set->m_Colour.Get4f(); switch (set->m_Mode) { case CG3DBlendSet::OFF: glDisable(GL_BLEND); break; case CG3DBlendSet::COMBINED: glEnable(GL_BLEND); glBlendEquation(GetBlendFunc(set->m_Func)); glBlendFunc(GetBlendParam(set->m_Src), GetBlendParam(set->m_Dest)); glBlendColor(col.x, col.y, col.z, col.w); break; case CG3DBlendSet::SEPARATE: glEnable(GL_BLEND); glBlendEquationSeparate(GetBlendFunc(set->m_Func), GetBlendFunc(set->m_FuncAlpha)); glBlendFuncSeparate(GetBlendParam(set->m_Src), GetBlendParam(set->m_Dest), GetBlendParam(set->m_SrcAlpha), GetBlendParam(set->m_DestAlpha)); glBlendColor(col.x, col.y, col.z, col.w); break; } } break; case CG3DGlobalSet::SAMPLE_COVERAGE: { CG3DSampleCoverageSet* set = (CG3DSampleCoverageSet*)m_Stacks[type].m_Value; if (set->m_Coverage) glEnable(GL_SAMPLE_COVERAGE); else glDisable(GL_SAMPLE_COVERAGE); if (set->m_AlphaCoverage) glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE); else glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); glSampleCoverage(set->m_Value, set->m_Invert); } break; case CG3DGlobalSet::DITHER: { CG3DDitherSet* set = (CG3DDitherSet*)m_Stacks[type].m_Value; if (set->m_Dither) glEnable(GL_DITHER); else glDisable(GL_DITHER); } break; case CG3DGlobalSet::POLYGON_OFFSET: { CG3DPolygonOffsetSet* set = (CG3DPolygonOffsetSet*)m_Stacks[type].m_Value; if (set->m_PolygonOffset) glEnable(GL_POLYGON_OFFSET_FILL); else glDisable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(set->m_Factor, set->m_Units); } break; } }
bool LWFRendererFactory::Render(class LWF *lwf, Node *node, BlendEquationProtocol *be, int renderingIndex, bool visible, BlendFunc *baseBlendFunc) { m_renderingIndex = renderingIndex; node->setVisible(visible); if (!visible) return false; Node *target; switch (m_maskMode) { case Format::BLEND_MODE_ERASE: case Format::BLEND_MODE_MASK: case Format::BLEND_MODE_LAYER: { LWFMask *mask; if (m_lastMaskMode != m_maskMode) { ++m_maskNo; if (m_masks.size() > m_maskNo) { mask = m_masks[m_maskNo]; } else { mask = LWFMask::create(); m_masks.push_back(mask); } PlaceNode(m_node, mask); LWFMask *layer = nullptr; if (m_lastMaskMode == Format::BLEND_MODE_LAYER && (m_maskMode == Format::BLEND_MODE_ERASE || m_maskMode == Format::BLEND_MODE_MASK) && m_maskNo > 0) { layer = m_masks[m_maskNo - 1]; if (layer) layer->setLocalZOrder(INT_MAX); PlaceNode(mask, layer); } if (layer && mask) { switch (m_maskMode) { case Format::BLEND_MODE_ERASE: case Format::BLEND_MODE_MASK: switch (m_maskMode) { case Format::BLEND_MODE_ERASE: layer->setBlendFunc( {GL_ONE_MINUS_DST_ALPHA, GL_ZERO}); break; case Format::BLEND_MODE_MASK: layer->setBlendFunc( {GL_DST_ALPHA, GL_ZERO}); break; } BlendFunc blendFunc = {GL_ONE, GL_ZERO}; GetBlendFunc(blendFunc, m_blendMode); mask->setBlendFunc(blendFunc); break; } } m_lastMaskMode = m_maskMode; } else { mask = m_masks[m_maskNo]; } if (mask) mask->setLocalZOrder(m_renderingIndex + 1); target = mask; } break; default: target = m_node; break; } PlaceNode(target, node); node->setLocalZOrder(renderingIndex); BlendProtocol *p = dynamic_cast<BlendProtocol *>(node); if (p) { BlendFunc blendFunc = baseBlendFunc ? *baseBlendFunc : p->getBlendFunc(); GetBlendFunc(blendFunc, m_blendMode); p->setBlendFunc(blendFunc); } BlendEquationProtocol *ep = dynamic_cast<BlendEquationProtocol *>(node); if (ep) ep->setBlendEquation(m_blendMode); return true; }
void WalkEdges(const GEdge e1, const GEdge e2, const GPaint &paint) { const GBitmap &bm = GetInternalBitmap(); int h = bm.fHeight; int w = bm.fWidth; GASSERT(e1.p1.y() == e2.p1.y()); int startY = Clamp(static_cast<int>(e1.p1.y() + 0.5f), 0, h-1); GASSERT(e1.p2.y() == e2.p2.y()); int endY = Clamp(static_cast<int>(e1.p2.y() + 0.5f), 0, h-1); if(endY == startY) { return; } GASSERT(endY > startY); // Initialize to NAN float m1 = 0.0f/0.0f, b1; float m2 = 0.0f/0.0f, b2; bool vert1 = e1.ComputeLine(m1, b1); bool vert2 = e2.ComputeLine(m2, b2); if(m1 == 0 || m2 == 0) { return; } // Collinear? if(vert2 && vert1 && e1.p1.x() == e2.p1.x()) { return; } else if(m1 == m2 && b1 == b2) { return; } float stepX1 = vert1? 0 : 1/m1; float stepX2 = vert2? 0 : 1/m2; GPoint p1, p2; float sY = static_cast<float>(startY) + 0.5f; if(vert1) { p1.set(e1.p1.x(), sY); } else { p1.set((sY - b1) / m1, sY); } if(vert2) { p2.set(e2.p1.x(), sY); } else { p2.set((sY - b2) / m2, sY); } // Make sure that p1 is always less than p2 to avoid // doing a min/max in the inner loop if(p1.x() > p2.x()) { std::swap(p1, p2); std::swap(stepX1, stepX2); } GPixel color = ColorToPixel(paint.getColor()); BlendFunc blend = GetBlendFunc(eBlendOp_SrcOver); uint32_t nSteps = endY - startY; for(uint32_t i = 0; i < nSteps; i++) { // Since we haven't implemented clipping yet, take care // not to go beyond our bounds... const int x1 = Clamp<int>(p1.fX + 0.5f, 0, w-1); const int x2 = Clamp<int>(p2.fX + 0.5f, 0, w-1); GPixel *row = GetRow(bm, startY + i); for(int x = x1; x < x2; x++) { row[x] = blend(row[x], color); } p1.fX += stepX1; p2.fX += stepX2; } }
void fillIRect(const GIRect &rect, const GColor &c, EBlendOp op) { const GBitmap &bitmap = GetInternalBitmap(); uint32_t h = bitmap.fHeight; uint32_t w = bitmap.fWidth; GIRect bmRect; if(!(bmRect.setIntersection(rect, GIRect::MakeWH(w, h)))) return; h = bmRect.height(); w = bmRect.width(); // premultiply alpha ... GPixel clearValue = ColorToPixel(c); // Figure out blendfunc BlendFunc blend = GetBlendFunc(op); if(bitmap.fRowBytes == w * sizeof(GPixel)) { GPixel *p = bitmap.fPixels + bmRect.fTop*bitmap.fWidth + bmRect.fLeft; switch(op) { case eBlendOp_Src: memsetPixel(p, clearValue, w*h); break; default: { GPixel *end = bitmap.fPixels + ((bmRect.fBottom - 1) * w + bmRect.fRight); for(; p != end; p++) { *p = blend(*p, clearValue); } break; } } } else { for(uint32_t j = bmRect.fTop; j < bmRect.fBottom; j++) { GPixel *rowPixels = GetRow(bitmap, j) + bmRect.fLeft; switch(op) { case eBlendOp_Src: { memsetPixel(rowPixels, clearValue, w); break; } default: { GPixel oldP = rowPixels[0]; GPixel newP = blend(oldP, clearValue); rowPixels[0] = newP; for(uint32_t i = 1; i < w; i++) { if(oldP == rowPixels[i]) { rowPixels[i] = newP; } else { oldP = rowPixels[i]; newP = rowPixels[i] = blend(rowPixels[i], clearValue); } } break; } } // switch } // for } // else }