void CFreetypeFontFace::NewPage() { BEATS_ASSERT(m_pTexture.Get() == nullptr); static const int32_t nDataSize = PAGE_WIDTH * PAGE_HEIGHT * 2; char *pZeroBuf = new char[nDataSize]; memset(pZeroBuf, 0, nDataSize); m_pTexture = new CTexture; m_pTexture->SetFilePath(_T("FreetypeFontFaceTexture")); m_pTexture->InitWithData(pZeroBuf, nDataSize, PixelFormat::AI88, PAGE_WIDTH, PAGE_HEIGHT); BEATS_SAFE_DELETE_ARRAY(pZeroBuf); m_pTexture->SetInitializeFlag(true); m_pTexture->SetLoadFlag(true); }
bool CSkin::Load() { bool bRet = false; BEATS_ASSERT(!IsLoaded(), _T("Can't Load a skin which is already loaded!")); // Load From File CSerializer serializer(_T("..\\Resource\\skin\\org.skin")); CSerializer tmpVerticesBufferPos, tmpVerticesBufferUV; CSerializer indexBuffer; size_t uVertexCount = 0; serializer >> uVertexCount; m_uVertexCount = uVertexCount; m_vertices = new CVertexPTB[uVertexCount]; float x, y, z; float u,v; for (size_t i = 0; i < uVertexCount; ++i) { ESkeletonBoneType bone, bone1, bone2, bone3; float weight, weight1, weight2,weight3; serializer >> x >> y >> z >> u >> v; serializer >> bone; serializer >> weight; serializer >> bone1; serializer >> weight1; serializer >> bone2; serializer >> weight2; serializer >> bone3; serializer >> weight3; CVertexPTB &vertex = m_vertices[i]; kmVec3Fill(&vertex.position,x,y,z); vertex.tex = CTex(u,v); vertex.bones = CIVector4(bone, bone1, bone2, bone3); kmVec4Fill(&vertex.weights,weight,weight1,weight2,weight3); #ifdef _DEBUG float sum = weight + weight1 + weight2+weight3; BEATS_ASSERT(sum < 1.01F, _T("Weight can't be greater than 1.01F, cur Value : %f!"), sum); BEATS_WARNING(sum > 0.99F, _T("Weight can't be smaller than 0.99F, cur Value : %f!"), sum); #endif } for (size_t i = 0; i < uVertexCount; ++i) { indexBuffer << (short)i; } CRenderer* pRenderer = CRenderer::GetInstance(); pRenderer->GenVertexArrays(1, &m_uVAO); pRenderer->GenBuffers(2, m_uVBO); #ifndef SW_SKEL_ANIM buildVBOVertex(m_vertices, m_uVertexCount*sizeof(CVertexPTB)); BEATS_SAFE_DELETE_ARRAY(m_vertices); #endif buildVBOIndex(indexBuffer.GetBuffer(), indexBuffer.GetWritePos()); buildVAO(); SetLoadedFlag(true); return bRet; }
void CSkin::CalcSkelAnim(const CAnimationController::BoneMatrixMap &matrices) { CVertexPT *vertices = new CVertexPT[m_uVertexCount]; for(size_t i = 0; i < m_uVertexCount; ++i) { const CVertexPTB &vertex = m_vertices[i]; CVertexPT &vertex1 = vertices[i]; if(matrices.empty()) { vertex1.position = vertex.position; vertex1.tex = vertex.tex; continue; } kmVec3 pos; kmVec3Fill(&pos,vertex.position.x,vertex.position.y, vertex.position.z); kmVec3 finalpos; kmMat4 mat, mat2, mat3, mat4; if(vertex.bones.x >= 0) { auto itr = matrices.find(static_cast<ESkeletonBoneType>(vertex.bones.x)); BEATS_ASSERT(itr != matrices.end()); mat = itr->second; kmVec3 postmp; kmVec3Transform(&postmp,&pos,&mat); kmVec3Scale(&postmp, &postmp, vertex.weights.x); finalpos = postmp; } if(vertex.bones.y >= 0) { auto itr = matrices.find(static_cast<ESkeletonBoneType>(vertex.bones.y)); BEATS_ASSERT(itr != matrices.end()); mat2 = itr->second; kmVec3 postmp; kmVec3Transform(&postmp,&pos,&mat2); kmVec3Scale(&postmp, &postmp, vertex.weights.y); kmVec3Add(&finalpos,&finalpos,&postmp); } if(vertex.bones.z >= 0) { auto itr = matrices.find(static_cast<ESkeletonBoneType>(vertex.bones.z)); BEATS_ASSERT(itr != matrices.end()); mat3 = itr->second; kmVec3 postmp; kmVec3Transform(&postmp,&pos,&mat3); kmVec3Scale(&postmp, &postmp, vertex.weights.z); kmVec3Add(&finalpos,&finalpos,&postmp); } if(vertex.bones.w >= 0) { auto itr = matrices.find(static_cast<ESkeletonBoneType>(vertex.bones.w)); BEATS_ASSERT(itr != matrices.end()); mat4 = itr->second; kmVec3 postmp; kmVec3Transform(&postmp,&pos,&mat4); kmVec3Scale(&postmp, &postmp, vertex.weights.w); kmVec3Add(&finalpos,&finalpos,&postmp); } vertex1.position = finalpos; vertex1.tex = vertex.tex; } buildVBOVertex(vertices, m_uVertexCount*sizeof(CVertexPT)); BEATS_SAFE_DELETE_ARRAY(vertices); }
CSkin::~CSkin() { BEATS_SAFE_DELETE_ARRAY(m_vertices); }
bool CEnumStrGenerator::ScanEnumInFile( const TCHAR* pFileName, const TCHAR* pSpecifyEnumName ) { bool bRet = false; CSerializer serializer(pFileName); while (serializer.GetReadPos() != serializer.GetWritePos()) { if (ScanKeyWordInCPlusPlusFile(ENUM_KEYWORD_STR, &serializer)) { bool bIsKeyWord = IsEnumKeyword(&serializer); uint32_t startPos = serializer.GetReadPos(); startPos += (uint32_t)strlen(ENUM_KEYWORD_STR); serializer.SetReadPos(startPos); if (bIsKeyWord && ScanKeyWordInCPlusPlusFile("{", &serializer)) { uint32_t endPos = serializer.GetReadPos(); uint32_t enumNameLength = endPos - startPos; char* enumName = new char[enumNameLength + 1]; enumName[enumNameLength] = 0; serializer.SetReadPos(startPos); serializer.Deserialize(enumName, enumNameLength); char* enumNewName = new char[enumNameLength + 1]; enumNewName[enumNameLength] = 0; FilterCPlusPlusFileComments(enumName, enumNewName, enumNameLength); BEATS_SAFE_DELETE_ARRAY(enumName); BEATS_ASSERT(serializer.GetReadPos() == endPos); std::set<TString> filters; filters.insert(_T("\r\n")); filters.insert(_T(" ")); filters.insert(_T("\n")); filters.insert(_T("class"));// such as enum class ETest{} TString strEnumName = CStringHelper::GetInstance()->FilterString(enumNewName, filters); BEATS_SAFE_DELETE_ARRAY(enumNewName); int nFindColonPos = CStringHelper::GetInstance()->FindFirstString(strEnumName.c_str(), ":", false); if (nFindColonPos != TString::npos) { strEnumName = strEnumName.substr(0, nFindColonPos); } std::map<TString, SEnumScanData*>::iterator iter = m_enumStrPool.find(strEnumName.c_str()); if (pSpecifyEnumName == NULL || _tcscmp(pSpecifyEnumName, strEnumName.c_str()) == 0) { bool bExisting = iter != m_enumStrPool.end(); BEATS_WARNING(!bExisting, _T("The enum type %s in %s is already scanned in %s, it may be you have scaned same file twice or a enum type with same name under different name space."), strEnumName.c_str(), pFileName, iter->second->m_enumFilePath.c_str()); // If the length is 0, it means we meet no name enum declare or a typedef. if (strEnumName.length() != 0 && !bExisting) { startPos = endPos + 1; // Escape "{" ScanKeyWordInCPlusPlusFile("}", &serializer); endPos = serializer.GetReadPos(); serializer.SetReadPos(startPos); uint32_t dataLength = endPos - startPos; char* textBuff = new char[dataLength + 1]; textBuff[dataLength] = 0; serializer.Deserialize(textBuff, dataLength); BEATS_ASSERT(serializer.GetReadPos() == endPos); char* newTextBuff = new char[dataLength + 1]; newTextBuff[dataLength] = 0; uint32_t length = 0; FilterCPlusPlusFileComments(textBuff, newTextBuff, length); BEATS_SAFE_DELETE_ARRAY(textBuff); TString strNewText = CStringHelper::GetInstance()->FilterString(newTextBuff, filters); BEATS_SAFE_DELETE_ARRAY(newTextBuff); SEnumScanData* pEnumData = new SEnumScanData; std::vector<TString> rawEnumString; CStringHelper::GetInstance()->SplitString(strNewText.c_str(), _T(","), rawEnumString); int iDefaultEnumValue = 0; for (uint32_t i = 0; i < rawEnumString.size(); ++i) { // The last enum string could be empty, such as // enum {E_1, E_2,} if (!rawEnumString[i].empty()) { SEnumData* pData = AnalyseRawEnumString(rawEnumString[i], iDefaultEnumValue); pEnumData->m_enumValue.push_back(pData); } else { BEATS_ASSERT(i == rawEnumString.size() - 1); } } pEnumData->m_enumFilePath.assign(pFileName); m_enumStrPool[strEnumName] = pEnumData; bRet = true; } } } } } return bRet; }
const CFontGlyph *CFreetypeFontFace::PrepareChar(wchar_t character, bool& bGlyphRestFlag) { bGlyphRestFlag = false; m_glyphMapLocker.lock(); auto itr = m_glyphMap.find(character); CFreetypeFontGlyph *pGlyph = itr != m_glyphMap.end() ? down_cast<CFreetypeFontGlyph *>(itr->second) : nullptr; m_glyphMapLocker.unlock(); if (!pGlyph) { float outlineWidth = GetBorderWeight() * GetScaleFactor(); ApplyFTSize(); FT_Face pFontFace = m_pFont->GetFontFace(); BEATS_ASSERT(pFontFace != NULL); bool bFindCharacterGlyph = FT_Get_Char_Index(pFontFace, character) != 0; BEYONDENGINE_UNUSED_PARAM(bFindCharacterGlyph); BEATS_ASSERT(bFindCharacterGlyph, _T("Character %d can't be found in all font face!"), character); FT_Error err = FT_Load_Char(pFontFace, character, FT_LOAD_NO_BITMAP); BEYONDENGINE_UNUSED_PARAM(err); BEATS_ASSERT(!err); FT_GlyphSlot pGlyphSlot = pFontFace->glyph; BEATS_ASSERT(pGlyphSlot != NULL); int32_t nBorderAdvanceX = pGlyphSlot->metrics.horiAdvance >> FT_SHIFT_NUM; int32_t nBorderAdvanceY = m_nLineHeight + (uint32_t)ceil(outlineWidth * 2.0f); int32_t nFontAdvanceX = nBorderAdvanceX; int32_t nFontHeight = 0; int32_t nBorderOriginWidth = 0; int32_t nFontOriginWidth = 0; int32_t nBorderHeight = 0; FT_BBox borderBox; FT_BBox fontBox; int32_t x = 0, y = 0; if (pGlyphSlot->format == FT_GLYPH_FORMAT_OUTLINE) { FT_Library ftLib = CFont::GetLibrary(); // Set up a stroker. FT_Stroker stroker; FT_Stroker_New(ftLib, &stroker); FT_Stroker_Set(stroker, (int32_t)(outlineWidth * 64), FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0); FT_Glyph pOutlineGlyph, pInnerGlyph; if (FT_Get_Glyph(pGlyphSlot, &pOutlineGlyph) == 0 && FT_Get_Glyph(pGlyphSlot, &pInnerGlyph) == 0) { FT_Glyph_StrokeBorder(&pOutlineGlyph, stroker, 0, 1); BEATS_ASSERT(pOutlineGlyph->format == FT_GLYPH_FORMAT_OUTLINE && pInnerGlyph->format == FT_GLYPH_FORMAT_OUTLINE); FT_Outline *pOutLine = &reinterpret_cast<FT_OutlineGlyph>(pOutlineGlyph)->outline; FT_Glyph_Get_CBox(pOutlineGlyph, FT_GLYPH_BBOX_GRIDFIT, &borderBox); FT_Glyph_Get_CBox(pInnerGlyph, FT_GLYPH_BBOX_GRIDFIT, &fontBox); nBorderOriginWidth = (borderBox.xMax - borderBox.xMin) >> FT_SHIFT_NUM; nFontOriginWidth = (fontBox.xMax - fontBox.xMin) >> FT_SHIFT_NUM; int32_t nBorderWidth = nextMOE(nBorderOriginWidth); // Because our GL_UNPACK_ALIGNMENT should be 8 here. nBorderHeight = (borderBox.yMax - borderBox.yMin) >> FT_SHIFT_NUM; nFontHeight = (fontBox.yMax - fontBox.yMin) >> FT_SHIFT_NUM; x = pGlyphSlot->metrics.horiBearingX >> FT_SHIFT_NUM; y = pGlyphSlot->metrics.horiBearingY >> FT_SHIFT_NUM; if(nBorderAdvanceX < x + nBorderOriginWidth) // It is true for most of the time, because border size always greater than nAdvanceX { nBorderAdvanceX = x + nBorderOriginWidth; } if (nFontAdvanceX < x + nFontOriginWidth) { nFontAdvanceX = nFontOriginWidth; } if(m_uCurrX + x + nBorderWidth > PAGE_WIDTH) { m_uCurrX = 0; m_uCurrY += (nBorderAdvanceY + m_nBorderSpace); if (m_uCurrY + nBorderAdvanceY > PAGE_HEIGHT) { BEATS_WARNING(false, "Freetype texture buffer overflow for %d glyphs, we will rebuild this texture buffer.", (uint32_t)m_glyphMap.size()); ResetGlyphs(); bGlyphRestFlag = true; return nullptr; } } int32_t nDataSize = nBorderWidth * nBorderHeight; float fBorderOffsetY = 1.0f; // Makes it look like a shadow. unsigned char* pBorderData = RenderFontDataToBmp(nBorderWidth, nBorderHeight, -borderBox.xMin, (int32_t)(-borderBox.yMin * fBorderOffsetY), pOutLine); FT_Outline *pInnerOutLine = &reinterpret_cast<FT_OutlineGlyph>(pInnerGlyph)->outline; unsigned char* pFontData = RenderFontDataToBmp(nBorderWidth, nBorderHeight, -borderBox.xMin, -borderBox.yMin, pInnerOutLine); unsigned char* pAllData = new unsigned char[nDataSize * 2]; for (int32_t i = 0; i < nDataSize; ++i) { pAllData[i * 2] = pBorderData[i]; pAllData[i * 2 + 1] = pFontData[i]; } BEATS_ASSERT(m_pTexture.Get() != nullptr); GLint nX = MAX((int32_t)m_uCurrX + x, 0); GLint nY = MAX((int32_t)m_uCurrY + (m_nAscender - y), 0); SFontUpdateImageInfo* pImageInfo = new SFontUpdateImageInfo; pImageInfo->m_pTexture = m_pTexture; pImageInfo->m_nWidth = nBorderWidth; pImageInfo->m_nHeight = nBorderHeight; pImageInfo->m_x = nX; pImageInfo->m_y = nY; pImageInfo->m_pData = pAllData; m_fontUpdateImageCacheMutex.lock(); m_fontUpdateImageCache.push_back(pImageInfo); m_fontUpdateImageCacheMutex.unlock(); // Clean up afterwards. FT_Stroker_Done(stroker); FT_Done_Glyph(pOutlineGlyph); FT_Done_Glyph(pInnerGlyph); BEATS_SAFE_DELETE_ARRAY(pBorderData); BEATS_SAFE_DELETE_ARRAY(pFontData); }