void CNumbersAttribute::setColor(video::SColor color) { reset(); if (IsFloat) { if (Count > 0) ValueF[0] = (f32) color.getRed() / 255.0f; if (Count > 1) ValueF[1] = (f32) color.getGreen() / 255.0f; if (Count > 2) ValueF[2] = (f32) color.getBlue() / 255.0f; if (Count > 3) ValueF[3] = (f32) color.getAlpha() / 255.0f; } else { if (Count > 0) ValueI[0] = color.getRed(); if (Count > 1) ValueI[1] = color.getGreen(); if (Count > 2) ValueI[2] = color.getBlue(); if (Count > 3) ValueI[3] = color.getAlpha(); } }
void GL32_draw2DRectangle(video::SColor color, const core::rect<s32>& position, const core::rect<s32>* clip) { if (!irr_driver->isGLSL()) { irr_driver->getVideoDriver()->draw2DRectangle(color, position, clip); return; } core::dimension2d<u32> frame_size = irr_driver->getVideoDriver()->getCurrentRenderTargetSize(); const int screen_w = frame_size.Width; const int screen_h = frame_size.Height; float center_pos_x = float(position.UpperLeftCorner.X + position.LowerRightCorner.X); center_pos_x /= screen_w; center_pos_x -= 1; float center_pos_y = float(position.UpperLeftCorner.Y + position.LowerRightCorner.Y); center_pos_y /= screen_h; center_pos_y = 1 - center_pos_y; float width = float(position.LowerRightCorner.X - position.UpperLeftCorner.X); width /= screen_w; float height = float(position.LowerRightCorner.Y - position.UpperLeftCorner.Y); height /= screen_h; if (color.getAlpha() < 255) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } else { glDisable(GL_BLEND); } if (clip) { if (!clip->isValid()) return; glEnable(GL_SCISSOR_TEST); const core::dimension2d<u32>& renderTargetSize = irr_driver->getVideoDriver()->getCurrentRenderTargetSize(); glScissor(clip->UpperLeftCorner.X, renderTargetSize.Height - clip->LowerRightCorner.Y, clip->getWidth(), clip->getHeight()); } glUseProgram(UIShader::ColoredRectShader::getInstance()->Program); glBindVertexArray(SharedObject::UIVAO); UIShader::ColoredRectShader::getInstance()->setUniforms(core::vector2df(center_pos_x, center_pos_y), core::vector2df(width, height), color); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); if (clip) glDisable(GL_SCISSOR_TEST); glUseProgram(0); glGetError(); }
//! Default constructor for color list CNumbersAttribute::CNumbersAttribute(const c8* name, video::SColor value) : ValueI(), ValueF(), Count(4), IsFloat(false) { Name = name; ValueI.pushBack(value.getRed()); ValueI.pushBack(value.getGreen()); ValueI.pushBack(value.getBlue()); ValueI.pushBack(value.getAlpha()); }
void push_ARGB8(lua_State *L, video::SColor color) { lua_newtable(L); lua_pushnumber(L, color.getAlpha()); lua_setfield(L, -2, "a"); lua_pushnumber(L, color.getRed()); lua_setfield(L, -2, "r"); lua_pushnumber(L, color.getGreen()); lua_setfield(L, -2, "g"); lua_pushnumber(L, color.getBlue()); lua_setfield(L, -2, "b"); }
// Fill the editfields with the value for the given color void CColorControl::setEditsFromColor(video::SColor col) { DirtyFlag = true; if ( EditAlpha ) EditAlpha->setText( core::stringw(col.getAlpha()).c_str() ); if ( EditRed ) EditRed->setText( core::stringw(col.getRed()).c_str() ); if ( EditGreen ) EditGreen->setText( core::stringw(col.getGreen()).c_str() ); if ( EditBlue ) EditBlue->setText( core::stringw(col.getBlue()).c_str() ); if ( ColorStatic ) ColorStatic->setBackgroundColor(col); }
void GL32_draw2DRectangle(video::SColor color, const core::rect<s32>& position, const core::rect<s32>* clip) { if (!irr_driver->isGLSL()) { irr_driver->getVideoDriver()->draw2DRectangle(color, position, clip); return; } core::dimension2d<u32> frame_size = irr_driver->getVideoDriver()->getCurrentRenderTargetSize(); const int screen_w = frame_size.Width; const int screen_h = frame_size.Height; float center_pos_x = position.UpperLeftCorner.X + position.LowerRightCorner.X; center_pos_x /= screen_w; center_pos_x -= 1; float center_pos_y = position.UpperLeftCorner.Y + position.LowerRightCorner.Y; center_pos_y /= screen_h; center_pos_y = 1 - center_pos_y; float width = position.LowerRightCorner.X - position.UpperLeftCorner.X; width /= screen_w; float height = position.LowerRightCorner.Y - position.UpperLeftCorner.Y; height /= screen_h; if (color.getAlpha() < 255) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } else { glDisable(GL_BLEND); } glUseProgram(UIShader::ColoredRectShader::Program); glBindVertexArray(UIShader::ColoredRectShader::vao); UIShader::ColoredRectShader::setUniforms(center_pos_x, center_pos_y, width, height, color); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); glUseProgram(0); }
// ---------------------------------------------------------------------------- void FontWithFace::render(const core::stringw& text, const core::rect<s32>& position, const video::SColor& color, bool hcenter, bool vcenter, const core::rect<s32>* clip, FontSettings* font_settings, FontCharCollector* char_collector) { const bool is_bold_face = dynamic_cast<BoldFace*>(this); const bool black_border = font_settings ? font_settings->useBlackBorder() : false; const bool rtl = font_settings ? font_settings->isRTL() : false; const float scale = font_settings ? font_settings->getScale() : 1.0f; const float shadow = font_settings ? font_settings->useShadow() : false; if (shadow) { assert(font_settings); // Avoid infinite recursion font_settings->setShadow(false); core::rect<s32> shadowpos = position; shadowpos.LowerRightCorner.X += 2; shadowpos.LowerRightCorner.Y += 2; render(text, shadowpos, font_settings->getShadowColor(), hcenter, vcenter, clip, font_settings); // Set back font_settings->setShadow(true); } core::position2d<float> offset(float(position.UpperLeftCorner.X), float(position.UpperLeftCorner.Y)); core::dimension2d<s32> text_dimension; if (rtl || hcenter || vcenter || clip) { text_dimension = getDimension(text.c_str(), font_settings); if (hcenter) offset.X += (position.getWidth() - text_dimension.Width) / 2; else if (rtl) offset.X += (position.getWidth() - text_dimension.Width); if (vcenter) offset.Y += (position.getHeight() - text_dimension.Height) / 2; if (clip) { core::rect<s32> clippedRect(core::position2d<s32> (s32(offset.X), s32(offset.Y)), text_dimension); clippedRect.clipAgainst(*clip); if (!clippedRect.isValid()) return; } } // Collect character locations const unsigned int text_size = text.size(); core::array<s32> indices(text_size); core::array<core::position2d<float>> offsets(text_size); std::vector<bool> fallback(text_size); // Test again if lazy load char is needed, // as some text isn't drawn with getDimension insertCharacters(text.c_str()); updateCharactersList(); for (u32 i = 0; i < text_size; i++) { wchar_t c = text[i]; if (c == L'\r' || // Windows breaks c == L'\n' ) // Unix breaks { if (c==L'\r' && text[i+1]==L'\n') c = text[++i]; offset.Y += m_font_max_height * scale; offset.X = position.UpperLeftCorner.X; if (hcenter) offset.X += (position.getWidth() - text_dimension.Width) >> 1; continue; } // if lineBreak bool use_fallback_font = false; const FontArea &area = getAreaFromCharacter(c, &use_fallback_font); fallback[i] = use_fallback_font; if (char_collector == NULL) { float glyph_offset_x = area.bearing_x * (fallback[i] ? m_fallback_font_scale : scale); float glyph_offset_y = area.offset_y * (fallback[i] ? m_fallback_font_scale : scale); offset.X += glyph_offset_x; offset.Y += glyph_offset_y; offsets.push_back(offset); offset.X -= glyph_offset_x; offset.Y -= glyph_offset_y; } else { // Prevent overwriting texture used by billboard text when // using lazy loading characters if (supportLazyLoadChar() && fallback[i]) { const int cur_texno = m_fallback_font->getSpriteBank() ->getSprites()[area.spriteno].Frames[0].textureNumber; if (cur_texno == int(m_fallback_font->getSpriteBank() ->getTextureCount() - 1)) { m_fallback_font->createNewGlyphPage(); } } else if (supportLazyLoadChar()) { const int cur_texno = m_spritebank ->getSprites()[area.spriteno].Frames[0].textureNumber; if (cur_texno == int(m_spritebank->getTextureCount() - 1)) { createNewGlyphPage(); } } // Billboard text specific, use offset_y_bt instead float glyph_offset_x = area.bearing_x * (fallback[i] ? m_fallback_font_scale : scale); float glyph_offset_y = area.offset_y_bt * (fallback[i] ? m_fallback_font_scale : scale); offset.X += glyph_offset_x; offset.Y += glyph_offset_y; offsets.push_back(offset); offset.X -= glyph_offset_x; offset.Y -= glyph_offset_y; } indices.push_back(area.spriteno); offset.X += getCharWidth(area, fallback[i], scale); } // for i < text_size // Do the actual rendering const int indice_amount = indices.size(); core::array<gui::SGUISprite>& sprites = m_spritebank->getSprites(); core::array<core::rect<s32>>& positions = m_spritebank->getPositions(); core::array<gui::SGUISprite>* fallback_sprites; core::array<core::rect<s32>>* fallback_positions; if (m_fallback_font != NULL) { fallback_sprites = &m_fallback_font->m_spritebank->getSprites(); fallback_positions = &m_fallback_font->m_spritebank->getPositions(); } else { fallback_sprites = NULL; fallback_positions = NULL; } const int sprite_amount = sprites.size(); if ((black_border || is_bold_face) && char_collector == NULL) { // Draw black border first, to make it behind the real character // which make script language display better video::SColor black(color.getAlpha(),0,0,0); for (int n = 0; n < indice_amount; n++) { const int sprite_id = indices[n]; if (!fallback[n] && (sprite_id < 0 || sprite_id >= sprite_amount)) continue; if (indices[n] == -1) continue; const int tex_id = (fallback[n] ? (*fallback_sprites)[sprite_id].Frames[0].textureNumber : sprites[sprite_id].Frames[0].textureNumber); core::rect<s32> source = (fallback[n] ? (*fallback_positions) [(*fallback_sprites)[sprite_id].Frames[0].rectNumber] : positions[sprites[sprite_id].Frames[0].rectNumber]); core::dimension2d<float> size(0.0f, 0.0f); float cur_scale = (fallback[n] ? m_fallback_font_scale : scale); size.Width = source.getSize().Width * cur_scale; size.Height = source.getSize().Height * cur_scale; core::rect<float> dest(offsets[n], size); video::ITexture* texture = (fallback[n] ? m_fallback_font->m_spritebank->getTexture(tex_id) : m_spritebank->getTexture(tex_id)); for (int x_delta = -2; x_delta <= 2; x_delta++) { for (int y_delta = -2; y_delta <= 2; y_delta++) { if (x_delta == 0 || y_delta == 0) continue; draw2DImage(texture, dest + core::position2d<float> (float(x_delta), float(y_delta)), source, clip, black, true); } } } } for (int n = 0; n < indice_amount; n++) { const int sprite_id = indices[n]; if (!fallback[n] && (sprite_id < 0 || sprite_id >= sprite_amount)) continue; if (indices[n] == -1) continue; const int tex_id = (fallback[n] ? (*fallback_sprites)[sprite_id].Frames[0].textureNumber : sprites[sprite_id].Frames[0].textureNumber); core::rect<s32> source = (fallback[n] ? (*fallback_positions)[(*fallback_sprites)[sprite_id].Frames[0] .rectNumber] : positions[sprites[sprite_id].Frames[0].rectNumber]); core::dimension2d<float> size(0.0f, 0.0f); float cur_scale = (fallback[n] ? m_fallback_font_scale : scale); size.Width = source.getSize().Width * cur_scale; size.Height = source.getSize().Height * cur_scale; core::rect<float> dest(offsets[n], size); video::ITexture* texture = (fallback[n] ? m_fallback_font->m_spritebank->getTexture(tex_id) : m_spritebank->getTexture(tex_id)); if (fallback[n] || is_bold_face) { video::SColor top = GUIEngine::getSkin()->getColor("font::top"); video::SColor bottom = GUIEngine::getSkin() ->getColor("font::bottom"); top.setAlpha(color.getAlpha()); bottom.setAlpha(color.getAlpha()); video::SColor title_colors[] = {top, bottom, top, bottom}; if (char_collector != NULL) { char_collector->collectChar(texture, dest, source, title_colors); } else { draw2DImage(texture, dest, source, clip, title_colors, true); } } else { if (char_collector != NULL) { video::SColor colors[] = {color, color, color, color}; char_collector->collectChar(texture, dest, source, colors); } else { draw2DImage(texture, dest, source, clip, color, true); } } } } // render
bool drawLine( video::IImage* dst, s32 x0, s32 y0, s32 x1, s32 y1, const video::SColor& color_a, const video::SColor& color_b, bool blend ) { if (!dst) return false; const core::dimension2du img_size = dst->getDimension(); if ((img_size.Width == 0) || (img_size.Height == 0)) return false; const s32 dx = core::abs_<s32>( x1 - x0 ); const s32 dy = core::abs_<s32>( y1 - y0 ); if ((dx==0) && (dy==0)) return false; s32 sx = 1; // sign s32 sy = 1; // sign if (x0 > x1) sx = -1; if (y0 > y1) sy = -1; s32 err = dx-dy; s32 e2 = 0; s32 x = x0; s32 y = y0; s32 numpixels = 0; // count pixels while (1) { numpixels++; if ((x==x1) && (y==y1)) break; e2 = err << 1; if (e2 > -dy) { err -= dy; x += sx; } if (e2 < dx) { err += dx; y += sy; } } // reset vars; err = dx-dy; e2 = 0; x = x0; y = y0; // values for linear color interpolation const f32 A1=(f32)color_a.getAlpha(); const f32 R1=(f32)color_a.getRed(); const f32 G1=(f32)color_a.getGreen(); const f32 B1=(f32)color_a.getBlue(); const f32 dA=(f32)color_b.getAlpha()-A1; const f32 dR=(f32)color_b.getRed()-R1; const f32 dG=(f32)color_b.getGreen()-G1; const f32 dB=(f32)color_b.getBlue()-B1; // actual drawing f32 f=0.f; s32 k=0; u32 cR=0, cG=0, cB=0, cA=0; while (1) { f = (f32)k/(f32)numpixels; k++; cA=A1; cR=R1; cG=G1; cB=B1; // maybe faster under the assumption that colors have most likely same alpha value if (dA>0) cA = (u32)core::clamp( core::round32(A1+dA*f), 0, 255); if (dR>0) cR = (u32)core::clamp( core::round32(R1+dR*f), 0, 255); if (dG>0) cG = (u32)core::clamp( core::round32(G1+dG*f), 0, 255); if (dB>0) cB = (u32)core::clamp( core::round32(B1+dB*f), 0, 255); drawPixel( dst, x, y, video::SColor( cA, cR, cG, cB), blend ); if (x == x1 && y == y1) break; e2 = err << 1; if (e2 > -dy) { err -= dy; x += sx; } if (e2 < dx) { err += dx; y += sy; } } return true; }
//! draws some text and clips it to the specified rectangle if wanted void ScalableFont::doDraw(const core::stringw& text, const core::rect<s32>& position, video::SColor color, bool hcenter, bool vcenter, const core::rect<s32>* clip, FontCharCollector* charCollector) { if (!Driver) return; if (m_shadow) { m_shadow = false; // avoid infinite recursion core::rect<s32> shadowpos = position; shadowpos.LowerRightCorner.X += 2; shadowpos.LowerRightCorner.Y += 2; draw(text, shadowpos, m_shadow_color, hcenter, vcenter, clip); m_shadow = true; // set back } core::position2d<s32> offset = position.UpperLeftCorner; core::dimension2d<s32> text_dimension; if (m_rtl || hcenter || vcenter || clip) { text_dimension = getDimension(text.c_str()); if (hcenter) offset.X += (position.getWidth() - text_dimension.Width) / 2; else if (m_rtl) offset.X += (position.getWidth() - text_dimension.Width); if (vcenter) offset.Y += (position.getHeight() - text_dimension.Height) / 2; if (clip) { core::rect<s32> clippedRect(offset, text_dimension); clippedRect.clipAgainst(*clip); if (!clippedRect.isValid()) return; } } // ---- collect character locations const unsigned int text_size = text.size(); core::array<s32> indices(text_size); core::array<core::position2di> offsets(text_size); std::vector<bool> fallback(text_size); for (u32 i = 0; i<text_size; i++) { wchar_t c = text[i]; if (c == L'\r' || // Windows breaks c == L'\n' ) // Unix breaks { if(c==L'\r' && text[i+1]==L'\n') c = text[++i]; offset.Y += (int)(MaxHeight*m_scale); offset.X = position.UpperLeftCorner.X; if (hcenter) offset.X += (position.getWidth() - text_dimension.Width) >> 1; continue; } // if lineBreak bool use_fallback_font = false; const SFontArea &area = getAreaFromCharacter(c, &use_fallback_font); fallback[i] = use_fallback_font; offset.X += area.underhang; offsets.push_back(offset); // Invisible character. add something to the array anyway so that // indices from the various arrays remain in sync indices.push_back( Invisible.findFirst(c) < 0 ? area.spriteno : -1 ); offset.X += getCharWidth(area, fallback[i]); } // for i<text_size // ---- do the actual rendering const int indiceAmount = indices.size(); core::array< SGUISprite >& sprites = SpriteBank->getSprites(); core::array< core::rect<s32> >& positions = SpriteBank->getPositions(); core::array< SGUISprite >* fallback_sprites; core::array< core::rect<s32> >* fallback_positions; if(m_fallback_font!=NULL) { fallback_sprites = &m_fallback_font->SpriteBank->getSprites(); fallback_positions = &m_fallback_font->SpriteBank->getPositions(); } else { fallback_sprites = NULL; fallback_positions = NULL; } const int spriteAmount = sprites.size(); for (int n=0; n<indiceAmount; n++) { const int spriteID = indices[n]; if (!fallback[n] && (spriteID < 0 || spriteID >= spriteAmount)) continue; if (indices[n] == -1) continue; //assert(sprites[spriteID].Frames.size() > 0); const int texID = (fallback[n] ? (*fallback_sprites)[spriteID].Frames[0].textureNumber : sprites[spriteID].Frames[0].textureNumber); core::rect<s32> source = (fallback[n] ? (*fallback_positions)[(*fallback_sprites)[spriteID].Frames[0].rectNumber] : positions[sprites[spriteID].Frames[0].rectNumber]); const TextureInfo& info = (fallback[n] ? (*(m_fallback_font->m_texture_files.find(texID))).second : (*(m_texture_files.find(texID))).second ); float char_scale = info.m_scale; core::dimension2d<s32> size = source.getSize(); float scale = (fallback[n] ? m_scale*m_fallback_font_scale : m_scale); size.Width = (int)(size.Width * scale * char_scale); size.Height = (int)(size.Height * scale * char_scale); // align vertically if character is smaller int y_shift = (size.Height < MaxHeight*m_scale ? (int)((MaxHeight*m_scale - size.Height)/2.0f) : 0); core::rect<s32> dest(offsets[n] + core::position2di(0, y_shift), size); video::ITexture* texture = (fallback[n] ? m_fallback_font->SpriteBank->getTexture(texID) : SpriteBank->getTexture(texID) ); /* if (fallback[n]) { Log::info("ScalableFont", "Using fallback font %s; source area is %d, %d; size %d, %d; dest = %d, %d", core::stringc(texture->getName()).c_str(), source.UpperLeftCorner.X, source.UpperLeftCorner.Y, source.getWidth(), source.getHeight(), offsets[n].X, offsets[n].Y); } */ if (texture == NULL) { // perform lazy loading if (fallback[n]) { m_fallback_font->lazyLoadTexture(texID); texture = m_fallback_font->SpriteBank->getTexture(texID); } else { lazyLoadTexture(texID); texture = SpriteBank->getTexture(texID); } if (texture == NULL) { Log::warn("ScalableFont", "Character not found in current font"); continue; // no such character } } if (m_black_border && charCollector == NULL) { // draw black border video::SColor black(color.getAlpha(),0,0,0); for (int x_delta=-2; x_delta<=2; x_delta++) { for (int y_delta=-2; y_delta<=2; y_delta++) { if (x_delta == 0 || y_delta == 0) continue; draw2DImage(texture, dest + core::position2d<s32>(x_delta, y_delta), source, clip, black, true); } } } if (fallback[n]) { // TODO: don't hardcode colors? video::SColor orange(color.getAlpha(), 255, 100, 0); video::SColor yellow(color.getAlpha(), 255, 220, 15); video::SColor title_colors[] = {orange, yellow, orange, yellow}; if (charCollector != NULL) { charCollector->collectChar(texture, dest, source, title_colors); } else { draw2DImage(texture, dest, source, clip, title_colors, true); } } else { if (charCollector != NULL) { video::SColor colors[] = { color, color, color, color }; charCollector->collectChar(texture, dest, source, colors); } else { draw2DImage(texture, dest, source, clip, color, true); } #ifdef FONT_DEBUG video::IVideoDriver* driver = GUIEngine::getDriver(); driver->draw2DLine(core::position2d<s32>(dest.UpperLeftCorner.X, dest.UpperLeftCorner.Y), core::position2d<s32>(dest.UpperLeftCorner.X, dest.LowerRightCorner.Y), video::SColor(255, 255,0,0)); driver->draw2DLine(core::position2d<s32>(dest.LowerRightCorner.X, dest.LowerRightCorner.Y), core::position2d<s32>(dest.LowerRightCorner.X, dest.UpperLeftCorner.Y), video::SColor(255, 255,0,0)); driver->draw2DLine(core::position2d<s32>(dest.LowerRightCorner.X, dest.LowerRightCorner.Y), core::position2d<s32>(dest.UpperLeftCorner.X, dest.LowerRightCorner.Y), video::SColor(255, 255,0,0)); driver->draw2DLine(core::position2d<s32>(dest.UpperLeftCorner.X, dest.UpperLeftCorner.Y), core::position2d<s32>(dest.LowerRightCorner.X, dest.UpperLeftCorner.Y), video::SColor(255, 255,0,0)); #endif } } }
void ScalableFont::doDraw(const core::stringw& text, const core::rect<s32>& position, video::SColor color, bool hcenter, bool vcenter, const core::rect<s32>* clip, FontCharCollector* charCollector) { if (!m_video_driver) return; GUIEngine::GlyphPageCreator* gp_creator = GUIEngine::getGlyphPageCreator(); if (m_shadow) { m_shadow = false; // avoid infinite recursion core::rect<s32> shadowpos = position; shadowpos.LowerRightCorner.X += 2; shadowpos.LowerRightCorner.Y += 2; draw(text, shadowpos, m_shadow_color, hcenter, vcenter, clip); m_shadow = true; // set back } core::position2d<s32> offset = position.UpperLeftCorner; core::dimension2d<s32> text_dimension; if (m_rtl || hcenter || vcenter || clip) { text_dimension = getDimension(text.c_str()); if (hcenter) offset.X += (position.getWidth() - text_dimension.Width) / 2; else if (m_rtl) offset.X += (position.getWidth() - text_dimension.Width); if (vcenter) offset.Y += (position.getHeight() - text_dimension.Height) / 2; if (clip) { core::rect<s32> clippedRect(offset, text_dimension); clippedRect.clipAgainst(*clip); if (!clippedRect.isValid()) return; } } // ---- collect character locations const unsigned int text_size = text.size(); core::array<s32> indices(text_size); core::array<core::position2di> offsets(text_size); std::vector<bool> fallback(text_size); if (m_type == T_NORMAL || T_BOLD) //lazy load char, have to do this again { //because some text isn't drawn with getDimension for (u32 i = 0; i < text_size; i++) { wchar_t c = text[i]; if (c == L'\r' || c == L'\n' || c == L' ' || c < 32) continue; if (!GUIEngine::getFont()->hasThisChar(c)) gp_creator->insertChar(c); if (charCollector != NULL && m_type == T_NORMAL && m_spritebank->getSprites() [GUIEngine::getFont()->getSpriteNoFromChar(&c)].Frames[0].textureNumber == m_spritebank->getTextureCount() - 1) //Prevent overwriting texture used by billboard text { Log::debug("ScalableFont::doDraw", "Character used by billboard text is in the last " "glyph page of normal font. Create a new glyph " "page for new characters inserted later to prevent " "it from being removed."); GUIEngine::getFont()->forceNewPage(); } } if (gp_creator->getNewChar().size() > 0 && !m_is_hollow_copy && m_scale == 1) { Log::debug("ScalableFont::doDraw", "New character(s) %s discoverd, perform lazy loading", StringUtils::wideToUtf8(gp_creator->getNewChar()).c_str()); if (!GUIEngine::getFont()->lazyLoadChar()) Log::error("ScalableFont::lazyLoadChar", "Can't insert new char into glyph pages."); } } for (u32 i = 0; i < text_size; i++) { wchar_t c = text[i]; if (c == L'\r' || // Windows breaks c == L'\n' ) // Unix breaks { if(c==L'\r' && text[i+1]==L'\n') c = text[++i]; offset.Y += (int)(m_max_height*m_scale); offset.X = position.UpperLeftCorner.X; if (hcenter) offset.X += (position.getWidth() - text_dimension.Width) >> 1; continue; } // if lineBreak bool use_fallback_font = false; const SFontArea &area = getAreaFromCharacter(c, &use_fallback_font); fallback[i] = use_fallback_font; if (charCollector == NULL) { //Try to use ceil to make offset calculate correctly when m_scale is smaller than 1 s32 glyph_offset_x = (s32)((float) area.bearingx* (fallback[i] ? m_scale*m_fallback_font_scale : m_scale)); s32 glyph_offset_y = (s32)ceil((float) area.offsety* (fallback[i] ? m_scale*m_fallback_font_scale : m_scale)); offset.X += glyph_offset_x; offset.Y += s32(glyph_offset_y + floor(m_type == T_DIGIT ? 20*m_scale : 0)); //Additional offset for digit text offsets.push_back(offset); offset.X -= glyph_offset_x; offset.Y -= s32(glyph_offset_y + floor(m_type == T_DIGIT ? 20*m_scale : 0)); } else //Billboard text specific { s32 glyph_offset_x = (s32)ceil((float) area.bearingx* (fallback[i] ? m_scale*m_fallback_font_scale : m_scale)); s32 glyph_offset_y = (s32)ceil((float) area.offsety_bt* (fallback[i] ? m_scale*m_fallback_font_scale : m_scale)); offset.X += glyph_offset_x; offset.Y += s32(glyph_offset_y + floor(m_type == T_DIGIT ? 20*m_scale : 0)); //Additional offset for digit text offsets.push_back(offset); offset.X -= glyph_offset_x; offset.Y -= s32(glyph_offset_y + floor(m_type == T_DIGIT ? 20*m_scale : 0)); } // Invisible character. add something to the array anyway so that // indices from the various arrays remain in sync indices.push_back(m_invisible.findFirst(c) < 0 ? area.spriteno : -1); offset.X += getCharWidth(area, fallback[i]); } // for i<text_size // ---- do the actual rendering const int indiceAmount = indices.size(); core::array< SGUISprite >& sprites = m_spritebank->getSprites(); core::array< core::rect<s32> >& positions = m_spritebank->getPositions(); core::array< SGUISprite >* fallback_sprites; core::array< core::rect<s32> >* fallback_positions; if (m_fallback_font != NULL) { fallback_sprites = &m_fallback_font->m_spritebank->getSprites(); fallback_positions = &m_fallback_font->m_spritebank->getPositions(); } else { fallback_sprites = NULL; fallback_positions = NULL; } const int spriteAmount = sprites.size(); if (m_black_border && charCollector == NULL) { //Draw black border first, to make it behind the real character //which make script language display better video::SColor black(color.getAlpha(),0,0,0); for (int n = 0; n < indiceAmount; n++) { const int spriteID = indices[n]; if (!fallback[n] && (spriteID < 0 || spriteID >= spriteAmount)) continue; if (indices[n] == -1) continue; const int texID = (fallback[n] ? (*fallback_sprites)[spriteID].Frames[0].textureNumber : sprites[spriteID].Frames[0].textureNumber); core::rect<s32> source = (fallback[n] ? (*fallback_positions)[(*fallback_sprites)[spriteID].Frames[0].rectNumber] : positions[sprites[spriteID].Frames[0].rectNumber]); core::dimension2d<s32> size = source.getSize(); float scale = (fallback[n] ? m_scale*m_fallback_font_scale : m_scale); size.Width = (int)(size.Width * scale); size.Height = (int)(size.Height * scale); core::rect<s32> dest(offsets[n], size); video::ITexture* texture = (fallback[n] ? m_fallback_font->m_spritebank->getTexture(texID) : m_spritebank->getTexture(texID) ); for (int x_delta = -2; x_delta <= 2; x_delta++) { for (int y_delta = -2; y_delta <= 2; y_delta++) { if (x_delta == 0 || y_delta == 0) continue; draw2DImage(texture, dest + core::position2d<s32>(x_delta, y_delta), source, clip, black, true); } } } } for (int n = 0; n < indiceAmount; n++) { const int spriteID = indices[n]; if (!fallback[n] && (spriteID < 0 || spriteID >= spriteAmount)) continue; if (indices[n] == -1) continue; //assert(sprites[spriteID].Frames.size() > 0); const int texID = (fallback[n] ? (*fallback_sprites)[spriteID].Frames[0].textureNumber : sprites[spriteID].Frames[0].textureNumber); core::rect<s32> source = (fallback[n] ? (*fallback_positions)[(*fallback_sprites)[spriteID].Frames[0].rectNumber] : positions[sprites[spriteID].Frames[0].rectNumber]); core::dimension2d<s32> size = source.getSize(); float scale = (fallback[n] ? m_scale*m_fallback_font_scale : m_scale); size.Width = (int)(size.Width * scale); size.Height = (int)(size.Height * scale); core::rect<s32> dest(offsets[n], size); video::ITexture* texture = (fallback[n] ? m_fallback_font->m_spritebank->getTexture(texID) : m_spritebank->getTexture(texID) ); /* if (fallback[n]) { Log::info("ScalableFont", "Using fallback font %s; source area is %d, %d; size %d, %d; dest = %d, %d", core::stringc(texture->getName()).c_str(), source.UpperLeftCorner.X, source.UpperLeftCorner.Y, source.getWidth(), source.getHeight(), offsets[n].X, offsets[n].Y); } */ #ifdef FONT_DEBUG GL32_draw2DRectangle(video::SColor(255, 255,0,0), dest,clip); #endif if (fallback[n] || m_type == T_BOLD) { video::SColor top = GUIEngine::getSkin()->getColor("font::top"); video::SColor bottom = GUIEngine::getSkin()->getColor("font::bottom"); top.setAlpha(color.getAlpha()); bottom.setAlpha(color.getAlpha()); video::SColor title_colors[] = {top, bottom, top, bottom}; if (charCollector != NULL) { charCollector->collectChar(texture, dest, source, title_colors); } else { draw2DImage(texture, dest, source, clip, title_colors, true); } } else { if (charCollector != NULL) { video::SColor colors[] = { color, color, color, color }; charCollector->collectChar(texture, dest, source, colors); } else { draw2DImage(texture, dest, source, clip, color, true); } } } }
void GL32_draw2DRectangle(video::SColor color, const core::rect<s32>& position, const core::rect<s32>* clip) { if (!irr_driver->isGLSL()) { irr_driver->getVideoDriver()->draw2DRectangle(color, position, clip); return; } core::dimension2d<u32> frame_size = irr_driver->getVideoDriver()->getCurrentRenderTargetSize(); const int screen_w = frame_size.Width; const int screen_h = frame_size.Height; float center_pos_x = position.UpperLeftCorner.X + position.LowerRightCorner.X; center_pos_x /= screen_w; center_pos_x -= 1; float center_pos_y = position.UpperLeftCorner.Y + position.LowerRightCorner.Y; center_pos_y /= screen_h; center_pos_y = 1 - center_pos_y; float width = position.LowerRightCorner.X - position.UpperLeftCorner.X; width /= screen_w; float height = position.LowerRightCorner.Y - position.UpperLeftCorner.Y; height /= screen_h; if (color.getAlpha() < 255) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } else { glDisable(GL_BLEND); } if (clip) { if (!clip->isValid()) return; glEnable(GL_SCISSOR_TEST); const core::dimension2d<u32>& renderTargetSize = irr_driver->getVideoDriver()->getCurrentRenderTargetSize(); glScissor(clip->UpperLeftCorner.X, renderTargetSize.Height - clip->LowerRightCorner.Y, clip->getWidth(), clip->getHeight()); } glUseProgram(UIShader::ColoredRectShader::Program); glBindVertexArray(UIShader::ColoredRectShader::vao); UIShader::ColoredRectShader::setUniforms(center_pos_x, center_pos_y, width, height, color); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); if (clip) glDisable(GL_SCISSOR_TEST); glUseProgram(0); GLenum glErr = glGetError(); if (glErr != GL_NO_ERROR) { Log::warn("IrrDriver", "GLWrap : OpenGL error %i\n", glErr); } }