Skip to content

Instantly share code, notes, and snippets.

@ousttrue
Created April 26, 2009 14:57
Show Gist options
  • Save ousttrue/102056 to your computer and use it in GitHub Desktop.
Save ousttrue/102056 to your computer and use it in GitHub Desktop.
// 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