Skip to content

Commit

Permalink
try to load chinese chars
Browse files Browse the repository at this point in the history
this is ugly, we need to preload all used chars right now, which
is enough for current scenario.
  • Loading branch information
Sian Cao committed May 7, 2014
1 parent 1db480b commit 5d5e3aa
Show file tree
Hide file tree
Showing 3 changed files with 228 additions and 27 deletions.
143 changes: 143 additions & 0 deletions .ycm_extra_conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import os
import ycm_core

# These are the compilation flags that will be used in case there's no
# compilation database set (by default, one is not set).
# CHANGE THIS LIST OF FLAGS. YES, THIS IS THE DROID YOU HAVE BEEN LOOKING FOR.
flags = [
'-Wall',
'-DNDEBUG',
# THIS IS IMPORTANT! Without a "-std=<something>" flag, clang won't know which
# language to use when compiling headers. So it will guess. Badly. So C++
# headers will be compiled as C headers. You don't want that so ALWAYS specify
# a "-std=<something>".
# For a C project, you would set this to something like 'c99' instead of
# 'c++11'.
'-std=c++11',
# ...and the same thing goes for the magic -x option which specifies the
# language that the files to be compiled are written in. This is mostly
# relevant for c++ headers.
# For a C project, you would set this to 'c' instead of 'c++'.
'-x',
'c++',
'-isystem',
'/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8',
'-isystem',
'/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/backward',
'-isystem',
'/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/x86_64-linux-gnu/c++/4.8',
'-isystem',
'/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++',
'-isystem',
'/usr/local/include',
'-isystem',
'/usr/include/x86_64-linux-gnu',
'-isystem',
'/usr/include',
'-I.',
'-I/usr/include/freetype2',
'-I/usr/include/GLES2',
'-I/usr/include/EGL',
'-I/usr/include/GLFW',
'-I/usr/include/glm',
]


# Set this to the absolute path to the folder (NOT the file!) containing the
# compile_commands.json file to use that instead of 'flags'. See here for
# more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html
#
# Most projects will NOT need to set this to anything; you can just change the
# 'flags' list of compilation flags. Notice that YCM itself uses that approach.
compilation_database_folder = ''

if os.path.exists( compilation_database_folder ):
database = ycm_core.CompilationDatabase( compilation_database_folder )
else:
database = None

SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ]

def DirectoryOfThisScript():
return os.path.dirname( os.path.abspath( __file__ ) )


def MakeRelativePathsInFlagsAbsolute( flags, working_directory ):
if not working_directory:
return list( flags )
new_flags = []
make_next_absolute = False
path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ]
for flag in flags:
new_flag = flag

if make_next_absolute:
make_next_absolute = False
if not flag.startswith( '/' ):
new_flag = os.path.join( working_directory, flag )

for path_flag in path_flags:
if flag == path_flag:
make_next_absolute = True
break

if flag.startswith( path_flag ):
path = flag[ len( path_flag ): ]
new_flag = path_flag + os.path.join( working_directory, path )
break

if new_flag:
new_flags.append( new_flag )
return new_flags


def IsHeaderFile( filename ):
extension = os.path.splitext( filename )[ 1 ]
return extension in [ '.h', '.hxx', '.hpp', '.hh' ]


def GetCompilationInfoForFile( filename ):
# The compilation_commands.json file generated by CMake does not have entries
# for header files. So we do our best by asking the db for flags for a
# corresponding source file, if any. If one exists, the flags for that file
# should be good enough.
if IsHeaderFile( filename ):
basename = os.path.splitext( filename )[ 0 ]
for extension in SOURCE_EXTENSIONS:
replacement_file = basename + extension
if os.path.exists( replacement_file ):
compilation_info = database.GetCompilationInfoForFile(
replacement_file )
if compilation_info.compiler_flags_:
return compilation_info
return None
return database.GetCompilationInfoForFile( filename )


def FlagsForFile( filename, **kwargs ):
if database:
# Bear in mind that compilation_info.compiler_flags_ does NOT return a
# python list, but a "list-like" StringVec object
compilation_info = GetCompilationInfoForFile( filename )
if not compilation_info:
return None

final_flags = MakeRelativePathsInFlagsAbsolute(
compilation_info.compiler_flags_,
compilation_info.compiler_working_dir_ )

# NOTE: This is just for YouCompleteMe; it's highly likely that your project
# does NOT need to remove the stdlib flag. DO NOT USE THIS IN YOUR
# ycm_extra_conf IF YOU'RE NOT 100% SURE YOU NEED IT.
#try:
#final_flags.remove( '-stdlib=libc++' )
#except ValueError:
#pass
else:
relative_to = DirectoryOfThisScript()
final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to )

return {
'flags': final_flags,
'do_cache': True
}
103 changes: 78 additions & 25 deletions atlas.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,26 +30,41 @@ static void init_ft()
}
}

void TextMode::create_atlas(FT_Face face, int pointSize)
bool TextMode::load_char_helper(FT_ULong char_code)
{
FT_GlyphSlot slot = face->glyph;
if (FT_Load_Char(face, char_code, FT_LOAD_RENDER)) {
std::cerr << "load " << char_code << " failed\n";
return false;
}

_atlas.infos[char_code] = {
(float)slot->bitmap_left, (float)slot->bitmap_top,
(float)slot->bitmap.width, (float)slot->bitmap.rows,
float(slot->advance.x >> 6), float(slot->advance.y >> 6),
_atlas.width
};

_atlas.height = std::max(_atlas.height, _atlas.infos[char_code].height);
_atlas.width += _atlas.infos[char_code].width + 10;
return true;
}

//@arg preloads is a wstring which contains all chars that need to load into atlas
void TextMode::create_atlas(FT_Face face, int pointSize, std::wstring preloads)
{
FT_Set_Pixel_Sizes(face, 0, pointSize);
_atlas.point_size = pointSize;
FT_GlyphSlot slot = face->glyph;
for (unsigned char i = 32; i < 128; i++) {
if (FT_Load_Char(face, (char)i, FT_LOAD_RENDER)) {
std::cerr << "load " << i << " failed\n";
continue;
}

_atlas.infos[i] = {
(float)slot->bitmap_left, (float)slot->bitmap_top,
(float)slot->bitmap.width, (float)slot->bitmap.rows,
float(slot->advance.x >> 6), float(slot->advance.y >> 6),
_atlas.width
};
FT_ULong num = 128;

//ASCII is loaded by default
for (auto i = 32; i < num; i++) {
load_char_helper(i);
}

_atlas.height = std::max(_atlas.height, _atlas.infos[i].height);
_atlas.width += _atlas.infos[i].width + 10;
for (auto i: preloads) {
load_char_helper(i);
}

//NOTE: transparent and `+10` above are anti rendering artifacts.
Expand All @@ -59,8 +74,9 @@ void TextMode::create_atlas(FT_Face face, int pointSize)
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, _atlas.width, _atlas.height,
0, GL_ALPHA, GL_UNSIGNED_BYTE, transparent);

for (unsigned char i = 32; i < 128; i++) {
if (FT_Load_Char(face, (char)i, FT_LOAD_RENDER)) {
for (auto p: _atlas.infos) {
auto i = p.first;
if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {
std::cerr << "load " << i << " failed\n";
continue;
}
Expand All @@ -69,6 +85,43 @@ void TextMode::create_atlas(FT_Face face, int pointSize)
}
}

void TextMode::render_str(std::wstring ws, float x, float y, float sx, float sy)
{
int len = ws.length();

struct point_t {
GLfloat x, y, s, t;
} points[6 * len];

int i = 0;
for (auto c: ws) {
GLfloat x0 = x + _atlas.infos[c].left * sx;
GLfloat y0 = y + _atlas.infos[c].top * sy;
GLfloat w = _atlas.infos[c].width * sx, h = _atlas.infos[c].height * sy;

float tw = _atlas.infos[c].width / _atlas.width;
float tx = _atlas.infos[c].offset / _atlas.width;
float ty = _atlas.infos[c].height / _atlas.height;

int p = i * 6;
points[p++] = {x0, y0, tx, 0,};
points[p++] = {x0 + w, y0, tx + tw, 0,};
points[p++] = {x0, y0 - h, tx, ty,};

points[p++] = {x0, y0 - h, tx, ty,};
points[p++] = {x0 + w, y0, tx + tw, 0,};
points[p++] = {x0 + w, y0 - h, tx + tw, ty,};

x += _atlas.infos[c].ax * sx;
y += _atlas.infos[c].ay * sy;
i++;
}

glBindBuffer(GL_ARRAY_BUFFER, _proc.vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof points, points, GL_DYNAMIC_DRAW);
glDrawArrays(GL_TRIANGLES, 0, len * 6);
}

void TextMode::render_text(const char *text, float x, float y, float sx, float sy)
{
int len = strlen(text);
Expand Down Expand Up @@ -138,7 +191,7 @@ bool TextMode::init(int width, int height)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

create_atlas(face, 28);
create_atlas(face, 28, L"普华客户端操作系统");

glClearColor(1.0, 1.0, 1.0, 1.0);
return true;
Expand All @@ -165,20 +218,20 @@ void TextMode::render()
};
glUniform4fv(glGetUniformLocation(_proc.program, "bgcolor"), 1, bgcolor);

float ps1 = 24.0, ps2 = 38.0;
float ps1 = 24.0;
float sx = 2.0 / _screenWidth, sy = 2.0 / _screenHeight;

float x = -1.0, y = 1.0 - ps1 * sy;
render_text("this is freetype2 rendered text", x, y, sx, sy);

x = -1.0, y = 1.0 - (ps1+ps2) * sy;
render_text("this is freetype2 rendered text again", x, y, sx, sy);
render_text("Welcome to iSoft Client OS", x, y, sx, sy);

GLfloat bgcolor2[] = {
0, float((glm::cos(t) + 1.0)/2.0), float((glm::sin(t)+1.0)/2.0), 0.5
};
glUniform4fv(glGetUniformLocation(_proc.program, "bgcolor"), 1, bgcolor2);
x = -1.0 + 0.002, y = 1.0 - (ps1+ps2+ps2/3) * sy;
render_text("overrided transparent line", x, y, sx, sy);
x = -1.0 + (_screenWidth/2.0) * sx - 0.3, y = 1.0 - (_screenHeight/2.0) * sy;
render_str(L"普华客户端操作系统", x, y, sx, sy);

y -= ps1 * 2 * sy;
render_str(L"System Loading...", x, y, sx, sy);
}

9 changes: 7 additions & 2 deletions atlas.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
#include <freetype2/ft2build.h>
#include FT_FREETYPE_H

#include <string>
#include <unordered_map>

struct char_info_t {
float left, top;
Expand All @@ -17,7 +19,8 @@ struct char_info_t {

struct atlas_t {
float width, height;
struct char_info_t infos[128];
//struct char_info_t infos[128];
std::unordered_map<FT_ULong, struct char_info_t> infos;
int point_size;
};

Expand All @@ -34,8 +37,10 @@ class TextMode: public ActionMode {

private:
atlas_t _atlas;
void create_atlas(FT_Face face, int pointSize);
void create_atlas(FT_Face face, int pointSize, std::wstring preloads);
void render_text(const char *text, float x, float y, float sx, float sy);
void render_str(std::wstring ws, float x, float y, float sx, float sy);
bool load_char_helper(FT_ULong char_code);
};

#endif

0 comments on commit 5d5e3aa

Please sign in to comment.