void EC_OgreMovableTextOverlay::SetText(const std::string& text) { if (!node_) return; text_ = text; boost::trim(text_); // Replace few common scandic letters with a and o. ReplaceCharInplace(text_, 'Ä', 'A'); ReplaceCharInplace(text_, 'ä', 'a'); ReplaceCharInplace(text_, 'Ö', 'O'); ReplaceCharInplace(text_, 'ö', 'o'); ReplaceCharInplace(text_, 'Å', 'A'); ReplaceCharInplace(text_, 'å', 'a'); try { text_element_->setCaption(text_); } catch(...) { text_ = ""; } textDim_ = GetTextDimensions(text_); container_->setDimensions(textDim_.x, textDim_.y); }
NS_IMETHODIMP nsThebesRenderingContext::GetTextDimensions(const char* aString, PRInt32 aLength, PRInt32 aAvailWidth, PRInt32* aBreaks, PRInt32 aNumBreaks, nsTextDimensions& aDimensions, PRInt32& aNumCharsFit, nsTextDimensions& aLastWordDimensions, PRInt32* aFontID) { PRUint32 maxChunkLength = GetMaxChunkLength(this); if (aLength <= PRInt32(maxChunkLength)) return GetTextDimensionsInternal(aString, aLength, aAvailWidth, aBreaks, aNumBreaks, aDimensions, aNumCharsFit, aLastWordDimensions, aFontID); if (aFontID) { *aFontID = 0; } // Do a naive implementation based on 3-arg GetTextDimensions PRInt32 x = 0; PRInt32 wordCount; for (wordCount = 0; wordCount < aNumBreaks; ++wordCount) { PRInt32 lastBreak = wordCount > 0 ? aBreaks[wordCount - 1] : 0; nsTextDimensions dimensions; NS_ASSERTION(aBreaks[wordCount] > lastBreak, "Breaks must be monotonically increasing"); NS_ASSERTION(aBreaks[wordCount] <= aLength, "Breaks can't exceed string length"); // Call safe method nsresult rv = GetTextDimensions(aString + lastBreak, aBreaks[wordCount] - lastBreak, dimensions); if (NS_FAILED(rv)) return rv; x += dimensions.width; // The first word always "fits" if (x > aAvailWidth && wordCount > 0) break; // aDimensions ascent/descent should exclude the last word (unless there // is only one word) so we let it run one word behind if (wordCount == 0) { aDimensions = dimensions; } else { aDimensions.Combine(aLastWordDimensions); } aNumCharsFit = aBreaks[wordCount]; aLastWordDimensions = dimensions; } // aDimensions width should include all the text aDimensions.width = x; return NS_OK; }
DGLE_RESULT DGLE_API CBitmapFont::Draw3D(const char *pcTxt) { size_t length = strlen(pcTxt); if (length == 0) return S_FALSE; DGLE_RESULT hr; uint strwidth, strheight; if (FAILED(hr = GetTextDimensions(pcTxt, strwidth, strheight))) return hr; _pTex->Bind(); uint t_w, t_h; _pTex->GetDimensions(t_w, t_h); float x = -(float)strwidth * 0.5f, y = -(float)strheight * 0.5f; const uint floats_per_char = 12 /* vertices */ + 12 /* texture coords */, line_floats_cnt = length * floats_per_char; if (_uiBufferSize < line_floats_cnt) { _uiBufferSize = line_floats_cnt; delete[] _pBuffer; _pBuffer = new float[_uiBufferSize]; } const uint tex_coords_offset = line_floats_cnt / 2; for (size_t i = 0; i < length; ++i) { const uchar ch = static_cast<const uchar>(pcTxt[i]) - 32; const int &curb_x = _astChars[ch].x, &curb_y = _astChars[ch].y, &curb_w = _astChars[ch].w, &curb_h = _astChars[ch].h; const uint char_step = i * (floats_per_char / 2); _pBuffer[char_step] = x + curb_w * _fScale; _pBuffer[char_step + 1] = y; _pBuffer[char_step + 2] = x + curb_w * _fScale; _pBuffer[char_step + 3] = y + curb_h * _fScale; _pBuffer[char_step + 4] = x; _pBuffer[char_step + 5] = y; _pBuffer[char_step + 6] = x; _pBuffer[char_step + 7] = y; _pBuffer[char_step + 8] = x + curb_w * _fScale; _pBuffer[char_step + 9] = _pBuffer[char_step + 3]; _pBuffer[char_step + 10] = x; _pBuffer[char_step + 11] = _pBuffer[char_step + 3]; _pBuffer[tex_coords_offset + char_step] = (curb_x + curb_w) / (float)t_w; _pBuffer[tex_coords_offset + char_step + 1] = (curb_y + curb_h) / (float)t_h; _pBuffer[tex_coords_offset + char_step + 2] = _pBuffer[tex_coords_offset + char_step]; _pBuffer[tex_coords_offset + char_step + 3] = curb_y / (float)t_h; _pBuffer[tex_coords_offset + char_step + 4] = curb_x / (float)t_w; _pBuffer[tex_coords_offset + char_step + 5] = _pBuffer[tex_coords_offset + char_step + 1]; _pBuffer[tex_coords_offset + char_step + 6] = _pBuffer[tex_coords_offset + char_step + 4]; _pBuffer[tex_coords_offset + char_step + 7] = _pBuffer[tex_coords_offset + char_step + 1]; _pBuffer[tex_coords_offset + char_step + 8] = _pBuffer[tex_coords_offset + char_step + 2]; _pBuffer[tex_coords_offset + char_step + 9] = _pBuffer[tex_coords_offset + char_step + 3]; _pBuffer[tex_coords_offset + char_step + 10] = _pBuffer[tex_coords_offset + char_step + 4]; _pBuffer[tex_coords_offset + char_step + 11] = _pBuffer[tex_coords_offset + char_step + 3]; x += curb_w * _fScale; } _pRender3D->Draw(TDrawDataDesc((uint8 *)_pBuffer, -1, tex_coords_offset * sizeof(float), true), CRDM_TRIANGLES, (uint)length * 6); return S_OK; }
DGLE_RESULT DGLE_API CBitmapFont::Draw2D(float fX, float fY, const char *pcTxt, const TColor4 &stColor, float fAngle, bool bVerticesColors) { uint length = strlen(pcTxt); if (length == 0) return S_FALSE; bool b_need_update; _pRender2D->NeedToUpdateBatchData(b_need_update); if (!b_need_update) { _pRender2D->Draw(_pTex, TDrawDataDesc(), CRDM_TRIANGLES, length * 6, TRectF(), (E_EFFECT2D_FLAGS)(EF_BLEND | (bVerticesColors ? EF_DEFAULT : EF_COLOR_MIX))); return S_OK; } uint width, height; GetTextDimensions(pcTxt, width, height); float quad[] = {fX, fY, fX + (float)width, fY, fX + (float)width, fY + (float)height, fX, fY + (float)height}; TMatrix4 transform; if (fAngle != 0.f) { TMatrix4 rot = MatrixIdentity(); const float s = sinf(-fAngle * (float)M_PI/180.f), c = cosf(-fAngle * (float)M_PI/180.f); rot._2D[0][0] = c; rot._2D[0][1] = -s; rot._2D[1][0] = s; rot._2D[1][1] = c; transform = MatrixTranslate(TVector3(-(fX + width / 2.f), -(fY + height / 2.f), 0.f)) * rot * MatrixTranslate(TVector3(fX + width / 2.f, fY + height / 2.f, 0.f)); float x = quad[0], y = quad[1]; quad[0] = transform._2D[0][0] * x + transform._2D[1][0] * y + transform._2D[3][0]; quad[1] = transform._2D[0][1] * x + transform._2D[1][1] * y + transform._2D[3][1]; x = quad[2]; y = quad[3]; quad[2] = transform._2D[0][0] * x + transform._2D[1][0] * y + transform._2D[3][0]; quad[3] = transform._2D[0][1] * x + transform._2D[1][1] * y + transform._2D[3][1]; x = quad[4]; y = quad[5]; quad[4] = transform._2D[0][0] * x + transform._2D[1][0] * y + transform._2D[3][0]; quad[5] = transform._2D[0][1] * x + transform._2D[1][1] * y + transform._2D[3][1]; x = quad[6]; y = quad[7]; quad[6] = transform._2D[0][0] * x + transform._2D[1][0] * y + transform._2D[3][0]; quad[7] = transform._2D[0][1] * x + transform._2D[1][1] * y + transform._2D[3][1]; } if (!_pRender2D->BBoxInScreen(quad, fAngle != 0.f)) return S_OK; float xoffset = 0.f; uint t_w, t_h; _pTex->GetDimensions(t_w, t_h); TColor4 prev_color, verts_colors[4]; _pRender2D->GetColorMix(prev_color); _pRender2D->SetColorMix(stColor); if (bVerticesColors) _pRender2D->GetVerticesColors(verts_colors[0], verts_colors[1], verts_colors[2], verts_colors[3]); uint size = length * 12 * 2; if (bVerticesColors) size = length * 24 * 2; if (_uiBufferSize < size) { _uiBufferSize = size; delete[] _pBuffer; _pBuffer = new float[_uiBufferSize]; } for (uint i = 0; i < length; ++i) { const uchar ch = static_cast<const uchar>(pcTxt[i]) - 32; const int &curb_x = _astChars[ch].x, &curb_y = _astChars[ch].y, &curb_w = _astChars[ch].w, &curb_h = _astChars[ch].h; const uint idx = i * 24; _pBuffer[idx] = fX + xoffset; _pBuffer[idx + 1] = fY; _pBuffer[idx + 2] = (float)curb_x / (float)t_w; _pBuffer[idx + 3] = (float)curb_y / (float)t_h; _pBuffer[idx + 4] = fX + xoffset + (float)curb_w * _fScale; _pBuffer[idx + 5] = fY; _pBuffer[idx + 6] = (float)(curb_x + curb_w) / (float)t_w; _pBuffer[idx + 7] = (float)curb_y / (float)t_h; _pBuffer[idx + 8] = fX + xoffset + (float)curb_w * _fScale; _pBuffer[idx + 9] = fY + (float)curb_h * _fScale; _pBuffer[idx + 10] = (float)(curb_x + curb_w) / (float)t_w; _pBuffer[idx + 11] = (float)(curb_y + curb_h) / (float)t_h; _pBuffer[idx + 12] = _pBuffer[idx]; _pBuffer[idx + 13] = _pBuffer[idx + 1]; _pBuffer[idx + 14] = _pBuffer[idx + 2]; _pBuffer[idx + 15] = _pBuffer[idx + 3]; _pBuffer[idx + 16] = _pBuffer[idx + 8]; _pBuffer[idx + 17] = _pBuffer[idx + 9]; _pBuffer[idx + 18] = _pBuffer[idx + 10]; _pBuffer[idx + 19] = _pBuffer[idx + 11]; _pBuffer[idx + 20] = fX + xoffset; _pBuffer[idx + 21] = fY + (float)curb_h * _fScale; _pBuffer[idx + 22] = (float)curb_x / (float)t_w; _pBuffer[idx + 23] = (float)(curb_y + curb_h) / (float)t_h; if (fAngle != 0.f) { float x = _pBuffer[idx], y = _pBuffer[idx + 1]; _pBuffer[idx] = transform._2D[0][0] * x + transform._2D[1][0] * y + transform._2D[3][0]; _pBuffer[idx + 1] = transform._2D[0][1] * x + transform._2D[1][1] * y + transform._2D[3][1]; x = _pBuffer[idx + 4]; y = _pBuffer[idx + 5]; _pBuffer[idx + 4] = transform._2D[0][0] * x + transform._2D[1][0] * y + transform._2D[3][0]; _pBuffer[idx + 5] = transform._2D[0][1] * x + transform._2D[1][1] * y + transform._2D[3][1]; x = _pBuffer[idx + 8]; y = _pBuffer[idx + 9]; _pBuffer[idx + 8] = transform._2D[0][0] * x + transform._2D[1][0] * y + transform._2D[3][0]; _pBuffer[idx + 9] = transform._2D[0][1] * x + transform._2D[1][1] * y + transform._2D[3][1]; x = _pBuffer[idx + 20]; y = _pBuffer[idx + 21]; _pBuffer[idx + 20] = transform._2D[0][0] * x + transform._2D[1][0] * y + transform._2D[3][0]; _pBuffer[idx + 21] = transform._2D[0][1] * x + transform._2D[1][1] * y + transform._2D[3][1]; _pBuffer[idx + 12] = _pBuffer[idx]; _pBuffer[idx + 13] = _pBuffer[idx + 1]; _pBuffer[idx + 16] = _pBuffer[idx + 8]; _pBuffer[idx + 17] = _pBuffer[idx + 9]; } if (bVerticesColors) { const uint idx = length * 24 + i * 24; memcpy(&_pBuffer[idx], verts_colors[0], 12 * sizeof(float)); memcpy(&_pBuffer[idx + 12], verts_colors[0], 4 * sizeof(float)); memcpy(&_pBuffer[idx + 16], verts_colors[2], 8 * sizeof(float)); } xoffset += (float)curb_w * _fScale; } TDrawDataDesc desc; desc.pData = (uint8 *)_pBuffer; desc.uiVertexStride = 4 * sizeof(float); desc.bVertices2D = true; desc.uiTextureVertexOffset = 2 * sizeof(float); desc.uiTextureVertexStride = desc.uiVertexStride; if (bVerticesColors) desc.uiColorOffset = length * 24 * sizeof(float); _pRender2D->Draw(_pTex, desc, CRDM_TRIANGLES, length*6, TRectF(), (E_EFFECT2D_FLAGS)(EF_BLEND | (bVerticesColors ? EF_DEFAULT : EF_COLOR_MIX))); _pRender2D->SetColorMix(prev_color); return S_OK; }
void EC_OgreMovableTextOverlay::Update() { if (!node_ || !visible_ || !placeable_ || renderer_.expired()) return; if(!node_->isInSceneGraph()) { overlay_->hide(); return; } Ogre::Camera* camera = renderer_.lock()->GetCurrentCamera(); if (!camera) return; Ogre::Viewport* viewport = camera->getViewport(); Ogre::Vector3 point = node_->_getDerivedPosition(); // Is the camera facing that point? If not, hide the overlay and return. Ogre::Plane cameraPlane = Ogre::Plane(Ogre::Vector3(camera->getDerivedOrientation().zAxis()), camera->getDerivedPosition()); if(cameraPlane.getSide(point) != Ogre::Plane::NEGATIVE_SIDE) { overlay_->hide(); return; } // Hide the overlay if it's too far. Ogre::Vector3 res = camera->getDerivedPosition() - point; float distance = sqrt(res.x * res.x + res.y * res.y + res.z * res.z); if (distance > MAX_VISIBILITY_DISTANCE) { overlay_->hide(); return; } // Set the alpha channel for the overlay. if (materialHasAlpha_) SetAlphaChannelIntensity(distance); // Derive the 2D screen-space coordinates for node point. point = camera->getProjectionMatrix() * (camera->getViewMatrix() * point); // Transform from coordinate space [-1, 1] to [0, 1] float x = (point.x / 2) + 0.5f; float y = 1 - ((point.y / 2) + 0.5f); // Update the position (centering the text) container_->setPosition(x - (textDim_.x / 2), y); // Update the dimensions also if the window is resized. if (windowWidth_ != viewport->getActualWidth() || windowHeight_ != viewport->getActualHeight()) { windowWidth_ = viewport->getActualWidth(); windowHeight_ = viewport->getActualHeight(); textDim_ = GetTextDimensions(text_); container_->setDimensions(textDim_.x, textDim_.y); } ///\todo Scale the text and width and height of the container? // text_element_->setMetricsMode(Ogre::GMM_RELATIVE); // text_element_->setPosition(textDim_.x, textDim_.y); // text_element_->setPosition(textDim_.x / 10, 0.01); // text_element_->setCharHeight(max_x - min_x/*2*0.0175f*///); overlay_->show(); }
void EC_OgreMovableTextOverlay::CreateOverlay(const Vector3df& offset) { if (renderer_.expired()) return; // Return if already created if (node_) return; // Create SceneNode Ogre::SceneManager *scene_mgr = renderer_.lock()->GetSceneManager(); node_ = scene_mgr->createSceneNode(); // Set the node position to an user-specified offset node_->setPosition(ToOgreVector3(offset)); // Overlay overlayName_ = renderer_.lock()->GetUniqueObjectName(); overlay_ = Ogre::OverlayManager::getSingleton().create(overlayName_); // Container containerName_ = renderer_.lock()->GetUniqueObjectName(); container_ = static_cast<Ogre::OverlayContainer*> (Ogre::OverlayManager::getSingleton().createOverlayElement("Panel", containerName_)); overlay_->add2D(container_); // Font ///\todo user-defined font std::string fontName = "Console"; Ogre::FontManager::getSingleton().load(fontName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); font_ = (Ogre::Font*)Ogre::FontManager::getSingleton().getByName(fontName).getPointer(); font_->setParameter("size", "16"); // Overlay text text_element_ = checked_static_cast<Ogre::TextAreaOverlayElement*> (Ogre::OverlayManager::getSingleton().createOverlayElement("TextArea", overlayName_)); // text_element_ = Ogre::OverlayManager::getSingleton().createOverlayElement("TextArea", "shapeNameText"); text_element_->setDimensions(0.8, 0.8); text_element_->setMetricsMode(Ogre::GMM_PIXELS); text_element_->setPosition(1, 2); text_element_->setParameter("font_name", fontName); text_element_->setParameter("char_height", font_->getParameter("size")); // text_element_->setCharHeight(0.035f); text_element_->setParameter("horz_align", "left"); fontColor_ = Color(0, 0, 0, 1); text_element_->setColour(Ogre::ColourValue::Black); container_->addChild(text_element_); if(text_ != "") { textDim_ = GetTextDimensions(text_); container_->setDimensions(textDim_.x, textDim_.y); } SetMaterial("BlueTransparent"/*baseMaterialName_*/); if (visible_) overlay_->show(); else overlay_->hide(); overlay_->setZOrder(100); }