第2回目CocoaでOpenGLで作ったプログラムにテクスチャ表示を追加してみます。
class Image { public: Image(void); ~Image(void); void Release(void); bool Load(char* name, char* type); int GetWidth(void); int GetHeight(void); unsigned char* GetBuffer(void); private: unsigned char* buffer; int width; int height; int size; private: Image(Image&); Image& operator = (Image&); };
C++形式でImageクラスを作ります。
#import <Cocoa/Cocoa.h> #import "image.hpp" Image::Image(void) :buffer(0), width(0), height(0) { } Image::~Image(void) { Release(); } void Image::Release(void) { if(buffer) { delete [] buffer; buffer = 0; width = 0; height = 0; } } bool Image::Load(char* name, char* type) { Release(); NSImage* image; NSBitmapImageRep* image_rep; NSBundle *bundle; NSString *filepath; bundle = [NSBundle mainBundle]; filepath = [bundle pathForResource:[NSString stringWithCString:name] ofType:[NSString stringWithCString:type]]; image = [[[NSImage alloc] initWithContentsOfFile: filepath] autorelease]; image_rep = [[NSBitmapImageRep alloc] initWithData : [image TIFFRepresentation]]; width = static_cast<int>([image_rep pixelsWide]); height = static_cast<int>([image_rep pixelsHigh]); buffer = new unsigned char[width * height * 4]; memcpy(buffer, static_cast<unsigned char*>([image_rep bitmapData]), width * height * 4); [image_rep release]; return true; } int Image::GetWidth(void) { return width; } int Image::GetHeight(void) { return height; } unsigned char* Image::GetBuffer(void) { return buffer; }
拡張子は.mmですがクラス自体はC++形式です、内部ではObjectiveC形式の関数を呼び出しています。 このImageクラスはC++で使用することができます。 バッファのサイズ計算の手を抜いているため画像の読み込みは アルファ情報付きのフルカラー(32ビット)のみ読み込むことが可能です。
#ifndef RENDER_HPP #define RENDER_HPP #ifdef __cplusplus extern "C" { #endif void Render_Initialize(void); void Render_Draw(void); void Render_Update(void); #ifdef __cplusplus } #endif #endif
これは前回と同じ。
#include <stdio.h> #include <math.h> #include <OpenGL/OpenGL.h> #include <OpenGL/gl.h> #include <OpenGL/glu.h> #include "image.hpp" #include "render.hpp" static int anime = 0; static int animespeed = 0; static GLuint texturenumber[2]; static float TextureWidth[2]; static float TextureHeight[2]; void Render_Initialize(void) { int i; float fovy; float depth; // OpenGL setup glLoadIdentity(); gluPerspective(30.0f, 640.0f / 480.0f, 1.0f, 10000.0f); fovy = 30.0f * 3.1415928f / 180.0f; depth = 480.0f / tanf(fovy / 2.0f) / 2.0f; gluLookAt(0.0f, 0.0f, depth, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f); glPolygonMode(GL_FRONT, GL_FILL); glPolygonMode(GL_BACK, GL_FILL); glDisable(GL_CULL_FACE); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glEnable(GL_TEXTURE_2D); // Texture load glGenTextures(2, texturenumber); Image image; for(i = 0; i < 2; i ++) { if(i == 0) { image.Load("fighter1", "png"); } else { image.Load("fighter2", "png"); } TextureWidth[i] = static_cast<float>(image.GetWidth()); TextureHeight[i] = static_cast<float>(image.GetHeight()); glBindTexture(GL_TEXTURE_2D, texturenumber[i]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.GetWidth(), image.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, image.GetBuffer()); glBindTexture(GL_TEXTURE_2D, 0); } } void DrawRectangle(int texture, float x1, float y1, float x2, float y2, float z, float texture_x, float texture_y, float texture_width, float texture_height) { float s1; float t1; float s2; float t2; s1 = (texture_x - 0.5f) / TextureWidth[texture]; t1 = (texture_y - 0.5f) / TextureHeight[texture]; s2 = (texture_x + texture_width - 0.5f) / TextureWidth[texture]; t2 = (texture_y + texture_height - 0.5f) / TextureHeight[texture]; glPushMatrix(); glRotatef(0.0f, 0.0f, 0.0f, 1.0f); glBindTexture(GL_TEXTURE_2D, texturenumber[texture]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glBegin(GL_QUADS); glColor3d(1.0f, 1.0f, 1.0f); glTexCoord2f(s1, t1); glVertex3f(x1, y1, z); glTexCoord2f(s2, t1); glVertex3f(x2, y1, z); glTexCoord2f(s2, t2); glVertex3f(x2, y2, z); glTexCoord2f(s1, t2); glVertex3f(x1, y2, z); glEnd(); glPopMatrix(); } void Render_Draw(void) { int anime_table[8] = {0, 1, 2, 3, 4, 3, 2, 1}; glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); DrawRectangle(0, -128.0f, 0.0f, -128.0f + 48.0f, -48.0f, 0.0f, static_cast<float>(anime_table[anime]) * 48.0f, 0.0f, 48.0f, 48.0f); DrawRectangle(1, 128.0f, 0.0f, 128.0f + 48.0f, -48.0f, 0.0f, static_cast<float>(anime_table[anime]) * 48.0f, 0.0f, 48.0f, 48.0f); glFlush(); } void Render_Update(void) { animespeed ++; if(animespeed > 30) { anime ++; if(anime > 7) { anime = 0; } animespeed = 0; } }
Render_InitializeではOpenGLの初期化、2枚のテクスチャの読み込みをしています。 Render_Drawでは画面の左右にテクスチャを表示しています。 左はfighter1.png、右はfighter2.pngを表示。 各テクスチャは256x64の大きさで48x48のキャラクタが描かれています。 それをアニメーション表示しています。 DrawRectangleはテクスチャの一部を切り取り画面に表示する関数です。 MacBookの場合はなぜか glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); の2行を省略するとテクスチャが表示されなくなります。謎。 Render_Updateはアニメーションのコマ数を制御しています。
#ref(): File not found: "OpenGLSample_20090601.jpg" at page "CocoaでOpenGL3"