Created
April 26, 2009 14:57
-
-
Save ousttrue/102056 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// g++ `pkg-config cairo-ft --cflags --libs` -lglut main.cpp | |
#include <iostream> | |
#include <vector> | |
#include <algorithm> | |
#include <cassert> | |
#ifdef _MSC_VER | |
#include <windows.h> | |
#include <cairo.h> | |
#pragma comment(lib, "cairo.lib") | |
#else | |
#include <ft2build.h> | |
#include FT_FREETYPE_H | |
#include <cairo-ft.h> | |
#endif | |
#include <GL/glut.h> | |
// global variables | |
//------------------------------------------------------------// | |
int viewWidth_; | |
int viewHeight_; | |
float rotate_=0; | |
float head_=0; | |
float pitch_=0; | |
float distance_=8; | |
bool isMouseRightDown_=false; | |
int mouseX_; | |
int mouseY_; | |
#ifndef _MSC_VER | |
//------------------------------------------------------------// | |
// FreeType | |
//------------------------------------------------------------// | |
class FreeType | |
{ | |
FT_Library library_; | |
FT_Face face_; | |
int error_; | |
public: | |
void load(const char *file, int index=0) | |
{ | |
error_=FT_Init_FreeType(&library_); | |
if(error_){ | |
std::cout << "FT_Init_FreeType" << std::endl; | |
return; | |
} | |
error_=FT_New_Face(library_, file, index, &face_); | |
if(error_){ | |
std::cout << "FT_New_Face: " << file << std::endl; | |
return ; | |
} | |
} | |
~FreeType() | |
{ | |
error_=FT_Done_Face(face_); | |
assert(error_==0); | |
error_=FT_Done_FreeType(library_); | |
assert(error_==0); | |
} | |
int getError(){ return error_; } | |
FT_Face& getFace(){ return face_; } | |
}; | |
#endif | |
//------------------------------------------------------------// | |
// Cairo | |
//------------------------------------------------------------// | |
class Cairo | |
{ | |
cairo_surface_t *surface_; | |
int width_; | |
int height_; | |
int powerOfTwoWidth_; | |
int powerOfTwoHeight_; | |
int r_; | |
std::vector<unsigned char> raw_; | |
#ifndef _MSC_VER | |
FreeType ft_; | |
#endif | |
public: | |
Cairo() | |
: surface_(NULL) | |
{ | |
#ifndef _MSC_VER | |
ft_.load("mikachanfont-8.9/fonts/mikachan.ttf"); | |
#endif | |
} | |
~Cairo() | |
{ | |
cairo_surface_destroy(surface_); | |
} | |
void create(int width, int height, int r) | |
{ | |
int w=2; | |
while(w<width){ | |
w*=2; | |
} | |
int h=2; | |
while(h<height){ | |
h*=2; | |
} | |
powerOfTwoWidth_=w; | |
powerOfTwoHeight_=h; | |
width_=width; | |
height_=height; | |
r_=r; | |
raw_.resize(powerOfTwoWidth_*powerOfTwoHeight_*4); | |
surface_=cairo_image_surface_create_for_data(&raw_[0], CAIRO_FORMAT_ARGB32 | |
, powerOfTwoWidth_, powerOfTwoHeight_, powerOfTwoWidth_*4); | |
} | |
void update() | |
{ | |
assert(surface_); | |
// clear image | |
std::fill(raw_.begin(), raw_.end(), 0); | |
cairo_t *cr = cairo_create(surface_); | |
int w=width_; | |
int h=height_; | |
int r=r_; | |
// draw backgoround | |
cairo_move_to(cr, r,0); | |
cairo_line_to(cr, w-r,0); | |
cairo_curve_to(cr, w,0,w,0,w,r); | |
cairo_line_to(cr, w, h-r); | |
cairo_curve_to(cr, w,h,w,h,w-r,h); | |
cairo_line_to(cr, r,h); | |
cairo_curve_to(cr, 0,h,0,h,0,h-r); | |
cairo_line_to(cr, 0,r); | |
cairo_curve_to(cr, 0,0,0,0,r,0); | |
cairo_set_source_rgba (cr, 0, 0, 1, 0.40); | |
cairo_fill_preserve(cr); | |
cairo_set_line_width (cr, 2.0); | |
cairo_set_source_rgb (cr, 0, 0, 0); | |
cairo_stroke (cr); | |
// draw text | |
#ifdef _MSC_VER | |
cairo_select_font_face (cr, "Sans" | |
, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); | |
#else | |
cairo_set_font_face(cr | |
, cairo_ft_font_face_create_for_ft_face(ft_.getFace(), 0)); | |
#endif | |
cairo_set_font_size(cr, 24); | |
cairo_set_source_rgb(cr, 1, 1, 1); | |
char buf[1024]; | |
cairo_move_to(cr, 5, 30); | |
sprintf(buf, "茶壷回転: %0.2f", rotate_); | |
cairo_show_text(cr, buf); | |
cairo_move_to(cr, 5, 60); | |
sprintf(buf, "ヘッド: %0.2f", head_); | |
cairo_show_text(cr, buf); | |
cairo_move_to(cr, 5, 90); | |
sprintf(buf, "ピッチ: %0.2f", pitch_); | |
cairo_show_text(cr, buf); | |
cairo_destroy(cr); | |
} | |
int getWidth(){ return width_; } | |
int getHeight(){ return height_; } | |
int getTextureWidth(){ return powerOfTwoWidth_; } | |
int getTextureHeight(){ return powerOfTwoHeight_; } | |
unsigned char* getData(){ return &raw_[0]; } | |
}; | |
//------------------------------------------------------------// | |
// Sprite | |
//------------------------------------------------------------// | |
class Sprite | |
{ | |
int width_; | |
int height_; | |
GLuint id_; | |
bool isFirst_; | |
public: | |
Sprite() | |
: isFirst_(true) | |
{ | |
glGenTextures(1 , &id_); | |
} | |
void update(int width, int height, unsigned char* data) | |
{ | |
glBindTexture(GL_TEXTURE_2D, id_); | |
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); | |
if(isFirst_){ | |
// store data | |
/* | |
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA | |
, width, height | |
, GL_RGBA, GL_UNSIGNED_BYTE, data); | |
*/ | |
int w=2; | |
while(w<width){ | |
w*=2; | |
} | |
int h=2; | |
while(h<height){ | |
h*=2; | |
} | |
assert(w==width); | |
assert(h==height); | |
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA | |
, width, height, 0 | |
, GL_RGBA, GL_UNSIGNED_BYTE, data); | |
isFirst_=false; | |
width_=width; | |
height_=height; | |
} | |
else{ | |
// replace | |
glTexSubImage2D(GL_TEXTURE_2D, 0 | |
, 0, 0 , width, height | |
, GL_RGBA, GL_UNSIGNED_BYTE, data); | |
} | |
} | |
int getWidth(){ return width_; } | |
int getHeight(){ return height_; } | |
void draw(int left, int top) | |
{ | |
glEnable(GL_TEXTURE_2D); | |
glBindTexture(GL_TEXTURE_2D, id_); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); | |
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,GL_REPLACE); | |
glColor3f(1, 1, 1); | |
glMatrixMode( GL_TEXTURE ); | |
glLoadIdentity(); | |
glScalef(1.0/width_, 1.0/height_, 0); | |
glMatrixMode( GL_MODELVIEW ); | |
glBegin(GL_QUADS); | |
glTexCoord2i(0, 0); glVertex2i(left, top); | |
glTexCoord2i(0, height_); glVertex2i(left, top+height_); | |
glTexCoord2i(width_, height_); glVertex2i(left+width_, top+height_); | |
glTexCoord2i(width_, 0); glVertex2i(left+width_, top); | |
glEnd(); | |
glDisable(GL_TEXTURE_2D); | |
} | |
}; | |
// global variables | |
//------------------------------------------------------------// | |
Cairo cairo_; | |
Sprite sprite_; | |
// opengl | |
//------------------------------------------------------------// | |
void OpenGL_initialize() | |
{ | |
glClearColor(0.8, 0.8, 0.8, 1); | |
glEnable (GL_BLEND); | |
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
GLfloat afLightDiffuse[4] = {0.76f, 0.75f, 0.65f, 1.0f}; | |
glEnable (GL_LIGHTING); | |
glEnable (GL_LIGHT0); | |
glLightfv (GL_LIGHT0, GL_DIFFUSE, afLightDiffuse); | |
glEnable(GL_DEPTH_TEST); | |
} | |
void projectionView() | |
{ | |
glMatrixMode(GL_PROJECTION); | |
glLoadIdentity(); | |
gluPerspective(30.0, (double)viewWidth_ / (double)viewHeight_, 1.0, 100.0); | |
glMatrixMode(GL_MODELVIEW); | |
glLoadIdentity(); | |
//gluLookAt(3.0, 4.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); | |
glTranslatef(0, 0, -distance_); | |
glRotatef(pitch_, 1, 0, 0); | |
glRotatef(head_, 0, 1, 0); | |
} | |
void screenView() | |
{ | |
glMatrixMode(GL_PROJECTION); | |
//glPushMatrix(); | |
glLoadIdentity(); | |
glOrtho(0, viewWidth_, -viewHeight_, 0, -1.0, 1.0); | |
glMatrixMode(GL_MODELVIEW); | |
//glPushMatrix(); | |
glLoadIdentity(); | |
glScalef(1, -1, 1); | |
} | |
void drawGrid() | |
{ | |
static const int GRID_COUNT=10; | |
static const float GRID_SIZE=1.0f; | |
static const float GRID_LENGTH=GRID_COUNT*GRID_SIZE; | |
glDisable(GL_LIGHTING); | |
glBegin(GL_LINES); | |
glColor3f(0.5, 0, 0); glVertex3f(-GRID_LENGTH, 0, 0); glVertex3f(0, 0, 0); | |
glColor3f(1, 0, 0); glVertex3f(0, 0, 0); glVertex3f(+GRID_LENGTH, 0, 0); | |
glColor3f(0, 0.5, 0); glVertex3f(0, -GRID_LENGTH, 0); glVertex3f(0, 0, 0); | |
glColor3f(0, 1, 0); glVertex3f(0, 0, 0); glVertex3f(0, +GRID_LENGTH, 0); | |
glColor3f(0, 0, 0.5); glVertex3f(0, 0, -GRID_LENGTH); glVertex3f(0, 0, 0); | |
glColor3f(0, 0, 1); glVertex3f(0, 0, 0); glVertex3f(0, 0, +GRID_LENGTH); | |
// xy grid | |
glColor3f(0.5, 0.5, 0.5); | |
float gridMax=GRID_COUNT*GRID_SIZE; | |
float z=-GRID_COUNT*GRID_SIZE; | |
for(int i=-GRID_COUNT; i<=GRID_COUNT; ++i, z+=GRID_SIZE) | |
{ | |
if(i==0){ | |
continue; | |
} | |
glVertex3f(-gridMax, 0, z); | |
glVertex3f(+gridMax, 0, z); | |
} | |
float x=-GRID_COUNT*GRID_SIZE; | |
for(int i=-GRID_COUNT; i<=GRID_COUNT; ++i, x+=GRID_SIZE) | |
{ | |
if(i==0){ | |
continue; | |
} | |
glVertex3f(x, 0, -gridMax); | |
glVertex3f(x, 0, +gridMax); | |
} | |
glEnd(); | |
glEnable(GL_LIGHTING); | |
} | |
// glut callback | |
//------------------------------------------------------------// | |
void timer(int id) | |
{ | |
glutPostRedisplay(); | |
rotate_+=1; | |
glutTimerFunc(1000/60, timer, 1); | |
} | |
void display() | |
{ | |
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
// draw teapot | |
projectionView(); | |
drawGrid(); | |
glRotatef(rotate_, 0, 1, 0); | |
glColor3f(0.5, 0.5, 0.5); | |
glutSolidTeapot(1); | |
// update texture | |
cairo_.update(); | |
sprite_.update(cairo_.getTextureWidth(), cairo_.getTextureHeight(), cairo_.getData()); | |
// draw sprite | |
screenView(); | |
sprite_.draw( | |
(viewWidth_-cairo_.getWidth())/2 | |
, (viewHeight_-cairo_.getHeight())/2); | |
glutSwapBuffers(); | |
} | |
void resize(int w, int h) | |
{ | |
glViewport(0, 0, w, h); | |
viewWidth_=w; | |
viewHeight_=h; | |
} | |
void mouse(int button, int state, int x, int y) | |
{ | |
if(button==GLUT_RIGHT_BUTTON){ | |
switch(state){ | |
case GLUT_UP: | |
isMouseRightDown_=false; | |
break; | |
case GLUT_DOWN: | |
isMouseRightDown_=true; | |
break; | |
default: | |
assert(false); | |
} | |
mouseX_=x; | |
mouseY_=y; | |
} | |
} | |
void motion(int x, int y) | |
{ | |
if(isMouseRightDown_){ | |
head_+=x-mouseX_; | |
pitch_+=y-mouseY_; | |
} | |
mouseX_=x; | |
mouseY_=y; | |
} | |
// entry point | |
//------------------------------------------------------------// | |
int main(int argc, char *argv[]) | |
{ | |
// initialize | |
glutInitWindowSize(600, 600); | |
glutInit(&argc, argv); | |
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); | |
glutCreateWindow(argv[0]); | |
// after create window | |
OpenGL_initialize(); | |
// setup texture | |
cairo_.create(200, 100, 30); | |
// set callbacks | |
glutTimerFunc(1000/60, timer, 1); | |
glutDisplayFunc(display); | |
glutReshapeFunc(resize); | |
glutMouseFunc(mouse); | |
glutMotionFunc(motion); | |
glutPassiveMotionFunc(motion); | |
// main loop | |
glutMainLoop(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment