int __stdcall get_length(char *text, char *buffer, int height, int max_len) { stbtt_fontinfo font; int i,j,ascent,baseline,ch,xpos=0; float scale=0; baseline=10; if (buffer==-1) {stbtt_InitFont(&font, pdf_font_DroidSans,stbtt_GetFontOffsetForIndex(pdf_font_DroidSans,0) );} else {stbtt_InitFont(&font, buffer,stbtt_GetFontOffsetForIndex(buffer,0) );kol_board_puts("Font loaded..\n");} //kol_board_puts("Engine init..\n"); //kol_board_puti(&screen); scale = stbtt_ScaleForPixelHeight(&font, height*3/4); while (dos2utf(text[ch])) { // kol_board_puts("new symbol...\n"); int advance,lsb; stbtt_GetCodepointHMetrics(&font, dos2utf(text[ch]), &advance, &lsb); xpos += (advance * scale); if ((int)xpos>max_len) return ch; if (text[ch+1]) xpos += scale*stbtt_GetCodepointKernAdvance(&font, dos2utf(text[ch]),dos2utf(text[ch+1])); ++ch; } return ch; }
FontRenderer FontRenderer::createHardCopy() const { FontRenderer ret; ret.m_currentSize = m_currentSize; ret.m_metrics = m_metrics; ret.m_fileSize = m_fileSize; ret.m_ownData = m_ownData; if (m_ownData) { fm::Uint8 *buf = new fm::Uint8[m_fileSize]; std::memcpy(buf,m_fileContent,m_fileSize); ret.m_fileContent = buf; } else { ret.m_fileContent = m_fileContent; } if (ret.m_fileContent) stbtt_InitFont((stbtt_fontinfo*)ret.m_stbFontInfo, ret.m_fileContent, stbtt_GetFontOffsetForIndex(ret.m_fileContent,0)); return ret; }
int __stdcall picture(char *text, char *buffer, char *screen1, int width, int height) { //unsigned char *screen; //screen=zmalloc(20*78); //kol_board_puts(screen); //kol_board_puts("It was text\n"); stbtt_fontinfo font; int i,j,ascent,baseline,descent,ch=0; float scale, xpos=0; //baseline=10; kol_board_puts("Font address:\n"); //kol_board_puti(buffer); if (buffer==-1) {stbtt_InitFont(&font, pdf_font_DroidSans,stbtt_GetFontOffsetForIndex(pdf_font_DroidSans,0) );kol_board_puts("default font\n");} else {stbtt_InitFont(&font, buffer,stbtt_GetFontOffsetForIndex(buffer,0) );kol_board_puts("Font loaded..\n");} //kol_board_puti(&screen); scale = stbtt_ScaleForPixelHeight(&font, height*3/4); //stbtt_GetFontVMetrics(&font, &ascent,0,0); stbtt_GetFontVMetrics(&font, &ascent,&descent,0); //lev //baseline = (int) (ascent*scale); baseline = (int) ((ascent-descent)*scale); //lev //kol_board_puts("Text render:\n"); while (dos2utf(text[ch])) { //kol_board_puts("new symbol...\n"); int advance,lsb,x0,y0,x1,y1; //float x_shift = xpos - (float) i_floor(xpos); // kol_board_puts("floor called!\n"); stbtt_GetCodepointHMetrics(&font, dos2utf(text[ch]), &advance, &lsb); stbtt_GetCodepointBitmapBoxSubpixel(&font, dos2utf(text[ch]), scale,scale,0,0, &x0,&y0,&x1,&y1); //10= y0, 20=y1-y0 or so stbtt_MakeCodepointBitmapSubpixel(&font, &screen1[(baseline + y0)*width+ (int)xpos + x0], x1-x0,y1-y0, width, scale,scale,0,0, dos2utf(text[ch])); // note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong // because this API is really for baking character bitmaps into textures. if you want to do this, // you need to render the bitmap to a temp buffer, then\n\t"alpha blend" that into the working buffer xpos += (advance * scale); if (text[ch+1]) xpos += scale*stbtt_GetCodepointKernAdvance(&font, dos2utf(text[ch]),dos2utf(text[ch+1])); ++ch; } //zmemcpy(screen1,bitmap,20*20); //kol_board_puts("finished...\n"); return 0; }
bool FontAtlas::generate() { generated = false; std::array<int, kMaxGlyphs> glyphs; int numGlyphs = glyphsForCategory(glyphCategory, glyphs); packData->charData.resize(numGlyphs); stbtt_pack_range packRange; packRange.font_size = fontSize; packRange.first_unicode_codepoint_in_range = 0; packRange.array_of_unicode_codepoints = glyphs.data(); packRange.num_chars = numGlyphs; packRange.chardata_for_range = packData->charData.data(); UPtr<unsigned char[]> textureData; stbtt_pack_context packContext; bool packed = pack(font, &packContext, &packRange, &textureData, &textureWidth, &textureHeight); if (!packed) { return false; } stbtt_fontinfo fontInfo; int res = stbtt_InitFont(&fontInfo, font->data(), stbtt_GetFontOffsetForIndex(font->data(), 0)); if (!res) { return false; } float scale = stbtt_ScaleForPixelHeight(&fontInfo, fontSize); int ascent, descent, lineGap; stbtt_GetFontVMetrics(&fontInfo, &ascent, &descent, &lineGap); fontSpacing.ascent = ascent * scale; fontSpacing.descent = descent * scale; fontSpacing.lineGap = lineGap * scale; texture = std::make_shared<Texture>(GL_TEXTURE_2D); texture->bind(); glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, textureWidth, textureHeight, 0, GL_RED, GL_UNSIGNED_BYTE, textureData.get()); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); texture->unbind(); generated = true; return true; }
fm::Result FontRenderer::loadFromFile(const std::string &fileName,unsigned int size) { clean(); m_ownData = true; std::ifstream in(fileName.c_str(), std::fstream::in | std::fstream::binary); if (!in) { clean(); return fm::Result("IOError",fm::Result::OPFailed,"FileNotFound","loadFromFile",__FILE__,__LINE__,fileName); } in.seekg(0, std::ios::end); m_fileSize = in.tellg(); if (in.fail()) { clean(); return fm::Result("IOError",fm::Result::OPFailed,"FileNotReadable","loadFromFile",__FILE__,__LINE__,fileName); } m_fileContent = new fm::Uint8[m_fileSize]; in.seekg(0, std::ios::beg); in.read((char*)m_fileContent, m_fileSize); if (in.fail()) { clean(); return fm::Result("IOError",fm::Result::OPFailed,"FileNotReadable","loadFromFile",__FILE__,__LINE__,fileName); } in.close(); if (!stbtt_InitFont((stbtt_fontinfo*)m_stbFontInfo, m_fileContent, stbtt_GetFontOffsetForIndex(m_fileContent,0))) { clean(); return fm::Result("TTFError",fm::Result::OPFailed,"InvalidFont","loadFromFile",__FILE__,__LINE__,fileName); } setCharacterSize(size); return fm::Result(); }
fm::Result FontRenderer::loadFromMemory(const fm::Uint8 *fileContent,fm::Size fileSizeInBytes,unsigned int size) { clean(); m_ownData = false; m_fileSize = fileSizeInBytes; m_fileContent = fileContent; if (!stbtt_InitFont((stbtt_fontinfo*)m_stbFontInfo, m_fileContent, stbtt_GetFontOffsetForIndex(m_fileContent,0))) { clean(); return fm::Result("FTError",fm::Result::OPFailed,"InvalidFont","loadFromMemory",__FILE__,__LINE__); } setCharacterSize(size); return fm::Result(); }
static void *font_renderer_stb_init(const char *font_path, float font_size) { int ascent, descent, line_gap; stbtt_fontinfo info; uint8_t *font_data = NULL; stb_font_renderer_t *self = (stb_font_renderer_t*) calloc(1, sizeof(*self)); /* See https://github.com/nothings/stb/blob/master/stb_truetype.h#L539 */ font_size = STBTT_POINT_SIZE(font_size); if (!self) goto error; if (!filestream_read_file(font_path, (void**)&font_data, NULL)) goto error; if (!font_renderer_stb_create_atlas(self, font_data, font_size, 512, 512)) goto error; if (!stbtt_InitFont(&info, font_data, stbtt_GetFontOffsetForIndex(font_data, 0))) goto error; stbtt_GetFontVMetrics(&info, &ascent, &descent, &line_gap); self->line_height = ascent - descent; if (font_size < 0) self->line_height *= stbtt_ScaleForMappingEmToPixels(&info, -font_size); else self->line_height *= stbtt_ScaleForPixelHeight(&info, font_size); free(font_data); return self; error: if (font_data) free(font_data); if (self) font_renderer_stb_free(self); return NULL; }
static void *font_renderer_stb_init(const char *font_path, float font_size) { uint8_t *font_data = NULL; int ascent, descent, line_gap; stbtt_fontinfo info; stb_font_renderer_t *self = (stb_font_renderer_t*) calloc(1, sizeof(*self)); /* prevent warnings */ (void)rect_width_compare; if (!self) goto error; if (!read_file(font_path, (void**)&font_data, NULL)) goto error; if (!font_renderer_stb_create_atlas(self, font_data, font_size)) goto error; if (!stbtt_InitFont(&info, font_data, stbtt_GetFontOffsetForIndex(font_data, 0))) goto error; stbtt_GetFontVMetrics(&info, &ascent, &descent, &line_gap); self->line_height = ascent - descent;// + line_gap; if (font_size < 0) self->line_height *= stbtt_ScaleForMappingEmToPixels(&info, -font_size); else self->line_height *= stbtt_ScaleForPixelHeight(&info, font_size); free(font_data); return self; error: if (font_data) free(font_data); font_renderer_stb_free(self); return NULL; }
fm::Result FontRenderer::copyFromMemory(const fm::Uint8 *fileContent,fm::Size fileSizeInBytes,unsigned int size) { clean(); m_ownData = true; m_fileSize = fileSizeInBytes; fm::Uint8 *buf = new fm::Uint8[fileSizeInBytes]; std::memcpy(buf,fileContent,fileSizeInBytes); m_fileContent = buf; if (!stbtt_InitFont((stbtt_fontinfo*)m_stbFontInfo, m_fileContent, stbtt_GetFontOffsetForIndex(m_fileContent,0))) { clean(); return fm::Result("FTError",fm::Result::OPFailed,"InvalidFont","copyFromMemory",__FILE__,__LINE__); } setCharacterSize(size); return fm::Result(); }
FontRenderer &FontRenderer::operator=(const FontRenderer &renderer) { if (m_ownData) delete m_fileContent; m_currentSize = renderer.m_currentSize; m_metrics = renderer.m_metrics; m_fileSize = renderer.m_fileSize; m_ownData = renderer.m_ownData; if (m_ownData) { fm::Uint8 *buf = new fm::Uint8[m_fileSize]; std::memcpy(buf,renderer.m_fileContent,m_fileSize); m_fileContent = buf; } else { m_fileContent = renderer.m_fileContent; } if (m_fileContent) stbtt_InitFont((stbtt_fontinfo*)m_stbFontInfo, m_fileContent, stbtt_GetFontOffsetForIndex(m_fileContent,0)); }
int main(int argc, char **argv) { stbtt_fontinfo font; unsigned char *bitmap; int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : 34807), s = (argc > 2 ? atoi(argv[2]) : 32); //debug(); // @TODO: why is minglui.ttc failing? fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/mingliu.ttc", "rb")); //fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/x/DroidSansMono.ttf", "rb")); { static stbtt_pack_context pc; static stbtt_packedchar cd[256]; static unsigned char atlas[1024*1024]; stbtt_PackBegin(&pc, atlas, 1024,1024,1024,1,NULL); stbtt_PackFontRange(&pc, ttf_buffer, 0, 32.0, 0, 256, cd); stbtt_PackEnd(&pc); } #if 0 stbtt_BakeFontBitmap(ttf_buffer,stbtt_GetFontOffsetForIndex(ttf_buffer,0), 40.0, temp_bitmap[0],BITMAP_W,BITMAP_H, 32,96, cdata); // no guarantee this fits! stbi_write_png("fonttest1.png", BITMAP_W, BITMAP_H, 1, temp_bitmap, 0); { stbtt_pack_context pc; stbtt_PackBegin(&pc, temp_bitmap[0], BITMAP_W, BITMAP_H, 0, 1, NULL); stbtt_PackFontRange(&pc, ttf_buffer, 0, 20.0, 32, 95, pdata); stbtt_PackFontRange(&pc, ttf_buffer, 0, 20.0, 0xa0, 0x100-0xa0, pdata); stbtt_PackEnd(&pc); stbi_write_png("fonttest2.png", BITMAP_W, BITMAP_H, 1, temp_bitmap, 0); } { stbtt_pack_context pc; stbtt_pack_range pr[2]; stbtt_PackBegin(&pc, temp_bitmap[0], BITMAP_W, BITMAP_H, 0, 1, NULL); pr[0].chardata_for_range = pdata; pr[0].first_unicode_char_in_range = 32; pr[0].num_chars_in_range = 95; pr[0].font_size = 20.0f; pr[1].chardata_for_range = pdata+256; pr[1].first_unicode_char_in_range = 0xa0; pr[1].num_chars_in_range = 0x100 - 0xa0; pr[1].font_size = 20.0f; stbtt_PackSetOversampling(&pc, 2, 2); stbtt_PackFontRanges(&pc, ttf_buffer, 0, pr, 2); stbtt_PackEnd(&pc); stbi_write_png("fonttest3.png", BITMAP_W, BITMAP_H, 1, temp_bitmap, 0); } return 0; #endif stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0)); bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, (float)s), c, &w, &h, 0,0); for (j=0; j < h; ++j) { for (i=0; i < w; ++i) putchar(" .:ioVM@"[bitmap[j*w+i]>>5]); putchar('\n'); } return 0; }
bool Font::load(std::string path, AssetManager& manager) { mName = getFileNameFromPath(path); mPath = getPathFromFilePath(path); FILE* file = fopen(path.c_str(), "rb"); size_t fSize = 0; U8* buffer = nullptr; if (!file) return false; fseek(file, 0, SEEK_END); fSize = ftell(file); rewind(file); buffer = new U8[fSize]; const U32 TATLAS_SIZE = 512; size_t result = fread(buffer, sizeof(U8), fSize, file); if (result != fSize) return false; stbtt_fontinfo fontInfo; stbtt_InitFont(&fontInfo, buffer, stbtt_GetFontOffsetForIndex(buffer, 0)); U8* img = new U8[TATLAS_SIZE * TATLAS_SIZE]; U8* rgbaImg = new U8[TATLAS_SIZE * TATLAS_SIZE * 4]; stbtt_pack_context pack; stbtt_packedchar pcdata[96]; stbtt_packedchar tabData; int packSuccess = stbtt_PackBegin(&pack, img, TATLAS_SIZE, TATLAS_SIZE, 0, 1, NULL); int rangeSuc = stbtt_PackFontRange(&pack, buffer, 0, mSize, 32, 95, pcdata); int tabSuc = stbtt_PackFontRange(&pack, buffer, 0, mSize, '\t', 1, &tabData); stbtt_PackEnd(&pack); I32 largestY = 0; I32 tabSize = 0; mTabWidth = tabData.xadvance; for (int i = 0; i < 96; ++i) { mGlyphs[i].x0 = pcdata[i].x0; mGlyphs[i].y0 = pcdata[i].y0; mGlyphs[i].x1 = pcdata[i].x1; mGlyphs[i].y1 = pcdata[i].y1; mGlyphs[i].xoff = pcdata[i].xoff; mGlyphs[i].yoff = pcdata[i].yoff; mGlyphs[i].xoff2 = pcdata[i].xoff2; mGlyphs[i].yoff2 = pcdata[i].yoff2; mGlyphs[i].xadvance = pcdata[i].xadvance; vec2 tl = GET_UV(mGlyphs[i].x0, TATLAS_SIZE, mGlyphs[i].y0, TATLAS_SIZE); vec2 br = GET_UV(mGlyphs[i].x1, TATLAS_SIZE, mGlyphs[i].y1, TATLAS_SIZE); mGlyphs[i].u0 = tl.x(); mGlyphs[i].v0 = tl.y(); mGlyphs[i].u1 = br.x(); mGlyphs[i].v1 = br.y(); mGlyphs[i].w = mGlyphs[i].x1 - mGlyphs[i].x0; mGlyphs[i].h = abs(mGlyphs[i].y1 - mGlyphs[i].y0); if (mGlyphs[i].y1 - mGlyphs[i].y0 > largestY) largestY = (mGlyphs[i].y1 - mGlyphs[i].y0); } mMaxGlyphHeight = largestY; for (int i = 0; i < TATLAS_SIZE * TATLAS_SIZE; ++i) { rgbaImg[(i * 4) + 0] = 255; //r rgbaImg[(i * 4) + 1] = 255; //g rgbaImg[(i * 4) + 2] = 255; //b rgbaImg[(i * 4) + 3] = img[i]; //a } glGenTextures(1, &glTex); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, glTex); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TATLAS_SIZE, TATLAS_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgbaImg); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glBindTexture(GL_TEXTURE_2D, 0); fclose(file); delete[] buffer; delete[] img; delete[] rgbaImg; return true; }
void MakeBitmapCodepoint(char Letter, platform_read_file *ReadFile, game_state *GameState) { read_file_result FontFile = PlatformReadFile("../Assets/Gotham-Medium.ttf"); Assert(FontFile.Contents > 0); int Width, Height, XOffset, YOffset; stbtt_fontinfo FontInfo; stbtt_InitFont(&FontInfo, (uint8 *)FontFile.Contents, stbtt_GetFontOffsetForIndex((uint8 *)FontFile.Contents, 0)); uint8 *MonoBitmap = stbtt_GetCodepointBitmap(&FontInfo, 0, stbtt_ScaleForPixelHeight(&FontInfo, (float)GlobalFontRenderSize), Letter, &Width, &Height, &XOffset, &YOffset); font_codepoint *NextCodepoint = &GameState->AlphabetBitmaps[GameState->AlphabetBitmapsCount]; GameState->AlphabetBitmapsCount++; NextCodepoint->BaselineFactor = YOffset; NextCodepoint->Bitmap.Width = Width; NextCodepoint->Bitmap.Height = Height; NextCodepoint->Bitmap.GLTexture = (GLuint)VirtualAlloc(0, sizeof(*MonoBitmap), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); SIZE_T BitmapSize = sizeof(uint32) * Width * Height; void *ConvertedBitmap = malloc(BitmapSize); uint32 Pitch = Width * sizeof(uint32); uint8 *Source = (uint8 *)MonoBitmap; uint8 *DestRow = (uint8 *)ConvertedBitmap + ((Height - 1) * Pitch); for (uint32 Y = 0; Y < (uint32)Height; ++Y) { uint32 *Dest = (uint32 *)DestRow; for (uint32 X = 0; X < (uint32)Width; ++X) { uint8 MonoAlpha = *Source++; uint8 Bit2 = MonoAlpha; // A uint8 Bit3 = MonoAlpha; // R uint8 Bit0 = MonoAlpha; // G uint8 Bit1 = MonoAlpha; // B *Dest++ = ((Bit0 << 24) | (Bit1 << 16) | (Bit2 << 8) | (Bit3 << 0)); } DestRow -= Pitch; } //TODO pull this out into a separate GL function to keep gl code separate from game code. glGenTextures(1, &NextCodepoint->Bitmap.GLTexture); glBindTexture(GL_TEXTURE_2D, NextCodepoint->Bitmap.GLTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, ConvertedBitmap); VirtualFree(ConvertedBitmap, BitmapSize, MEM_RELEASE); stbtt_FreeBitmap(MonoBitmap, 0); }