第5回目 CocoaでOpenGL

第2回目CocoaでOpenGLで作ったプログラムにテクスチャ表示を追加してみます。

プログラム作成

image.hpp

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クラスを作ります。

image.mm

#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ビット)のみ読み込むことが可能です。

プログラム修正

render.hpp

#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
これは前回と同じ。

render.cpp

#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"

ダウンロード

fileOpenGLSample_20090601.zip

前に戻る


トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS