明镜止水

知行合一

统计

留言簿

阅读排行榜

评论排行榜

2012年10月24日 #

关于pragma字节强制对齐的讨论

使用#pragma pack(NUM_OF_BYTE)可以实现字节对齐
#include <cstdio>
#pragma pack(2)
struct C
{
    char b;
    int a;
    double d;
    short c;
}test;
#pragma pack()
int main()
{
    printf("%p %p %p %p", &test.b, &test.a, &test.d, &test.c);
}
上例是按2字节对齐,可以按1 2 4 8字节对齐,除此之外,都不能编译通过


posted @ 2012-10-24 21:29 寒璿 阅读(282) | 评论 (0)编辑 收藏

2012年8月31日 #

OpenGL入门技巧——字体的渲染(引用黑莓样例源码)

《OpenGL编程精粹》是本很好的书,但是渲染字体的步骤让我头疼,要自己载入图片,自己写一个类,如果有以往开发的经验和源码,直接引用还可以。
但是对于新手来说,还是简单点好,这里介绍的例子是黑莓样例Hello World中的字体渲染技巧,能不能通用还有待检验啊。
        int dpi = bbutil_calculate_dpi(screen_cxt);
font = bbutil_load_font(
"/usr/fonts/font_repository/adobe/MyriadPro-Bold.otf", 10, dpi);
if (!font) {
fprintf(stderr, "cant open font\n");
}
先load一个font文件,可以看到,使用了adobe的字体库,在大多数电脑上都应该有这个字体库,类似的库当然也可以。
bbutil_load_font文件,看起来有点长,别担心,这些都是可以直接引用的代码:
font_t* bbutil_load_font(const char* path, int point_size, int dpi) {
    FT_Library library;
    FT_Face face;
    int c;
    int i, j;
    font_t* font;
    if (!initialized) {
    fprintf(stderr, "EGL has not been initialized\n");
    return NULL;
    }
    if (!path){
    fprintf(stderr, "Invalid path to font file\n");
return NULL;
}
    if(FT_Init_FreeType(&library)) {
    fprintf(stderr, "Error loading Freetype library\n");
    return NULL;
    }
    if (FT_New_Face(library, path,0,&face)) {
fprintf(stderr, "Error loading font %s\n", path);
return NULL;
    }
    if(FT_Set_Char_Size ( face, point_size * 64, point_size * 64, dpi, dpi)) {
fprintf(stderr, "Error initializing character parameters\n");
return NULL;
    }
    font = (font_t*) malloc(sizeof(font_t));
    font->initialized = false;
    glGenTextures(1, &(font->font_texture));
    //Let each glyph reside in 32x32 section of the font texture
    int segment_size_x = 0, segment_size_y = 0;
    int num_segments_x = 16;
    int num_segments_y = 8;
    FT_GlyphSlot slot;
    FT_Bitmap bmp;
    int glyph_width, glyph_height;
    //First calculate the max width and height of a character in a passed font
    for(c = 0; c < 128; c++) {
if(FT_Load_Char(face, c, FT_LOAD_RENDER)) {
fprintf(stderr, "FT_Load_Char failed\n");
free(font);
return NULL;
}
slot = face->glyph;
bmp = slot->bitmap;
//glyph_width = nextp2(bmp.width);
//glyph_height = nextp2(bmp.rows);
glyph_width = bmp.width;
glyph_height = bmp.rows;
if (glyph_width > segment_size_x) {
segment_size_x = glyph_width;
}
if (glyph_height > segment_size_y) {
segment_size_y = glyph_height;
}
    }
    int font_tex_width = nextp2(num_segments_x * segment_size_x);
    int font_tex_height = nextp2(num_segments_y * segment_size_y);
    int bitmap_offset_x = 0, bitmap_offset_y = 0;
    GLubyte* font_texture_data = (GLubyte*) malloc(sizeof(GLubyte) * 2 * font_tex_width * font_tex_height);
    if (!font_texture_data) {
fprintf(stderr, "Failed to allocate memory for font texture\n");
free(font);
return NULL;
}
    // Fill font texture bitmap with individual bmp data and record appropriate size, texture coordinates and offsets for every glyph
    for(c = 0; c < 128; c++) {
if(FT_Load_Char(face, c, FT_LOAD_RENDER)) {
fprintf(stderr, "FT_Load_Char failed\n");
free(font);
return NULL;
}
slot = face->glyph;
bmp = slot->bitmap;
glyph_width = nextp2(bmp.width);
glyph_height = nextp2(bmp.rows);
div_t temp = div(c, num_segments_x);
bitmap_offset_x = segment_size_x * temp.rem;
bitmap_offset_y = segment_size_y * temp.quot;
        for (j = 0; j < glyph_height; j++) {
        for (i = 0; i < glyph_width; i++) {
        font_texture_data[2 * ((bitmap_offset_x + i) + (j + bitmap_offset_y) * font_tex_width) + 0] =
        font_texture_data[2 * ((bitmap_offset_x + i) + (j + bitmap_offset_y) * font_tex_width) + 1] =
(i >= bmp.width || j >= bmp.rows)? 0 : bmp.buffer[i + bmp.width * j];
            }
        }
        font->advance[c] = (float)(slot->advance.x >> 6);
        font->tex_x1[c] = (float)bitmap_offset_x / (float) font_tex_width;
        font->tex_x2[c] = (float)(bitmap_offset_x + bmp.width) / (float)font_tex_width;
        font->tex_y1[c] = (float)bitmap_offset_y / (float) font_tex_height;
        font->tex_y2[c] = (float)(bitmap_offset_y + bmp.rows) / (float)font_tex_height;
        font->width[c] = bmp.width;
        font->height[c] = bmp.rows;
        font->offset_x[c] = (float)slot->bitmap_left;
        font->offset_y[c] =  (float)((slot->metrics.horiBearingY-face->glyph->metrics.height) >> 6);
    }
    glBindTexture(GL_TEXTURE_2D, font->font_texture);
    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_LUMINANCE_ALPHA, font_tex_width, font_tex_height, 0, GL_LUMINANCE_ALPHA , GL_UNSIGNED_BYTE, font_texture_data);
    int err = glGetError();
    free(font_texture_data);
    FT_Done_Face(face);
    FT_Done_FreeType(library);
    if (err != 0) {
    fprintf(stderr, "GL Error 0x%x", err);
    free(font);
    return NULL;
    }
    font->initialized = true;
    return font;
}
font_t类型如下:
typedef struct{
    unsigned int font_texture;
    float pt;
    float advance[128];
    float width[128];
    float height[128];
    float tex_x1[128];
    float tex_x2[128];
    float tex_y1[128];
    float tex_y2[128];
    float offset_x[128];
    float offset_y[128];
    int initialized;
} font_t;
这样就可以使用系统的字体了,字体大小和位置:
void bbutil_measure_text(font_t* font, char* msg, float *width, float* height) {
int i, c;
if (!msg) {
return;
}
if (width) {
//Width of a text rectangle is a sum advances for every glyph in a string
*width = 0.0f;
for(i = 0; i < strlen(msg); ++i) {
c = msg[i];
*width += font->advance[c];
}
}
if (height) {
//Height of a text rectangle is a high of a tallest glyph in a string
*height = 0.0f;
for(i = 0; i < strlen(msg); ++i) {
c = msg[i];
if (*height < font->height[c]) {
*height = font->height[c];
}
}
}
}
float text_width, text_height;
bbutil_measure_text(font, notice, &text_width, &text_height);
pos_x = (width - text_width) / 2;
pos_y = height / 2;
字体的渲染:
bbutil_render_text(font, notice, pos_x, pos_y);
bbutil_render_text(font, sscore, pos_x2, pos_y2);

这一篇不是原创,借鉴了很多黑莓样例的源码,主要是为了在开发中节省时间,OpenGL方面的知识还需要学习。

posted @ 2012-08-31 11:35 寒璿 阅读(489) | 评论 (0)编辑 收藏

OpenGL入门技巧——圆形绘制与渲染

Qt和其他众多库中,圆形绘制可能并不困难,但是OpenGL不是,因为OpenGL中的一切图形都是基于面和坐标。
渲染一个正方形或者正方体并不困难,只需要指出4或6或8个点,也就是顶点数组,就能看出效果。
但是对于初学者来讲,很难想到该如何渲染一个圆。
其实,只需要增加点数,同时调用正余弦函数,创建圆形顶点数组的简单代码如下:
        int i;
/*
为了尽量近似圆形,需要360个点。
每个点有两个值:x轴和y轴,所以需要计算720个数值。
*/
for (i = 0; i < 720; i += 2) {
   // x value
   vertices[i]   = (cos(DEGREES_TO_RADIANS(i/2)) * 1);
   // y value
   vertices[i+1] = (sin(DEGREES_TO_RADIANS(i/2)) * 1);
}
之后,在渲染函数里面加上:
        glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, vertices);
颜色渲染方面还是按照常规的步骤:
glClearColor(0.5f, 0.7f, 0.9f, 1.0f);   //指定颜色
        glClear(GL_COLOR_BUFFER_BIT);   //刷出颜色
注意,绘制圆形的时候选定好绘制方式,不然可能绘制出的只是一系列点,在屏幕上显示不明显,误以为代码错误。
        glDrawArrays(GL_TRIANGLE_FAN, 0, 360);   //这个绘制方法可以理解为连续填充绘制,绘制出的是完整的圆形,不是离散的点

写这篇的原因是,我绘制圆形的时候找了很久才拼凑起有效的方法,算是半个原创吧,希望更多的人能更容易得搜索到,节省时间。

posted @ 2012-08-31 10:59 寒璿 阅读(2490) | 评论 (0)编辑 收藏

2012年6月1日 #

字符串自动机的思考——从百度之星E题谈起

2012百度之星的E题吧,因为之间没准备,卡在这道水题上,程序一直wrong answer。

昨晚找人讨论了字符串的问题,写一点思考出来。

E题的大意是:c变量名风格是小写字母带下划线,比如:long_an,Java变量名是首字母小写,其后每个单词首字母大写。

但是在判定逻辑时,我对有些情况有疑惑:

1.双下划线,__exit,file__exit

2.首字符下划线,_exit

3.末尾字符下划线,__exit_

4.java这样的变量名:bAIDU

其实,以上这些情况都是合法的,比如双下划线,在调用某些系统函数时,经常遇到。这些都是琐碎逻辑的问题。

按照水题的标准来说,应该可以对c风格变量名的字符串使用strlwr和strcmp函数,直接比较即可得出。java的变量名判定就要容易一些,E题过的人代码都比较短,大概是这样做的吧。

晚上找同学讨论,他告诉我说字符串处理都可以用自动机来实现,这是收获颇丰的一点,比如上面的E题。

起始0状态遇到大写字母直接终结,遇到小写字母和下划线进入下一个状态1,然后依次判定,这样的代码会简短和精密许多。

posted @ 2012-06-01 16:39 寒璿 阅读(238) | 评论 (1)编辑 收藏

2012年5月7日 #

为什么重载逻辑运算操作符不支持短路求值,用函数实现IF的语义错误

IF 家族的分支语句,在计算机程序设计中可以说必不可少。相信读者都很熟悉这种 IF 结构

IF 条件 THEN
    一些语句;
ELSE
    另一些语句;
END IF

这是从 ALGOL 语言一脉相承下来的,很“自然”的 IF 写法。而早期的 FORTRAN 的 IF 写法却不这么直观,而是

IF (表达式) A B C

取决于表达式的值是小于零,等于零还是大于零,分别跳到(等价于 goto)标签 A, 标签B 或者标签 C。这个 IF 隐含了三个 Goto,可以说和结构化编程的实践截然相反,降低了程序的可读性。 Fortran 首创的这个三分支跳转的 IF 饱受诟病,Fortran 77 开始支持结构化的 IF,而 Fortran 90 标准进一步宣布三分支跳转的用法已经“过时”,不支持使用。

用 XIF 子程序完成类似于 IF 的分支功能,用法是:

XIF(条件, 表达式A, 表达式B)

取决于条件的满足与否,XIF 返回表达式A 或者表达式B 的值。很快,他发现,用子程序的方法实现 XIF,在语义上并不正确。我们知道,在 Fortran 和其他高级语言中,函数参数的值在进入函数之前必须全部确定。在 XIF 这里,不难看出,不管条件满足与否,我们都先要计算表达式A 和表达式B 的值。而 IF 是个分支逻辑,从语义上来说,应该只计算满足条件的分支的值。因此,用函数来实现 IF 是不正确的 [b]。

作为一个旁注,尽管 John McCarthy 早在50多年前就发现了函数实现 IF 是语义错误的,现代的程序员还常常犯这个错误。一个值得一题的例子是 C++ 逻辑运算符重载和短路表达式的不等价性。我们都知道,在 C 语言中,逻辑与 (&&) 和逻辑或( || ) 都隶属于短路表达式,也就是说,对于 A && B 这样的表达式,如果 A 已经确定为 false,就无需计算表达式 B 的值,即 B 的计算被”短路”。以 C 为蓝本的 C++ 一方便保留了这些短路表达式,另一方面在面向对象的特性中,引入了运算符重载。具体来说,只要一个对象定义了 operator&& 成员函数,就可以进行 && 运算。乍一看,这是一个很酷的特性,可以让程序员用 A&&B 这样的数学表达式表达复杂的逻辑关系。然而,仔细想想,  A.operator&&(B) 在语义上并不等价于 C 所定义的 A&&B,原因在于 A.operator&&() 是个函数,在求值之前需要先计算 B 的值,而后者是个短路表达式,本质上相当于

    IF A:
     return True
    ELSE:
     return B
    因为短路表达式不一定会对 B 求值,这两者从语义上就是不等价的。如果 B 不是一个简单的对象,而是一个复杂表达式的时候,对 B 求值可能有副作用,而这个副作用,是写 A && B 并把它当做短路表达式的程序员所没有预见的。按照 C++ Gotcha 的说法,这很容易造成潜在的程序 Bug。实际上,C++逻辑运算符重载是一个危险的特性,很多公司的编程标准都禁止使用逻辑运算符重载。

转自 http://blog.youxu.info/

posted @ 2012-05-07 15:19 寒璿 阅读(347) | 评论 (0)编辑 收藏

仅列出标题