ネタが切れたのでぶっぱ

C++コードは278行らしい。入力についてはキーコンフィグなしの暫定のもの。もはや1ファイルでいけるだろうということで全部グローバルスコープです。のびのびしてていいね(笑)。最終的にはサウンド・乱数関係の関数のエクスポートとかが増える予定。
VisualC++2008です。2010は特にC++0x対応でぜひとも導入したいところなのですが、ベータ版には手を出してません。こういうのってベータ版を使って移行を進めておいた方がいいのかなあ。tr1をなるべく使うようにはしているものの、shared_ptrとarrayくらいしか使っていないような気がします(笑)。4/12に出るとか?日本でも出るの?学生だとなんかごちゃごちゃしたので無料で手に入る気がするけどよくわかんないしめんどくさいからまたアカデミック版に数万円ぶっぱする気がする。エディション機能比較表でExpressEditionと比べて使ってる機能がなかった気もするけど。
dx9libは当初UNICODEでハードコーディングされていましたが(最近のDirectX SDKのサンプルがそうし始めたため)、Luaが思いっきりcharだったためひどい目にあい、必死で正規表現を駆使して_T()両対応に直しました。結構前の話です。もうMS推奨に従うのはやめます(分かってたのに…)。DirectX9使う時点で非推奨だっつーの。


basuke.cpp

#include "stdafx.h"
#include <lua.hpp>
#pragma comment(lib, "lua5.1.lib")

using std::tr1::shared_ptr;
using std::tr1::array;
using dx9lib::debug;

struct FrameInput {
	bool up, down, left, right;
	bool a, b, c, d;
};

void translateInput(FrameInput &out, BYTE (&keys)[256]) {
	out.up    = keys[DIK_UP]    != 0;
	out.down  = keys[DIK_DOWN]  != 0;
	out.left  = keys[DIK_LEFT]  != 0;
	out.right = keys[DIK_RIGHT] != 0;
	out.a     = keys[DIK_Z]     != 0;
	out.b     = keys[DIK_X]     != 0;
	out.c     = keys[DIK_C]     != 0;
	out.d     = keys[DIK_V]     != 0;
}

void addPadInput(FrameInput &out, const DIJOYSTATE &state) {
	const int TH = dx9lib::DInput::AXIS_RANGE / 2;
	out.up    |= state.lY < -TH;
	out.down  |= state.lY >  TH;
	out.left  |= state.lX < -TH;
	out.right |= state.lX >  TH;
	out.a     |= state.rgbButtons[0] != 0;
	out.b     |= state.rgbButtons[1] != 0;
	out.c     |= state.rgbButtons[2] != 0;
	out.d     |= state.rgbButtons[3] != 0;
}

shared_ptr<dx9lib::ResourceLoader> g_loader;
shared_ptr<dx9lib::DGraphics> g_pdg;
shared_ptr<dx9lib::DInput>    g_pdi;
shared_ptr<dx9lib::DSound>    g_pds;
const size_t TEXTURE_MAX = 256;
array<shared_ptr<dx9lib::Texture>, TEXTURE_MAX> g_pTextures;

/* Lua */
class LuaError : public std::runtime_error {
public:
	LuaError(const std::string &msg) : std::runtime_error(msg) {}
	static void check(lua_State *L, int result) {
		if (result != 0) {
			throw LuaError(lua_tostring(L, -1));
		}
	}
};

void lua_deleter(lua_State *L) {
	lua_close(L);
}

int atpanic(lua_State *L) {
	throw LuaError(lua_tostring(L, 1));
}

void check_at_exit() {
	for (size_t i = 0; i < g_pTextures.size(); i++) {
		if (g_pTextures[i]) {
			debug.printf("Image handle [%u] is not unloaded\n", i);
		}
	}
}

/* Lua Export */
// trace(values...)
int le_trace(lua_State *L) {
	int n = lua_gettop(L);
	for (int i = 1; i <= n; i++) {
		lua_getglobal(L, "tostring");
		lua_pushvalue(L, i);
		lua_pcall(L, 1, 1, 0);
		const char *str = lua_tostring(L, -1);
		debug.print(str);
		lua_pop(L, 1);
	}
	debug.println("");
	return 0;
}

bool g_quitFlag = false;
int le_quit(lua_State *L) {
	g_quitFlag = true;
	return 0;
}

// number load_image(string filename)
int le_loadimage(lua_State *L) {
	if (!lua_isstring(L, 1)) {
		return luaL_error(L, "filename is not string");
	}
	int index = -1;
	for (size_t i = 0; i < g_pTextures.size(); i++) {
		if (!g_pTextures[i]) {
			index = i;
			break;
		}
	}
	if (index == -1) {
		return luaL_error(L, "Image count over");
	}
	try {
		g_pTextures[index] = g_pdg->createTexture(*g_loader, lua_tostring(L, 1));
	} catch(const dx9lib::Dx9libError &e) {
		return luaL_error(L, e.what());
	}
	lua_pushinteger(L, index);
	return 1;
}

// void unload_image(number handle)
int le_unloadimage(lua_State *L) {
	if (!lua_isnumber(L, 1)) {
		return luaL_error(L, "Image handle is not number");
	}
	int index = lua_tointeger(L, 1);
	if (!g_pTextures.at(index)) {
		return luaL_error(L, "Invalid image handle");
	}
	g_pTextures[index].reset();
	return 0;
}

// void draw_image(number handle, number x, number y)
int le_drawimage(lua_State *L) {
	if (!lua_isnumber(L, 1)) {
		return luaL_error(L, "Image handle is not number");
	}
	if(!lua_isnumber(L, 2) || !lua_isnumber(L, 3)) {
		return luaL_error(L, "(x, y) is not number");
	}
	int index = lua_tointeger(L, 1);
	int x = lua_tointeger(L, 2);
	int y = lua_tointeger(L, 3);
	if (!g_pTextures.at(index)) {
		return luaL_error(L, "Invalid image handle");
	}
	g_pdg->drawSprite(g_pTextures[index], x, y);
	return 0;
}

// void draw_image_by_center(number handle, number x, number y, [number rotation])
int le_drawimagebycenter(lua_State *L) {
	if (!lua_isnumber(L, 1)) {
		return luaL_error(L, "Image handle is not number");
	}
	if(!lua_isnumber(L, 2) || !lua_isnumber(L, 3)) {
		return luaL_error(L, "(x, y) is not number");
	}
	int index = lua_tointeger(L, 1);
	int x = lua_tointeger(L, 2);
	int y = lua_tointeger(L, 3);
	double rot = lua_isnumber(L, 4) ? lua_tonumber(L, 4) : 0.0;
	if (!g_pTextures.at(index)) {
		return luaL_error(L, "Invalid image handle");
	}
	g_pdg->drawSpriteByCenter(g_pTextures[index], x, y, static_cast<float>(rot));
	return 0;
}

// number get_fps()
int le_getfps(lua_State *L) {
	lua_pushnumber(L, g_pdg->getFPS());
	return 1;
}

const luaL_Reg EXPORT_FUNCTIONS_GLOBAL[] = {
	{"trace", le_trace},
	{"quit", le_quit},
	{NULL, NULL}
};
const luaL_Reg EXPORT_FUNCTIONS_DG[] = {
	{"load_image", le_loadimage},
	{"unload_image", le_unloadimage},
	{"draw_image", le_drawimage},
	{"draw_image_by_center", le_drawimagebycenter},
	{"get_fps", le_getfps},
	{NULL, NULL}
};
/* end of Lua Export */

int APIENTRY WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

	debug.setFile("log.txt");

	try{
		debug.println("Initializing window and DirectX...");
		dx9lib::Window window("GameWindowClass", "basuke", LoadIcon(NULL, IDI_APPLICATION), 640, 480);
		g_loader.reset(new dx9lib::FileResourceLoader);
		g_pdg.reset(new dx9lib::DGraphics(window.getHWND(), false, true, true, 640, 480));
		g_pdi.reset(new dx9lib::DInput(window.getHWND()));
		g_pds.reset(new dx9lib::DSound(window.getHWND()));
		window.setVisible(true);

		debug.println("Initializing Lua...");
		shared_ptr<lua_State> L(luaL_newstate(), lua_deleter);
		lua_atpanic(L.get(), atpanic);
		luaL_openlibs(L.get());
		luaL_register(L.get(), "_G", EXPORT_FUNCTIONS_GLOBAL);
		luaL_register(L.get(), "dg", EXPORT_FUNCTIONS_DG);
		debug.println("OK");
		LuaError::check(L.get(), luaL_dofile(L.get(), "main.lua"));
		// call_lua on_load()
		lua_getglobal(L.get(), "on_load");
		LuaError::check(L.get(), lua_pcall(L.get(), 0, 0, 0));

		while (window.processMessage()) {
			FrameInput frameInput;
			g_pds->processFrame();
			g_pdi->processFrame();
			BYTE keys[256];
			g_pdi->getKeys(keys);
			translateInput(frameInput, keys);
			for (int i = 0; i < g_pdi->getPadCount(); i++) {
				DIJOYSTATE padState;
				g_pdi->getPadState(padState, i);
				addPadInput(frameInput, padState);
			}

			// call_lua on_frame(input)
			lua_getglobal(L.get(), "on_frame");
			lua_createtable(L.get(), 0, 8);
			lua_pushboolean(L.get(), frameInput.up);
			lua_setfield(L.get(), -2, "up");
			lua_pushboolean(L.get(), frameInput.down);
			lua_setfield(L.get(), -2, "down");
			lua_pushboolean(L.get(), frameInput.left);
			lua_setfield(L.get(), -2, "left");
			lua_pushboolean(L.get(), frameInput.right);
			lua_setfield(L.get(), -2, "right");
			lua_pushboolean(L.get(), frameInput.a);
			lua_setfield(L.get(), -2, "a");
			lua_pushboolean(L.get(), frameInput.b);
			lua_setfield(L.get(), -2, "b");
			lua_pushboolean(L.get(), frameInput.c);
			lua_setfield(L.get(), -2, "c");
			lua_pushboolean(L.get(), frameInput.d);
			lua_setfield(L.get(), -2, "d");
			LuaError::check(L.get(), lua_pcall(L.get(), 1, 0, 0));
			if (g_quitFlag) {
				break;
			}

			g_pdg->begin(D3DCOLOR_XRGB(0, 0, 255));

			// call_lua on_draw()
			lua_getglobal(L.get(), "on_draw");
			LuaError::check(L.get(), lua_pcall(L.get(), 0, 0, 0));

			g_pdg->end();
		}

		// call_lua on_unload()
		lua_getglobal(L.get(), "on_unload");
		LuaError::check(L.get(), lua_pcall(L.get(), 0, 0, 0));

		debug.println("Exiting successfully");

		check_at_exit();

		return window.getExitCode();
	} catch (const dx9lib::Dx9libError &e) {
		debug.print("Error: ");
		debug.println(e.what());
	} catch (const std::runtime_error &e) {
		debug.print("Error: ");
		debug.println(e.what());
	}
	return 0;
}

stdafx.h

#pragma once

#include <dx9lib.h>

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>