//---------------------------------------------------------------------------- void FontManager::RenderText (TriMesh *mesh, Font *font, const char *text, unsigned int style, unsigned int align, Rectf &rect, const Float2 &space, const Float4 &color, const Float3 &borderShadowColor, float shadowBorderSize, float scale, bool doTransfer) { if (!font) { assertion(false, "font must exist.\n"); return; } int fontWidth = 16; int fontHeight = 16; font->GetFontSize(fontWidth, fontHeight); float lineInterval = 0.0f; font->GetLineInterval(lineInterval); float textWidth = 0.0f; float textHeight = 0.0f; float offsetX = 0.0f; float offsetY = 0.0f; font->GetTextExtent(text, textWidth, textHeight, doTransfer); textWidth *= scale; textHeight *= scale; if (align & TEXTALIGN_LEFT) { offsetX = rect.Left; } else if (align & TEXTALIGN_HCENTER) { offsetX = rect.Left + (rect.Width() - textWidth) / 2.0f; } else if (align & TEXTALIGN_RIGHT) { offsetX = rect.Left + (rect.Width() - textWidth); } if (align & TEXTALIGN_TOP) { offsetY = rect.Bottom + rect.Height() - (fontHeight+lineInterval)*scale; } else if (align & TEXTALIGN_VCENTER) { offsetY = rect.Bottom + rect.Height()/2.0f + textHeight/2.0f - (fontHeight+lineInterval)*scale; } else if (align & TEXTALIGN_BOTTOM) { offsetY = rect.Bottom + textHeight - (fontHeight+lineInterval)*scale; } RenderText(mesh, font, text, style, offsetX, offsetY, space, color, borderShadowColor, shadowBorderSize, scale, doTransfer); }
//---------------------------------------------------------------------------- Vector2f RenderStep::PointWorldToViewPort(const APoint &point, bool *isInBack) { Rectf viewPort = mViewPort; if (viewPort.IsEmpty()) viewPort = Rectf(0.0f, 0.0f, mSize.Width, mSize.Height); HMatrix matProjView = mCamera->GetProjectionMatrix() * mCamera->GetViewMatrix(); HPoint hPoint(point.X(), point.Y(), point.Z(), point.W()); HPoint tempPoint = matProjView * hPoint; if (isInBack) { if (tempPoint.Z() <= 0) *isInBack = true; else *isInBack = false; } float wInv = 1.0f / tempPoint.W(); //投影坐标范围为[-1,1]要变成[0,1] Vector2f screenPoint; screenPoint.X() = (1.0f + tempPoint.X()*wInv) / 2.0f; screenPoint.Y() = (1.0f + tempPoint.Y()*wInv) / 2.0f; //投影坐标范围为[0,1]要变成视口内坐标 screenPoint.X() = viewPort.Left + screenPoint.X()*viewPort.Width(); screenPoint.Y() = viewPort.Bottom + screenPoint.Y()*viewPort.Height(); return screenPoint; }
//---------------------------------------------------------------------------- std::pair<float, float> EU_CanvasStage::CalPixelToWorld() { Rectf viewPort = mViewPort; if (viewPort.IsEmpty()) viewPort = Rectf(0.0f, 0.0f, mSize.Width, mSize.Height); std::pair<float, float> pixelToWorld; if (mStageCameraNode) { Camera *camera = mStageCameraNode->GetCamera(); float rMin = camera->GetRMin(); float uMin = camera->GetUMin(); float viewPortWidth = viewPort.Width(); float viewPortHeight = viewPort.Height(); float worldW = 2.0f * -rMin; float worldH = 2.0f * -uMin; worldW *= 1000.0f; worldH *= 1000.0f; pixelToWorld.first = worldW / (float)viewPortWidth; pixelToWorld.second = worldH / (float)viewPortHeight; } mPixelToWorld = pixelToWorld; return mPixelToWorld; }
//---------------------------------------------------------------------------- std::pair<float, float> RenderStep::CalPixelToWorld() { Rectf viewPort = mViewPort; if (viewPort.IsEmpty()) viewPort = Rectf(0.0f, 0.0f, mSize.Width, mSize.Height); std::pair<float, float> pixelToWorld; if (mCamera) { if (mCamera->IsPerspective()) { float rMin = mCamera->GetRMin(); float uMin = mCamera->GetUMin(); float viewPortWidth = viewPort.Width(); float viewPortHeight = viewPort.Height(); float worldW = 2.0f * -rMin; float worldH = 2.0f * -uMin; worldW *= 10.0f; worldH *= 10.0f; pixelToWorld.first = worldW / (float)viewPortWidth; pixelToWorld.second = worldH / (float)viewPortHeight; } else { float rMin = mCamera->GetRMin(); float uMin = mCamera->GetUMin(); float viewPortWidth = viewPort.Width(); float viewPortHeight = viewPort.Height(); float worldW = 2.0f * -rMin; float worldH = 2.0f * -uMin; worldW *= 1.0f; worldH *= 1.0f; pixelToWorld.first = worldW / (float)viewPortWidth; pixelToWorld.second = worldH / (float)viewPortHeight; } } return pixelToWorld; }
bool Sprite::pixCollision(const Sprite& other) const { // If bounding rectangles do not intersect, sprites // do not collide if (!rect.intersects(other.getBox())) { return false; } else { Rectf inter = intersection(other.getBox()); // Loop over region int height = (int)(inter.Height()); int width = (int)(inter.Width()); int xOff = (int)(inter.MinX() - pos.X()); int xOffOther = (int)(inter.MinX() - other.getPos().X()); int yOff = (int)(inter.MinY() - pos.Y()); int yOffOther = (int)(inter.MinY() - other.getPos().Y()); for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { // If pixel in current cell at (i, j) is non-transparent // for both sprites, then they do intersect bool thisIsTransparent = sheets[animations[current.X()].first.X().X()]->isPixTransparent( currentCell, j + xOff, i + yOff); bool otherIsTransparent = other.getSheet().isPixTransparent( other.currentCell, j + xOffOther, i + yOffOther); if (!thisIsTransparent && !otherIsTransparent) { return true; } } } // All pixels in region checked, there is no intersection return false; } }
//---------------------------------------------------------------------------- bool RenderStep::GetPickRay(float x, float y, APoint& origin, AVector& direction) { if (!mCamera) return false; Rectf viewPort = mViewPort; if (viewPort.IsEmpty()) viewPort = Rectf(0.0f, 0.0f, mSize.Width, mSize.Height); if (viewPort.IsEmpty()) return false; // Get the current viewport and test whether (x,y) is in it. float viewX = viewPort.Left; float viewY = viewPort.Bottom; float viewW = viewPort.Width(); float viewH = viewPort.Height(); // Get the [0,1]^2-normalized coordinates of (x,y). float r = ((float)(x - viewX)) / (float)viewW; float u = ((float)(y - viewY)) / (float)viewH; // Get the relative coordinates in [rmin,rmax]x[umin,umax]. float rBlend = (1.0f - r)*mCamera->GetRMin() + r*mCamera->GetRMax(); float uBlend = (1.0f - u)*mCamera->GetUMin() + u*mCamera->GetUMax(); if (mCamera->IsPerspective()) { origin = mCamera->GetPosition(); direction = mCamera->GetDMin()*mCamera->GetDVector() + rBlend*mCamera->GetRVector() + uBlend*mCamera->GetUVector(); direction.Normalize(); } else { origin = mCamera->GetPosition() + rBlend*mCamera->GetRVector() + uBlend*mCamera->GetUVector(); direction = mCamera->GetDVector(); direction.Normalize(); } return true; }
//---------------------------------------------------------------------------- Rectf EngineLoop::GetViewPortAdjustFromProject(const Rectf &viewPort) { Project *proj = Project::GetSingletonPtr(); if (!proj) return Rectf(); const Sizef &projSize = proj->GetSize(); Rectf rect; float leftPercent = viewPort.Left / projSize.Width; float bottomPercent = viewPort.Bottom / projSize.Height; float widthPercent = viewPort.Width() / projSize.Width; float heightPercent = viewPort.Height() / projSize.Height; rect.Left = mAdjustViewPort.Left + leftPercent * mAdjustViewPort.Width(); rect.Bottom = mAdjustViewPort.Bottom + bottomPercent * mAdjustViewPort.Height(); rect.Right = Mathf::Floor(rect.Left + widthPercent * mAdjustViewPort.Width()); rect.Top = Mathf::Floor(rect.Bottom + heightPercent * mAdjustViewPort.Height()); return rect; }
//---------------------------------------------------------------------------- void Font::TextOutRect(TriMesh *mesh, const char *text, Rectf &rect, float offsetX, float offsetY, bool autoWrap, const Float4 &color, unsigned int fontStyle, bool doTransfer, float scale) { if (!text) return; const char *p = text; CharCtrlCode ctrlCode; int ctrlCodeSize = 0; Rectf rec = rect; rec.Left = (float)((int)rec.Left); rec.Top = (float)((int)rec.Top); float curX = rec.Left; float curY = rec.Top; Float4 curColor = color; Float4 shadowColor = Float4(0.0f, 0.0f, 0.0f, color[3]); int showCharNum = 0; bool blink = false; int blinkModel = BLINKMODEL_SMOOTH; while (true) { ctrlCodeSize = mCharCodingObj->GetControlCode(p, ctrlCode, doTransfer); p += ctrlCodeSize; if (CCC_ENDOFSTRING == ctrlCode) break; switch (ctrlCodeSize) { case CCC_NEWLINE: { curX = rec.Left; curY -= (mCharHeight + mLineInterval) * scale; } break; case CCC_CHARACTER: { float charWidth = 0.0f; float charHeight = 0.0f; Rectf rectUV; float xx1 = 0.0f; float xx2 = 0.0f; float yy1 = 0.0f; float yy2 = 0.0f; float uOffset1 = 0.0f; float uOffset2 = 0.0f; float vOffset1 = 0.0f; float vOffset2 = 0.0f; if (autoWrap) { float dis = GetMinDisToNewLine(p, doTransfer); if (dis > rec.Width()) rec.Right = rec.Left + dis; if (curX+dis > rec.Right) { // 自动换行, 重新计算X坐标 curX = rec.Left; curY -= (mCharHeight + mLineInterval)*scale; int numSpace = mCharCodingObj->JumpOverSpaces(p); if (numSpace > 0) { p += numSpace; continue; } } } // 取一个字符 unsigned char cc[8]; int charSize = mCharCodingObj->GetAChar(p, cc); // 取字符的宽,高 GetCharExtent(cc, charWidth, charHeight); charWidth *= scale; charHeight *= scale; if (autoWrap) { xx1 = curX; xx2 = curY + charWidth; } else { xx1 = curX + offsetX; xx2 = curX + charWidth + offsetX; } yy1 = curY + offsetY; yy2 = curY + charHeight + offsetY; // 超出矩形区域则不显示,进行下一循环 if (yy2<=rec.Bottom || yy1>=rec.Top || (!autoWrap && (xx1>=rec.Right || xx2<=rec.Left))) { p += charSize; curX += charWidth; continue;; } // 按矩形区域裁剪字符多边形,同时计算纹理坐标偏移值 float height = yy2 - yy1; if (yy1 < rec.Bottom) { vOffset1 = (rect.Bottom - yy1)/height; yy1 = rec.Bottom; } if (yy2 > rec.Top) { vOffset2 = (yy2 - rec.Top)/height; yy2 = rec.Top; } if (!autoWrap) { float width = xx2 - xx1; if (xx1 < rec.Left) { uOffset1 = (rec.Left - xx1)/width; xx1 = rec.Left; } if (xx2 > rec.Right) { uOffset2 = (xx2 - rec.Right)/width; xx2 = rec.Right; } } // 取字符的贴图数据 Texture2D *tex = TexUVMaping(cc, rectUV); if (0 == mTexture) { mTexture = tex; } if (mTexture == tex) { // 对纹理坐标进行调整 float uWidth = rectUV.Width(); float vHeight = rectUV.Height(); rectUV.Left += uOffset1 * uWidth; rectUV.Right -= uOffset2 * uWidth; rectUV.Top -= vOffset1 * vHeight; rectUV.Bottom += vOffset2 * vHeight; shadowColor[3] = curColor[3]; if (fontStyle == FD_SHADOW) { SetupCharPoly(&mDrawRects[0]+mShowNum, xx1+1.0f, yy1-1.0f, xx2-xx1, yy2-yy1, rectUV, shadowColor); mShowNum++; } if (fontStyle == FD_BORDER) { SetupCharPoly(&mDrawRects[0]+mShowNum, xx1-1.0f, yy1, xx2-xx1, yy2-yy1, rectUV, shadowColor); mShowNum++; SetupCharPoly(&mDrawRects[0]+mShowNum, xx1+1.0f, yy1, xx2-xx1, yy2-yy1, rectUV, shadowColor); mShowNum++; SetupCharPoly(&mDrawRects[0]+mShowNum, xx1, yy1-1.0f, xx2-xx1, yy2-yy1, rectUV, shadowColor); mShowNum++; SetupCharPoly(&mDrawRects[0]+mShowNum, xx1, yy1+1.0f, xx2-xx1, yy2-yy1, rectUV, shadowColor); mShowNum++; } SetupCharPoly(&mDrawRects[0]+mShowNum, xx1, yy1, xx2-xx1, yy2-yy1,rectUV, curColor); mShowNum++; showCharNum++; p += charSize; curX += charWidth; } if (showCharNum>=mCharNumMaxCache || mShowNum>=FONT_MAXRECTNUM || mTexture!=tex) { RenderText(mesh); } } break; case CCC_TRANSFER: { switch (*p) { case 'R': curColor = Float4::RED; p += 1; break; case 'G': curColor = Float4::BLUE; p += 1; break; case 'B': curColor = Float4::BLUE; p += 1; break; case 'K': curColor = Float4::BLACK; p += 1; break; case 'Y': curColor = Float4::YELLOW; p += 1; break; case 'W': curColor = Float4::WHITE; p += 1; break; case 'n': curColor = color; p += 1; blink = false; break; case 'b': blink = true; if (*(p+1) == '1') { blinkModel = BLINKMODEL_SMOOTH; p += 2; } else if (*(p+1) == '2') { blinkModel = BLINKMODEL_SUDDEN; p += 2; } else { blinkModel = BLINKMODEL_SMOOTH; p += 1; } break; default: break; } if (blink) { if (BLINKMODEL_SMOOTH == blinkModel) { int microSec = (int)GetTimeInMicroseconds(); int msNum = microSec % BLINK_CIRCLE; if (msNum >= BLINK_HALFCIRCLE) msNum = BLINK_CIRCLE - msNum - 1; msNum = msNum*320/BLINK_HALFCIRCLE; if (msNum > 255) msNum = 255; } else { int microSec = (int)GetTimeInMicroseconds(); if ((microSec/BLINK_HALFCIRCLE) % 2) curColor = Float4::ZERO; } } } break; default: break; } // switch (ctrlCodeSize) } // whild (true) RenderText(mesh); }