OpenGL+FreeType 模仿黑客帝國數碼雨 V2.0

動圖請戳: 黑客帝國數碼-vicyang

但總算滿足了多年前的中二病需求。 V3.0 還在製作中

// Matrix.c, v2.5n// CodeBy: 523066680n// 2016-11nn#include <GL/glut.h>n#include <unistd.h>n#include <stdio.h>n#include <time.h>nn#include <ft2build.h>n#include <freetype/ftbbox.h>n#include <freetype/ftoutln.h>n#include FT_FREETYPE_Hnn#define SIZE_X 500n#define SIZE_Y 500n#define N_RAIN 50n#define N_TEXT 30nnint winID;nFT_Library library;nFT_Face face;nnFT_GlyphSlot slot;nFT_Error error;nFT_Outline outline;nFT_BBox box;nnGLUtesselator *tobj;nnstatic double vtx[5000][3];nstatic int vtx_contours[100];nstatic int Vi;nstatic int vtx_ctsi;nstatic float red = 0.0;nstatic int PARTS = 3.0; //曲線細分程度nstatic long code;nntypedef structn{n float x;n float y;n}npoint;nnvoid GetDatafromOutline(void);nint LoadGlyph(long symbol);nnfloat angx = 0.0;nfloat angy = 0.0;nfloat angz = 0.0;nfloat progress[N_RAIN];nfloat speed[N_RAIN];nfloat bright[N_RAIN];nfloat RXlist[N_RAIN];nfloat RYlist[N_RAIN];nfloat RZlist[N_RAIN];n//char uni[] = " abcdefghijklmnopqrstuvwxyz,ABCDEFGHIJKLMNOPQRSTUVWXYZ~!@#$%&*+-={}[];<>,.?";nnlong uni[] = {n 32, 30721, 26080, 30721, 20197, 21450, 20154, 20043, 30721, 65292,n22825, 20043, 36947, 65292, 25439, 26377, 20313, 32780, 34917, 19981,n36275, 65292, 26159, 25925, 34394, 32988, 23454, 65292, 19981, 36275,n32988, 26377, 20313, 12290, 20854, 24847, 21338, 65292, 20854, 29702,n22885, 65292, 20854, 36259, 28145, 65292, 22825, 22320, 20043, 35937,n20998, 65292, 38452, 38451, 20043, 20505, 21015, 65292, 21464, 21270,n20043, 30001, 34920, 65292, 27515, 29983, 20043, 20806, 24432, 65292,n19981, 35851, 32780, 36951, 36857, 33258, 21516, 65292, 21247, 32422,n32780, 24189, 26126, 26031, 22865, 65292, 31293, 20854, 35328, 26377,n24494, 65292, 39564, 20043, 20107, 19981, 24530, 65292, 35802, 21487,n35859, 33267, 36947, 20043, 23447, 65292, 22857, 29983, 20043, 22987,n30691, 12290, 20551, 33509, 22825, 26426, 36805, 21457, 65292, 22937,n35782, 29572, 36890, 65292, 25104, 35851, 34429, 23646, 20046, 29983,n30693, 65292, 26631, 26684, 20134, 36164, 20110, 27835, 35757, 65292,n26410, 23581, 26377, 34892, 19981, 30001, 36865, 65292, 20986, 19981,n30001, 20135, 32773, 20134, 12290, 28982, 21051, 24847, 30740, 31934,n65292, 25506, 24494, 32034, 38544, 65292, 25110, 35782, 22865, 30495,n35201, 65292, 21017, 30446, 29275, 26080, 20840, 65292, 25925, 21160,n21017, 26377, 25104, 65292, 29369, 39740, 31070, 24189, 36190, 65292,n32780, 21629, 19990, 22855, 26480, 65292, 26102, 26102, 38388, 20986,n28937, 12290, 86, 73, 67, 26472n};nstatic int n_char;nstatic int arr[N_RAIN][N_TEXT];nstatic float alpha[N_RAIN][N_TEXT];nnvoid beginCallback(GLenum which)n{n glBegin(which);n}nnvoid endCallback(void)n{n glEnd();n}nnvoid errorCallback(GLenum errorCode)n{n const GLubyte *estring;nn estring = gluErrorString(errorCode);n fprintf(stderr, "Tessellation Error: %sn", estring);n exit(0);n}nnvoid vertexCallback(GLdouble *vertex)n{n //const GLdouble *pointer;n //pointer = (GLdouble *) vertex;n glNormal3f(0.0, 0.0, 1.0);n glVertex3dv(vertex);n}nnvoid CALLBACK combineCallback(GLdouble coords[3], GLdouble *data[4],n GLfloat weight[4], GLdouble **dataOut )n{n GLdouble *vertex;n vertex = (GLdouble *) malloc(3 * sizeof(GLdouble));nn vertex[0] = coords[0];n vertex[1] = coords[1];n vertex[2] = coords[2];n *dataOut = vertex;n}nnvoid PointOnQuadBeizer(point cp[3], double t, double *vt )n{n double cx, bx, ax, cy, by, ay;nn ax = cp[1].x - cp[0].x;n ay = cp[1].y - cp[0].y;nn bx = cp[2].x - cp[1].x;n by = cp[2].y - cp[1].y;nn cx = (bx * t + cp[1].x) - (ax * t + cp[0].x);n cy = (by * t + cp[1].y) - (ay * t + cp[0].y);nn vt[0] = cx*t + (ax * t + cp[0].x);n vt[1] = cy*t + (ay * t + cp[0].y);n vt[2] = 0.0;n}nnvoid display(void)n{n int errcode;n int bgn;n int i, j;n int start;n // 清理顏色緩衝區n glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );n glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);nn glPushMatrix();n glRotatef(angy, 0.0, 0.5, 0.0);n glRotatef(angx, 1.0, 0.0, 0.0);n glRotatef(angz, 0.0, 0.0, 1.0);nn glColor3f(0.3, 0.8, 0.3);nn for (int m = 0; m < N_RAIN; m++)n {n glPushMatrix();n n //glTranslatef(-12000.0 + RXlist[m], 5000.0 + RYlist[m], RZlist[m]);n glTranslatef(RXlist[m], RYlist[m]+6000.0, RZlist[m]);n glRotatef( (float)m/(float)N_RAIN * 60.0 , 0.0, 1.0, 0.0 );n for (int n = 0; n < N_TEXT ; n++ )n {n //向下移位n glTranslatef(0.0, -1000.0, 0.0);nn //Matrix for scalen glPushMatrix(); n // glRotatef(90.0, 0.0, 0.0, 1.0);n if ( n == bright[m] )n {n glScalef(1.1, 1.1, 1.1);n glColor4f(0.2, 0.8, 0.2, 1.0);n }n elsen {n glColor4f(0.1, (float)n/(float)N_TEXT+0.5, 0.5, alpha[m][n] );n }nn alpha[m][n] -= 0.03;n glCallList( arr[m][n] );n glPopMatrix();n } n glPopMatrix();nn }n glPopMatrix();nn // glPushMatrix();n // glTranslatef(-15000.0, 15000.0, 0);n // glColor3f(0.3, 0.7, 0.5);n // for (i = 3; i >=0; i--)n // {n // glCallList( n_char - i );n // glTranslatef(1000.0, 0.0, 0.0);n // }n // glPopMatrix();nn glutSwapBuffers();n}nnvoid idle(void)n{n usleep(30000);n angy += 0.3;n //angz += 1.0;nn int r;n for (int i = 0; i < N_RAIN; i++ )n {n if ( progress[i] < n_char )n {n progress[i] += speed[i];n arr[i][ (int)progress[i] % N_TEXT ] = (int)progress[i];n alpha[i][ (int)progress[i] % N_TEXT ] = 1.0;n }n elsen {n progress[i] = 1.0;n RYlist[i] = (float)(rand() % 20 - 10) * 1000.0;n }n bright[i] = (int)progress[i] % N_TEXT;n }nnn glutPostRedisplay();n}nnvoid reshape(int Width, int Height)n{n const float fa = 20000.0;n const float half = 8000.0;nn float w = (float)Width;n float h = (float)Height;nn glViewport(0, 0, Width, Height); //視口範圍n glMatrixMode(GL_PROJECTION); // 投影視圖矩陣n glLoadIdentity();n //glOrtho(-half, half, -half, half, 0.0, 40000.0);n gluPerspective(80.0, w/h, 100.0, 40000.0);n glMatrixMode(GL_MODELVIEW); // 模型視圖矩陣n glLoadIdentity();n gluLookAt(0.0,0.0,fa, 0.0,0.0,0.0, 0.0,1.0,fa);n // 觀察點, 朝向的坐標, 觀察點向上坐標n}nnvoid keypress(unsigned char key, int mousex, int mousey)n{n int errcode;n switch (key)n {n case q:n case Q:n glutDestroyWindow(winID);n exit(0);n break; n case w:n case W:n angx += 1.0;n glutPostRedisplay();n break;n case s:n case S:n angx -= 1.0;n glutPostRedisplay();n break;n case a:n case A:n angz += 1.0;n glutPostRedisplay();n break;n case d:n case D:n angz -= 1.0;n glutPostRedisplay();n break;n case j:n case J:n angy += 2.0;n glutPostRedisplay();n break;n case k:n case K:n angy -= 2.0;n glutPostRedisplay();n break;n }n}nnvoid init(void)n{n int errcode;n Vi = 0;n vtx_ctsi = 0;n int bgn;n int next;n int base; //for Display Listnn //glutFullScreen();n srand( time(NULL) );n glClearColor(0.0, 0.0, 0.0, 0.0);n glLineWidth( 1.0 );n glPointSize( 2.0 );n glEnable(GL_BLEND);n glEnable(GL_DEPTH_TEST);n glEnable(GL_POINT_SMOOTH);n glEnable(GL_LINE_SMOOTH);n //glEnable(GL_POLYGON_SMOOTH);nn tobj = gluNewTess();n //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);n gluTessCallback(tobj, GLU_TESS_VERTEX, glVertex3dv);n gluTessCallback(tobj, GLU_TESS_BEGIN, beginCallback);n gluTessCallback(tobj, GLU_TESS_END, endCallback);n gluTessCallback(tobj, GLU_TESS_ERROR, errorCallback);n gluTessCallback(tobj, GLU_TESS_COMBINE,combineCallback);n //gluTessProperty(tobj, GLU_TESS_BOUNDARY_ONLY, GL_TRUE);n gluTessProperty(tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);n n for (int i = 0; i < N_RAIN; i++)n {n //製造參差效果n RXlist[i] = (float)(rand() % 20 - 10) * 1500.0;n RYlist[i] = (float)(rand() % 20 - 10) * 500.0;n RZlist[i] = (float)(rand() % 20 - 10) * 1000.0;nn //隨機進度、遞進速度n progress[i] = (float) ((rand()%50 + 1) * 1);n speed[i] = (float) ( rand()%5 + 2) / 10.0;n n //填入空白;顯示列表的索引,從1開始n for (int j = 0; j < N_TEXT; j++)n {n arr[i][j] = 1;n alpha[i][j] = 1.0;n }n }nn // 創建顯示列表n n_char = sizeof(uni)/sizeof(uni[0]);n base = glGenLists( n_char );nn //每個字元的點數據(已經對曲線求值了的)整理到 glyph 數組n for (int code = 0; code < n_char; code++ )n {n errcode = LoadGlyph( uni[code] );n //處理坐標、曲線數據到vtx數組n GetDatafromOutline();nn glNewList(base+code, GL_COMPILE);n gluTessBeginPolygon(tobj, NULL);n for (int cti = 0; cti < vtx_ctsi ; cti++ )n {n gluTessBeginContour(tobj);n int pti = (cti == 0 ? 0 : vtx_contours[cti-1] + 1 );n for (; pti <= vtx_contours[cti]; pti++ )n {n gluTessVertex(tobj, vtx[pti], vtx[pti] );n }n gluTessEndContour(tobj); n }n gluTessEndPolygon(tobj);nn for (int cti = 0; cti < vtx_ctsi; cti++ )n {n glBegin(GL_QUAD_STRIP);n int pti = (cti == 0 ? 0 : vtx_contours[cti-1] + 1 );n for (; pti <= vtx_contours[cti]; pti++ )n {n glVertex3f( vtx[pti][0], vtx[pti][1], 0.0 );n glVertex3f( vtx[pti][0], vtx[pti][1], -20.0 );n }n glEnd();n }nn glEndList();n }nn}nnvoid ftinit(void)n{n char* filename;n filename = "C:/windows/fonts/STXingKa.ttf";nn error = FT_Init_FreeType( &library );n error = FT_New_Face( library, filename, 0, &face ); /* create face object */n}nnint LoadGlyph(long symbol)n{n //這裡可以是unicode編碼值,字體必須支持才行n FT_UInt index = FT_Get_Char_Index(face, symbol);nn if (index <= 0)n {n printf("Error in %dn", symbol);n return 1;n }n elsen {n //printf("no problem in %dn", symbol);n FT_Error error = FT_Load_Glyph(face,n index,n FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);n slot = face->glyph;n outline = slot->outline;n FT_Outline_Get_BBox( &outline, &box );n return 0;n }n}nn//Function by 523066680nvoid GetDatafromOutline(void)n{n Vi = 0;n vtx_ctsi = 0;n int bgn;n int next;n point lastpt;n point cp[3];nn for (int cts = 0; cts < outline.n_contours; cts++ )n {n bgn = ( cts == 0 ? 0 : outline.contours[cts-1] + 1 );nn for (int i = bgn; i <= outline.contours[cts] ; i++)n {n //i==終點時,next回到某個輪廓的起點n next = ( i == outline.contours[cts] ? bgn : i+1 );nn if ( outline.tags[i] == 0 )n {n cp[1].x = (double)outline.points[i].x;n cp[1].y = (double)outline.points[i].y;nn if ( outline.tags[i-1] == 1 ) //1, 0n {n cp[0].x = (double)outline.points[i-1].x;n cp[0].y = (double)outline.points[i-1].y;nn if (outline.tags[next] == 1) //1, 0, 1 n {n cp[2].x = (double) outline.points[next].x;n cp[2].y = (double) outline.points[next].y;nn for (float i = 0.0; i < PARTS; i+=1.0 )n {n PointOnQuadBeizer(cp, i/PARTS, vtx[Vi]);n Vi++;n }n }n else //1, 0, 0n {n cp[2].x = (double)(outline.points[i].x + outline.points[next].x)/2;n cp[2].y = (double)(outline.points[i].y + outline.points[next].y)/2;nn for (float i=0.0; i <PARTS; i+=1.0 )n {n PointOnQuadBeizer(cp, i/PARTS, vtx[Vi]);n Vi++;n }n }n }n else //0, 0n {n //起點為上一段曲線的終點 而上一段曲線終點可能是計算出來的n cp[0].x = lastpt.x;n cp[0].y = lastpt.y;nn if ( outline.tags[next] == 0 ) //0, 0, 0n {n cp[2].x = (double)(outline.points[i].x + outline.points[next].x)/2 ;n cp[2].y = (double)(outline.points[i].y + outline.points[next].y)/2 ;nn for (float i=0.0; i < PARTS; i+=1.0 )n {n PointOnQuadBeizer(cp, i/PARTS, vtx[Vi]);n Vi++;n }n }n else //0, 0, 1n {n cp[2].x = (double)outline.points[next].x ;n cp[2].y = (double)outline.points[next].y ;nn for (float i=0.0; i < PARTS; i+=1.0 )n {n PointOnQuadBeizer(cp, i/PARTS, vtx[Vi]);n Vi++;n }n }n }n lastpt.x = cp[2].x;n lastpt.y = cp[2].y;n }n elsen {n //直線線段 只記錄當前點n if ( outline.tags[next] == 1 ) //1, 1n { n vtx[Vi][0] = outline.points[i].x;n vtx[Vi][1] = outline.points[i].y;n vtx[Vi][2] = 0.0;n Vi++;n }n }n }nn vtx_contours[vtx_ctsi] = Vi-1;n vtx_ctsi++;n }n //printf("vtx_ctsi: %d, nvtx: %dn", vtx_ctsi, Vi);n}nnint main( int argc, char** argv )n{nn ftinit();n LoadGlyph(code);n GetDatafromOutline();nn printf("font-name: %s, style: %sn", face->family_name, face->style_name);n printf("n_faces:%d, face_index:%d, face_flags:%d, style_flags:%dn",n face->num_faces,n face->face_index,n face->face_flags,n face->style_flagsn );nn printf("numglyphs :%d, fixed_sizes: %d, generic: %dn", n face->num_glyphs, n face->num_fixed_sizes, n face->genericn );nn printf("bbox x: %d - %d, y: %d - %d, ascender %d, descender %d, height %d n", n face->bbox.xMin,face->bbox.xMax,face->bbox.yMin,face->bbox.yMax,n face->ascender, n face->descender,n face->heightn );nn printf("n_contours: %d n n_points: %d n flags: %dn", n outline.n_contours,n outline.n_points,n outline.flagsn );n n for (int i=0; i<outline.n_contours; i++ )n {n printf("Contour %d: %dn", i, outline.contours[i]);n }n printf("n");nn // for (int i = 0; i<outline.n_points ; i++)n // {n // printf("%2d : %4d %4d %dn",n // i,n // outline.points[i].x,n // outline.points[i].y,n // outline.tags[i]n // );n // }nn glutInit(&argc, argv);n //顯示模式 雙緩衝 RGBAn glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA |GLUT_DEPTH | GLUT_MULTISAMPLE );n glutInitWindowSize(SIZE_X, SIZE_Y); //窗口大小n glutInitWindowPosition(200, 200); //位置n winID = glutCreateWindow("ViANG_5230"); //窗口句柄n init();n glutDisplayFunc(display); //顯示n glutKeyboardFunc(keypress); //按鍵事件響應n glutReshapeFunc(reshape); //窗口事件響應n glutIdleFunc(idle); //閑時回調函數n glutMainLoop(); //開始主循環nn FT_Done_Face ( face );n FT_Done_FreeType( library );nn return 0;n}n

推薦閱讀:

卡通渲染及其相關技術
神奇的深度圖:複雜的效果,不複雜的原理
基於物理的渲染—基於球面調和基的實時全局光照明
電影工業中的流體模擬(四)- 納維斯托克斯方程(下)

TAG:OpenGL | 计算机图形学 | FreeType |