2012年06月18日

やっぱりブラウザ

お久しぶりです。
引越し先の庭のプランターで育てている万能ねぎが、
そろそろ食べごろになってきて料理のレパートリーを広げようと
目下画策中のgood sun晴れこと山口です。

ここ最近私の書いたブログではJavaScriptを中心に紹介していますが、
今回もJavaScriptとブラウザに関係した情報を紹介したいと思います。

まず始めに皆さんはOpenCLという技術をご存知でしょうか?
OpenCLはGPUやマルチコアCPU等の資産を
ハードウェアを意識することなく
C言語ライクなプログラム言語によって並列コンピューティングに利用する技術です。
類似した技術としてNVIDIAのCUDAやMicrosoft DirectComputeが有名ですね。

このOpenCLにも実はブラウザ用の実装系が存在しています。
その名もWebCL!!わーい(嬉しい顔)
なんのひねりもありません。
このWebCLですが、WebGLと同じくJavaScriptからOpenCLを利用する事が出来ます。

その実力たるやなんとJavaScriptの100倍の速度で処理をさせることが出来るという、
超パワフルなテクノロジーであります。
このパワフルさに思わず想像してしまいました。
これでブラウザ上で高速に大量の物理シミュレーションが行えたり、
高速なレイトレースレンダラーが作れたりする時代がやってきたと!

しかし、残念ながら現在ブラウザをインストールするだけでは利用できず、
プラグインが必要な為まだまだ一般的ではありません。
現に今回紹介するに当たり、
WebCLが動く環境を作ろうとしてみましたが上手くいきませんでした。(リベンジ予定です!パンチ)

今回はこの辺で失礼して、
次回もまたブラウザの素晴らしさを紹介できたらと思います。
では!手(パー)

posted by 管理人 at 21:46 | プログラミング

2012年06月12日

動作確認の方法

こんにちは、ナカムラです。

突然ですがみなさん、プログラムを作成した後の動作確認、どうやってますか?
1度起動してみて、画面上で変な動きをしてなかったら、決定
残念ながら、それでは充分な動作確認ができたとは言えせん…もうやだ〜(悲しい顔)
今回は、動作確認の方法について、いくつか紹介してみます。

***

例えば、C言語で次のような関数を作成したとしましょう。


void function( int a, int b )
{
int value; // 未初期化

if( a == 0 ) {
value = 0;
}
if( b == 1 ) {
value += 5;
}

return value;
}


まずは、全ての命令が実行されて問題が無いかどうかを確認する事を目標にしてみましょう。
上の例で言うと a == 0 かつ b == 1 の場合の動作確認さえ行えば、この関数内の全ての命令を実行できた事になります。
案外、この1回の動作確認だけで済ませる人、多いんじゃないでしょうか?
でも、それだけだと不十分な気がしませんかexclamation&question
そうです。条件が偽になって、命令がスキップされたときの動作確認をする必要があります。
現に、上の例では変数 value が宣言時に初期化されていませんので、if 文が両方偽だった場合に、不定値を返してしまう事になりますよねバッド(下向き矢印)

***

先ほどは、命令に着目した動作確認でミスをしてしまいました。
次は全ての分岐に着目し、真と偽両方の処理を通る事を意識して動作確認してみましょう。
a == 0 かつ b == 1
a != 0 かつ b != 1
この2通りの動作確認さえ行えば、if 文の中を通るケースと通らないケース、両方を確認する事が出来ます。
今回の例なら、この動作確認によって、変数の未初期化が存在する事が分かった事でしょうグッド(上向き矢印)

では更に念入りな動作確認方法はあるのでしょうか?
それは、次の4通りの条件全てをチェックする方法です。
a == 0 かつ b == 1
a == 0 かつ b != 1
a != 0 かつ b == 1
a != 0 かつ b != 1
これなら条件式の組み合わせ全てをチェックする事になるので、
「1つ目の if 文を真で、2つ目の if 文を偽で通ったときにだけ発生する」
なんて不具合も見つける事が出来ます。
このチェック方法は複合条件網羅と呼ばれ、最も精度が高い動作確認方法と言われていますが…もし1つの関数の中に if 文が10個あった場合、複合条件網羅で確認すべき回数は2の10乗(1024)回にも上りますexclamation×2
全てのプログラムに対してこのレベルのチェックを行うのは、残念ながら現実的ではないというのが実状のようですたらーっ(汗)

***

どの方法で動作確認すれば良いのか、一概には言えません。
複合条件網羅が現実的ではないとは言え、重要な処理に限定してそれを行わなければならないケースもある事でしょう。
ある程度経験を積めば、自分が作成したプログラムを、どの程度のレベルで動作確認しなければならないのか、分かってくる事と思いますぴかぴか(新しい)
それがよく分からない方、どうも自分の作ったプログラムには、後から見つかるバグが多いな…と思ったら、一度動作確認方法を見直してみてはいかがでしょうか?


posted by 管理人 at 20:49 | プログラミング

2012年05月16日

メモリイメージ

日に日に気温も上昇し汗ばむ季節になってきましたね晴れ
汗かきなので既に薄着になりつつある「オクダ」です。
皆さんは夏に向けてのカラダ作りは大丈夫ですか?
今年はプロジェクトが佳境を迎えるのであきらめムードですふらふら

今回はプログラマ向けの少しディープな話をしてみようと思います。
テーマは「メモリ」です。
皆さんがPCを使ったりプログラムをしている時にメモリを意識する事は少ないかもしれませんが、
メモリとうまく付き合っていく事で、更に上位レベルのプログラマになれると思います。
プログラムの最適化や言語仕様の理解、デバッグに役立つと思います。

C言語(C++)を基準に解説していきますが、他の言語でも共通する考え方だと思います。
OSやライブラリはの大部分はC(C++)で作られているのでほとんどの言語がCのメモリ管理を踏襲しています。
CPUやコンパイラによる細かな違いもありますが、大きくは変わらないでしょう。


プログラムがシステムからメモリ上にロードされ動作を開始するタイミングでは大きく分けて4つのメモリ領域が確保(割り当て)されます。

1プログラムの命令部分
CPUはここに書かれた命令を一つずつ順番に処理していきます。
稀に、この領域に固定の値が含まれる事があります。(関数のstatic constなローカル変数など)

2固定された値
constな変数がここに分類されます。
固定のテーブルなどはココです。
この領域の内容が書き変わる事は無いハズですね。

3変数領域
globalな変数の領域です。
関数内のstatic変数やC++のstaticなクラスメンバもココになります。
関数内のstatic変数はコンパイラや最適化具合によって1の内部に分散格納される場合もありますが、場所の問題であって意図としては同じです。


4スタック
謎の領域「スタック」です。
基本的に固定された領域ですが、使い方がトリッキーで詳しく説明されない事も多いです。
次回はココにスポットを当てたいと思います。

更に実行時に割り当てられるメモリがあります。

5ヒープ領域
mallocやnewなどで実行時に動的に割り当てられるメモリ領域です。
mallocの場合はメモリ確保のイメージがあると思いますが、
newの場合はメモリ確保している印象は希薄だと思います。
また、関数内で宣言したクラスは宣言タイミングでヒープからメモリ確保され、スコープを抜けるタイミングで解放されます。
constructor,destructor(new,delete)がその都度呼ばれている事に注意しないと痛い目を見ます。

自分がプログラムの中で書いたコードや確保したメモリが
どういった役割を持っていて、どのような場所に確保されているか、、、
少しだけイメージできたでしょうか?
値が変更される可能性があるのか無いのか。
静的に確保されるのか動的に確保されるのか。
このあたりの違いがカギになっているようです。
バグが発生した場合の解決の糸口になる事もあるので、少しだけ意識してみるといいでしょう。

さて、今まで説明してきた中で触れていないモノがあります。
「staticでないローカル変数」です。
最適化された場合にはメモリではなくレジスタに割り当てられることも多いですが、
実は4のスタックに確保されることがほとんどです。
また、レジスタに割り当てられたとしてもスタックと無縁ではありません。
むしろ密接に関係しています。
次回はこの「スタック」の役割と仕組み、動作にスポットを当てたいと思います。
乞うご期待!


posted by 管理人 at 16:19 | プログラミング

2012年05月07日

JavaScriptで3D

突然ですが、ベランダで野菜を育て始めましたクリスマス
少しずつではありますが、元気に育っていく野菜を見るのが楽しみなgood sun晴れこと山口です。

さて少し前からJavaScriptを話題にしているのですが、
今回は前回のドラッグ&ドロップを引き継ぎつつ、今までと違ったJavaScriptのサンプルを用意しました。
お待たせ致しました、ついにWebGL到来です!!
ついにブラウザだけの力で3D表示出来る時代の波に少しだけ乗っかってみました。
その為今回のサンプルが動作するブラウザは限られてしまいます。
推奨ブラウザはGoogle Chromeとなります。

サンプルはこちらから

今回のサンプルは実行されると四角い箱が回っていますプレゼント
ここにブラウザで使用可能な画像ファイル(.png等)をドラッグ&ドロップすることで、
画像をテクスチャとして貼ることが出来ます。
※簡単に試してみましたが、どうもjpegは白い画像になってしまうようです。。。pngでお試し下さい。

ドラッグ&ドロップについては
最後に掲載するソースコードのdropFileの部分を参照して下さい。
dropイベントを受け取って、
中身が画像であればテクスチャを作成しています。
実際に一連のソースコードがあると、
どのような流れで動いているのか分かりやすいのでは無いでしょうか。

今回サンプルを作っていて、昔Java3Dでブラウザに3D表示をしていた時の事を思い出したりしました。
いまではJavaScriptで3D表示が出来ておまけにシェーダが使えてしまうのですから、
技術の進歩は凄まじいものです。

更にJavaScript版COLLADAローダというのもあるようです。
頑張れば3Dモデルデータもブラウザにドラッグ&ドロップで表示出来るようになってしまいます!
これは益々目が離せない感じです目

WebGL入門も果たしブラウザ熱が上がってきたところで今回は終了とさせて頂きたいと思います。
次回もWebGLについて書ければ良いなぁと考えておりますが、予定は未定です。


最後に注意点及び、今回のサンプルのソースコードを掲載します。
まず注意点ですが、
このサンプル、Google Chromeではサーバにソースコードがある場合は問題なく動作しますが、
ソースをローカルにダウンロードして動作させようとした場合に通常はドラッグ&ドロップが働きません。
MacOSXの場合は以下のようなシェルスクリプト経由で起動させることでファイルのドラッグ&ドロップを受け付けるようになります。

#!/bin/sh
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --allow-file-access-from-files

そして以下が今回のサンプルのソースコードになります。
今回のサンプルは行列処理にNewBSDライセンスにて配布されているglMatrixを利用しています。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>javascriptサンプル</title>
<script type="text/javascript" src="http://glmatrix.googlecode.com/files/glMatrix-0.9.5.min.js"></script>
</head>
<body>
<canvas id="canvas" ondragover="scene.dragFile(event);" ondrop="scene.dropFile(event);"></canvas>
<script id="vshader" type="x-shader/x-vertex">
#ifdef GL_ES
precision highp float;
#endif

uniform mat4 mMatrix;
uniform mat4 vpMatrix;

attribute vec3 position;
attribute vec2 uv;

varying vec2 texCoord;

void main() {
gl_Position = vpMatrix * mMatrix * vec4(position, 1.0);
texCoord = uv;
}
</script>
<script id="fshader" type="x-shader/x-fragment">
#ifdef GL_ES
precision highp float;
#endif

uniform sampler2D texture;

varying vec2 texCoord;

void main() {
gl_FragColor = texture2D(texture, texCoord);
}
</script>
<script type="text/javascript">
var scene;
var frame;
window.onload = function() {
frame = new Frame();
if(frame.enabled){
scene = new Scene(frame.context3d);
frame.drawFunc = function(context3d){scene.draw(context3d);}
frame.run(new Date());
}
}
</script>
</body>
<script type="text/javascript">
Screen = {
width:640,
height:480
};
//! カラー定義
function Color(r,g,b,a){
this.r = r;
this.g = g;
this.b = b;
this.a = a;
}
//! シェーダ
function Shader(context3d, vshaderSource, fshaderSource, attrNames, uniformNames){
this.vshader = null;
this.fshader = null;
this.program = null;
this.attributes = [];
this.uniforms = [];
// 頂点シェーダー
this.vshader = context3d.createShader(context3d.VERTEX_SHADER);
context3d.shaderSource(this.vshader, vshaderSource);
context3d.compileShader(this.vshader);
if(!context3d.getShaderParameter(this.vshader, context3d.COMPILE_STATUS)){
alert(context3d.getShaderInfoLog(this.vshader));
}
// フラグメントシェーダー
this.fshader = context3d.createShader(context3d.FRAGMENT_SHADER);
context3d.shaderSource(this.fshader, fshaderSource);
context3d.compileShader(this.fshader);
if(!context3d.getShaderParameter(this.fshader, context3d.COMPILE_STATUS)){
alert(context3d.getShaderInfoLog(this.fshader));
}

this.program = context3d.createProgram();
context3d.attachShader(this.program, this.vshader);
context3d.attachShader(this.program, this.fshader);

context3d.linkProgram(this.program);
if(!context3d.getProgramParameter(this.program, context3d.LINK_STATUS)){
alert(context3d.getProgramInfoLog(this.program));
}

for(var i = 0; i < attrNames.length; i++){
var attr = context3d.getAttribLocation(this.program, attrNames[i]);
this.attributes = this.attributes.concat(attr);
}

for(var i = 0; i < uniformNames.length; i++){
this.uniforms = this.uniforms.concat(context3d.getUniformLocation(this.program, uniformNames[i]));
}
}
//! ボックスデータを作る
function Box(context3d){
this.vbuffer = [];
this.ibuffer = null;
this.indexCount = 0;
this.initVertexBuffer(context3d);
this.initIndexBuffer(context3d);
}
Box.prototype.initVertexBuffer = function(context3d){
var position = [
[-1,-1,-1],
[ 1,-1,-1],
[-1,-1, 1],
[ 1,-1, 1],

[-1, 1,-1],
[ 1, 1,-1],
[-1, 1, 1],
[ 1, 1, 1],
];
var uv = [
[0,1],
[1,1],
[0,0],
[1,0]
];
// 頂点配列を組み立てる
var index = [[0,1,2,3],[0,1,4,5],[2,3,6,7],[0,2,4,6],[1,3,5,7],[4,5,6,7]];
var vertexPosition = [];
for(var i = 0; i < 6; i++){
for(var j = 0; j < 4; j++){
vertexPosition = vertexPosition.concat(position[index[i][j]]);
}
}
var vertexTexCoord = [];
for(var i = 0; i < 6; i++){
for(var j = 0; j < 4; j++){
vertexTexCoord = vertexTexCoord.concat(uv[j]);
}
}
// Buffer作成
var vbuffer = context3d.createBuffer();
context3d.bindBuffer(context3d.ARRAY_BUFFER, vbuffer);
context3d.bufferData(context3d.ARRAY_BUFFER, new Float32Array(vertexPosition), context3d.STATIC_DRAW);
vbuffer.itemSize = 3;
this.vbuffer = this.vbuffer.concat(vbuffer);

vbuffer = context3d.createBuffer();
context3d.bindBuffer(context3d.ARRAY_BUFFER, vbuffer);
context3d.bufferData(context3d.ARRAY_BUFFER, new Float32Array(vertexTexCoord), context3d.STATIC_DRAW);
vbuffer.itemSize = 2;
this.vbuffer = this.vbuffer.concat(vbuffer);

context3d.bindBuffer(context3d.ARRAY_BUFFER, null);
}
Box.prototype.initIndexBuffer = function(context3d){
var index = [];
var base = 0;
for(var i = 0 ; i < 6 ; i++) {
index = index.concat(base + 0);
index = index.concat(base + 1);
index = index.concat(base + 2);
index = index.concat(base + 2);
index = index.concat(base + 1);
index = index.concat(base + 3);
base += 4;
}
// バッファを作成
this.ibuffer = context3d.createBuffer(context3d);
context3d.bindBuffer(context3d.ELEMENT_ARRAY_BUFFER, this.ibuffer);
context3d.bufferData(context3d.ELEMENT_ARRAY_BUFFER, new Int16Array(index), context3d.STATIC_DRAW);
context3d.bindBuffer(context3d.ELEMENT_ARRAY_BUFFER, null);
this.indexCount = index.length;
}
Box.prototype.draw = function(context3d, shader){
context3d.enableVertexAttribArray(shader.attributes[0]);
context3d.bindBuffer(context3d.ARRAY_BUFFER, this.vbuffer[0]);
context3d.vertexAttribPointer(shader.attributes[0], this.vbuffer[0].itemSize, context3d.FLOAT, false, 0, 0);
context3d.enableVertexAttribArray(shader.attributes[1]);
context3d.bindBuffer(context3d.ARRAY_BUFFER, this.vbuffer[1]);
context3d.vertexAttribPointer(shader.attributes[1], this.vbuffer[1].itemSize, context3d.FLOAT, false, 0, 0);
context3d.bindBuffer(context3d.ELEMENT_ARRAY_BUFFER, this.ibuffer);
context3d.drawElements(context3d.TRIANGLES, this.indexCount, context3d.UNSIGNED_SHORT, 0);
}

//! 描画シーン
function Scene(context3d){
this.updateTexture = false;
this.image = null;
this.texture = this.createEmptyTexture(context3d);
this.shader = new Shader(
context3d,
window.document.getElementById("vshader").text,
window.document.getElementById("fshader").text,
["position", "uv"],
["mMatrix", "vpMatrix"]);
this.box = new Box(context3d);
this.viewMatrix = mat4.create();
mat4.identity(this.viewMatrix);
mat4.translate(this.viewMatrix, [0, 0, -8]);
this.projectionMatrix = mat4.create();
mat4.identity(this.projectionMatrix);
mat4.perspective(30, Screen.width / Screen.height, 0.1, 1000, this.projectionMatrix);

this.count = 0;
}
Scene.prototype.draw = function(context3d){
this.count++;
if(this.updateTexture){
this.updateTexture = false;
this.texture = this.createTexture(context3d, this.image);
}
context3d.disable(context3d.CULL_FACE);
context3d.useProgram(this.shader.program);
var matrix = mat4.create();
mat4.identity(matrix);
mat4.rotate(matrix, 10 * this.count * Math.PI / 180, [0, 1, 0]);

var camMatrix = mat4.create(this.projectionMatrix);
mat4.multiply(camMatrix, this.viewMatrix);

context3d.uniformMatrix4fv(this.shader.uniforms[0], false, matrix);
context3d.uniformMatrix4fv(this.shader.uniforms[1], false, camMatrix);

context3d.bindTexture(context3d.TEXTURE_2D, this.texture);
context3d.texParameteri(context3d.TEXTURE_2D, context3d.TEXTURE_MAG_FILTER, context3d.LINEAR);
context3d.texParameteri(context3d.TEXTURE_2D, context3d.TEXTURE_MIN_FILTER, context3d.LINEAR_MIPMAP_LINEAR);
context3d.texParameteri(context3d.TEXTURE_2D, context3d.TEXTURE_WRAP_S, context3d.CLAMP_TO_EDGE);
context3d.texParameteri(context3d.TEXTURE_2D, context3d.TEXTURE_WRAP_T, context3d.CLAMP_TO_EDGE);

this.box.draw(context3d, this.shader);
}
Scene.prototype.dragFile = function(event){
if (event.dataTransfer.types[0] == "Files"){
event.preventDefault();
}
}
Scene.prototype.dropFile = function(event){
var file = event.dataTransfer.files[0];
if(file.type.match(/image\/\w+/)){
var reader = new FileReader();
reader.filename = event.dataTransfer.files[0].fileName;
var _this = this;
// エンコード完了後のコールバック
reader.onloadend = function() {
_this.setupImage(reader);
}
// Base64URI変換
reader.readAsDataURL(file);
}
}
Scene.prototype.setupImage = function(reader){
if(reader.error){
return;
}
this.image = new Image();
this.image.src = reader.result;
this.image = this.checkSize(this.image);
this.updateTexture = true;
}
Scene.prototype.createEmptyTexture = function(context3d){
var canvas = document.createElement('canvas');
canvas.height = canvas.width = 8;
var context = canvas.getContext('2d');
context.fillStyle = "#ffffff";
context.fillRect(0, 0, canvas.width, canvas.height);

return this.createTexture(context3d, canvas);
}
Scene.prototype.createTexture = function(context3d, image){
var texture = context3d.createTexture();
context3d.bindTexture(context3d.TEXTURE_2D, texture);
context3d.texImage2D(context3d.TEXTURE_2D, 0, context3d.RGBA, context3d.RGBA, context3d.UNSIGNED_BYTE, image);
context3d.generateMipmap(context3d.TEXTURE_2D);
context3d.bindTexture(context3d.TEXTURE_2D, null);
return texture;
}
Scene.prototype.checkSize = function(image) {
var w = image.naturalWidth;
var h = image.naturalHeight;
var size = Math.pow(2, Math.log(Math.min(w, h)) / Math.LN2 | 0);
if (w !== h || w !== size) {
var canvas = document.createElement('canvas');
canvas.height = canvas.width = size;
canvas.getContext('2d').drawImage(image, 0, 0, w, h, 0, 0, size, size);
image = canvas;
}
return image;
}
//! フレーム管理クラス
function Frame(){
this.enabled = false;
// コンテキストの準備
this.canvas = window.document.getElementById("canvas");
var contextName = ["webgl", "experimental-webgl", "webkit-3d", "moz-webgl"];
for(var i = 0; i < contextName.length; i++){
try{
this.context3d = this.canvas.getContext(contextName[i]);
}catch(e){
}
if(this.context3d){
break;
}
}
if(!this.context3d){
return;
}
this.canvas.width = Screen.width;
this.canvas.height = Screen.height;
this.context3d.viewport(0, 0, Screen.width, Screen.height);
this.context3d.enable(this.context3d.TEXTURE_2D);
this.clearColor = new Color(0.1,0.1,0.1,1);
this.clearDepth = 1000;
this.enabled = true;
this.drawFunc = null;
}
Frame.prototype.clear = function(){
var cc = this.clearColor;
this.context3d.clearColor(cc.r, cc.g, cc.b, cc.a);
this.context3d.clearDepth(this.clearDepth);
this.context3d.clear(this.context3d.COLOR_BUFFER_BIT | this.context3d.DEPTH_BUFFER_BIT);
}
Frame.prototype.run = function(lastTime){
// クリア
this.clear();
this.context3d.enable(this.context3d.DEPTH_TEST);
this.drawFunc(this.context3d);
this.context3d.flush();
//! 更新を行う
var nowTime = new Date();
// 20FPS
var nextTime = 50 - (nowTime.getTime() - lastTime.getTime());
if(nextTime <= 0){
nextTime = 1;
}
var _this = this;
setTimeout(function(){_this.run(nowTime);}, nextTime);
}
</script>
</html>


posted by 管理人 at 16:33 | プログラミング

2012年04月25日

日付取得バッチファイル

こんちには。平尾ですわーい(嬉しい顔)
本日の大阪の最高予想気温は26度exclamation×2
かと思えば明日は19度と、寒暖の差が激しいですねふらふら
体調を崩さないよう気を付けなくては…!

2010-10-14-0.png


今回は日付取得バッチファイルについて書きたいと思います。


バッチファイルが有効に働くのは以下のようなときです。
 ・一括で何かさせたいとき (ex.一括データコンバート)
 ・自動で何かさせたいとき (ex.Jenkinsでのデイリービルド)
 ・一連の必要な手順をまとめておく (ex.ROMイメージの作成CD

こういったときに
『本日の日付をフォルダ名に設定する』
といったようなことができると非常に助かります決定
本日ですと 20120425 といった8桁の日付が欲しいわけですが、
日付の取得はどう書けばいいのでしょうか?


一番簡単な日付取得として次のように書く方法があります。
(仮に日付を表示する形をとっています)
echo %date:/=%
ただし、OSや設定で曜日出力が入ったりすることがあり、
うまくいかないこともあります…もうやだ〜(悲しい顔)


そんなときは文字の位置と文字数を指定し、
年月日を抜き出すという手があります手(パー)
echo %date:~0,4%%date:~5,2%%date:~8,2%
ただし、これも曜日表示が前に来たりするとダメだったりします。
もし環境が固定されていれば、文字取得位置をずらすだけで問題ありませんが、
チームで作業をしていると個人個人で全然違う設定になっていることも多々あります。
もし英語などの設定だと、曜日が英語だったりするわけで…ちっ(怒った顔)爆弾


PCによって日付出力が変わってしまうのは仕様ならば、違うアプローチで対応するしかない!パンチ
というわけで最終的に落ち着いたのは、
バッチファイルから WSH (Windows Script Host) を呼び出す形ですひらめき
WSH は Windowsの機能として入っていますので、新たなインストールなどは不要です。
バッチファイルの内容は以下のようになります。

@echo off
setlocal

rem 一時使用VBスクリプト(temp.vbs)の作成
echo strNow = Now() > temp.vbs
echo WScript.Echo Year(strNow) ^& Right("0" ^& Month(strNow), 2) ^& Right("0" ^& Day(strNow), 2) >> temp.vbs

rem 日付を取得
for /f %%A in ('cscript temp.vbs') do set today=%%A
echo %today%

rem 一時使用ファイルを削除
del temp.vbs

endlocal
pause


バッチファイルの流れを簡単に説明しますと、
 1VBスクリプト一時ファイルを作成
 2一時ファイル内で、年月日をそれぞれ取得、8桁に揃えています
  (月日にはそれぞれ先頭に0を加えて右の2桁を取得することで、必ず2桁になるようにしています)
 3for文からスクリプトを呼び出し、出力されたものを変数にセット
 4一時ファイルを削除
となります。
使用頻度が高く、一時ファイルの作成→削除の処理がもったいない場合は
別ファイルで用意しておくのが良いと思います。


と、日付出力だけでこんなに苦労するのも理不尽あせあせ(飛び散る汗)な気がしますが、
何にせよこれでバッチファイルへの組み込みができると思いますメモ

2010-10-14-0.png


身の回りの定型作業など、バッチファイルなどを活用していけば
日々の作業が少しずつ楽になっていきますsoon
作るまでの手間はありますが、トータルで見ると大きく変わってきます時計
できるだけ自動化をすすめて効率良い仕事、より良い仕事をしていけるよう
がんばっていきたいと思います!パンチ
(最近はRubyがマイブームだったりします)


posted by 管理人 at 14:13 | プログラミング

2012年03月21日

続々続JavaScript!

引っ越したことによって生活習慣が良い方向にガラリと変わり、
健康街道まっしぐらなgood sun晴れこと山口です。
すっかり肩こりも解消された感じです。わーい(嬉しい顔)
日々の軽い運動はデスクワークが中心となるプログラマーには素晴らしい効果をもたらします。

さて今回のJavaScriptネタはHTML5の中でも
私がグラフィック機能と並んで好きな
LocalStorageとファイルのドラッグ&ドロップ機能の紹介をしたいと思います。

まずはLocalStorageですが、
LocalStorageを使うとサーバと繋がっていなくても、
JavaScriptを使って様々な加工を行ったデータを
ブラウザにローカルなデータとして保存しておくことが出来ます。
HTMLに触れたことがある人であれば、
似た機能があることに気づくかもしれないですね。
Cookieです。
LocalStrageはCookieを強化したようなものです。
格納できるデータサイズはCookieより大きくなっているのと、
サーバへのリクエストを行わずにデータの格納が出来る点がパワフルです。
まさにローカル環境にデータを格納する為の機能です。

localStrage.setItem(名前, 値);

で書き込みを

var val = localStrage[名前];

で取得が出来ます。
とても簡単ですね。

そしてもう一つの機能、ファイルのドラッグ&ドロップについてです。
なんとブラウザ上の任意の場所にファイルをドロップすることで
JavaScriptでそのファイルのデータ内容を取得出来るのです!
今のJavaScriptは画像ファイルを読み込んで加工することも出来るという優れものです。
ondropイベントに対するコールバックの引数のevent.dataTransferにデータが格納されています。

更に先程のLocalStrageと合わせると加工済みデータを一先ずローカルに保存しておいて、
ひと通り加工が終わったらサーバに送信するような事が出来たりします。
この機能を使って3Dのモデリングもブラウザで出来る時代が来るかもしれません。
ゲーム開発にも何か応用できそうでワクワクしますよね!

実際にローカル環境だけで使用する場合は、
少し制限があったりするので、
次回はそのあたりも踏まえサンプルコードメモ付きでお届けできたらと思います。

posted by 管理人 at 20:43 | プログラミング

2012年03月19日

逆ポーランド記法

お久しぶりです。
先日の GDC 2012 でついに新作SimCityが発表NEWになり、
今から楽しみで仕方のないタイラです。わーい(嬉しい顔)

さて、Googleの検索機能の中に関数グラフ表示機能があるのをご存知でしょうか?
  x/2, (x/2)^2, 2^x
を検索するとグラフが表示されます。

今回はこの計算を作ってみました。
計算する方法ですが、逆ポーランド記法(Reverse Polish Notation) を用います。

通常、非演算子の間に演算子を書きますが、
この記法では非演算子の後に演算子を書きます。

変換前(通常)
 1 + 2 * 3 - 4

変換後(逆ポーランド記法)
 1 2 3 * + 4 -


並び替えキューに積んだ後順番に取り出しながらスタックへ積み上げていき、
演算子だった場合はスタックの上から2つの値を用い計算を行います。
キューの最後まで取り出して計算をすると、
最終的にスタック上には1つのデータが残り、式の答えになります。

[stack] [queue]
1 2 3 * + 4 -
1 2 3 * + 4 -
1 2 3 * + 4 -
1 2 3 * + 4 -
1 2 3 * + 4 -
1 6 + 4 -
1 6 + 4 -
7 4 -
7 4 -
7 4 -
3 // 答え

グラフ表示用では関数用の'x'をそのまま数値と同様に並び替え、
計算時に実際の数値に置き換えれる事で計算が出来ます。

変換前(通常)
 1 + 2 * x - 4

変換後(逆ポーランド記法)
 1 2 x * + 4 -



// x = 3;
[stack] [queue]
1 2 x * + 4 - // 並び替え時も'x'のまま保持
1 2 x * + 4 -
1 2 x * + 4 -
1 2 x * + 4 -
1 2 3 * + 4 - // ここで'x'を置き換える
1 2 3 * + 4 -
1 6 + 4 -
1 6 + 4 -
7 4 -
7 4 -
7 4 -
3 // 答え

xの値を順番に変化させていけばグラフが作れますねexclamation
三角関数や指数関数の計算はスタックの上1つを計算することで実現できます。
関数のバリエーションを増やすと関数電卓の代わりになりますね。ひらめき

ソースを載せるとかなり長くなるので、サンプルファイルを用意しました。
rpn.cpp

普段使っている物にも意外な機能を持っている事があります。
みなさんも探してみては如何でしょうか?

ちなみにGoogleで
 sqrt(cos(x)) * cos(300x) + sqrt(abs(x)) from -4 to 4
と検索するとハート型に見えますよ。

それではexclamation


posted by 管理人 at 21:18 | プログラミング

2012年02月21日

VisualC++11.0

こんにちはぴかぴか(新しい)

ここ最近風邪気味でしたが、
土日ですっかり元気を取り戻したイワモーですグッド(上向き矢印)

さて、皆さんは、VisualStudioの次世代バージョンが利用できる事はご存知でしょうか?
まだ正式名称は決まっていない様ですが、VisualStudio11という名前で、
デベロッパープレビュー版がマイクロソフト様から配布されています目

VisualStudio11になり、それに付随してVisualC++11.0となり、ライブラリの機能も強化され、
C++11(C++0x)のサポートもかなりされる様になっています晴れ

C++11については下記をご参照下さい。
http://ja.wikipedia.org/wiki/C%2B%2B11


今回はVisualC++11.0の機能を2つ程紹介してみたいと思います手(チョキ)


まず、for eachが標準でサポートされる様になりました目
例えば、今までだとSTLのalgorithmを呼び出し、関数を作成してfor_eachを呼び出す必要がありましたが……
for eachはVisualC++8.0で既にサポートされていた様です!お恥ずかしい……
for eachの箇所でauto変数を用いているので、VisualC++10.0水準となります。



#include<algorithm>
#include<iostream>
#include<vector>

void print(int i);
{
std::cout << i << std::endl;
}

void main()
{
std::vector<int> hogeVector;
hogeVector.push_back(0);
hogeVector.push_back(1);
hogeVector.push_back(2);
hogeVector.push_back(3);

std::for_each(hogeVector.begin(),hogeVector.end() ,print);
}



VisualC++11.0では言語そのものに既に標準で組み込まれており、



#include<iostream>
#include<vector>

void main()
{
std::vector<int> hogeVector;
hogeVector.push_back(0);
hogeVector.push_back(1);
hogeVector.push_back(2);
hogeVector.push_back(3);

//auto iterator はhogeVectorのイテレーターとなります
//hogeVectorの最後の要素になるまで、iteratorをループしていきます。
for each (auto iterator in hogeVector)
{
std::cout << iterator << std::endl;
}
}



この様にauto変数とfor eachを組み合わせる事で、かなり自然で楽な構文を書く事が出来ます。

auto変数については、VisualC++10.0(VisualStudio2010)から標準機能として装備されており、
コンパイラが型を自動的に決めてくれる変数です。

例えば

void main(void)
{
auto i = 10; //int型に自動的に認識してくれる
auto f = 10.0F; //float型…
auto d = 10.0; //double型…
auto c = 'C'; //char型…
}


デバッグして型を見てみると、自動的に型が選択されている事がわかると思います。


上記の様な簡単な型の場合は、autoを利用して抽象化する必要が無いですが、
汎用的なイテレーターとしての動作を行ったりする場合や、
ラムダ式(関数)を利用する際には、特に効果を発揮するのではないでしょうか目


さて、もう一つは
新たに追加されたThreadの機能です。

昨今のプログラムではマルチスレッド化が当たり前の様になっていますが、
VisualC++11.0では標準ライブラリとして、マルチスレッド用ライブラリが入っています。

簡単に利用するだけなら



#include<thread>
#include<iostream>

void printA()
{
std::cout << "スレッドA" << std::endl;
}

void printB()
{
std::cout << "スレッドB" << std::endl;
}

void main(void)
{
std::thread MultiThreadA(&printA);
std::thread MultiThreadB(&printB);


MultiThreadA.join();
MultiThreadB.join();
}


これだけの構文でマルチスレッド処理を書くことが出来ます。
ミューテックスのライブラリもちゃんと用意されていますので、
クリティカルセクションの構築も問題はないかと思います!

VisualStudio自体の新機能も含めて、紹介しきれない程の機能がありますが、
全部はとても書ききれないので、今回はこの辺りで一区切りしたいと思います。
興味が出た方は、是非一度調べてみて下さいグッド(上向き矢印)

また、今回はVisualC++11.0向けのサンプルコードを一つ用意してみました。

std::array, auto変数, for each, lambda関数, std::thread, std::mutex
上記を用いたサンプルとなっております


main.cpp


※・VisualStudio11以外のコンパイラでは、コンパイルが通りません。
 ・Visual Studio 11 Developer Preview版についてはコチラからダウンロードできます。


それではこの辺で手(パー)

posted by 管理人 at 13:15 | プログラミング

2012年02月06日

たまには失敗のjavaScript

お久しぶりです。
前回のブログ1月以上の間が空きまして、
この間色々な事がありました。
間もなく引越し予定のgood sun晴れこと山口です。

今回もJavaScriptネタをやろうとしたのですが、
最初にお断りさせて頂きますが、一部失敗しました。ふらふら
そんな時もあります。
まずは何がしたかったのか説明させて頂きます。

以前JavaScriptでマルチタッチ手(チョキ)が取れるというお話を書かせて頂きました。
今回はいつもより少し時間があったので
このタッチについてサンプルを作ってみようとしました。
そこまでは良かったのです。

問題は音るんるんを鳴らしてみようと思った所です。
GoogleChromeでは

var audio = new Audio(音データ);
audio.play();


で音が鳴ります。
ここまでは確認しました。
まだ問題ありません。

これをAndroidで確認すると...
鳴りません。
おかしいと思い検索エンジンで調査を開始しました。
なんと現行のAndroidやiOS端末のブラウザはJavaScript単体で音を鳴らすことが出来ないようです。

完全に調査不足でした。
しかし失敗はこれだけに留まりません。

どのように失敗なのかは今回のサンプルを実行していただくのが早いと思います。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name=”viewport” content=”width=480, user-scalable=no, maximum-scale=0.6667″ />
<title>javascriptサンプル</title>
</head>
<body>
<dir style="vertical-align: middle; margin-left:auto; margin-right:auto;">
<canvas id="canvas"></canvas>
</dir>
</body>
<script type="text/javascript" charset="UTF-8">
//! ノード管理クラス
function NodeManager(){
this.nodes = new Array();
}
NodeManager.prototype.create = function(x, y){
this.nodes.push(new Node(x, y));
}
NodeManager.prototype.update = function(){
for(var i = this.nodes.length - 1; i >= 0; i--){
if(!this.nodes[i].update()){
if(i == 0){
if(this.nodes.length > 1){
this.nodes = this.nodes.slice(1, this.nodes.length);
}else{
this.nodes = new Array();
}
}else{
if(i + 1 == this.nodes.length){
this.nodes = this.nodes.slice(0, i);
}else{
var tmparray = this.nodes.slice(0, i);
this.nodes = tmparray.concat(this.nodes.slice(i + 1, this.nodes.length));
}
}
}
}
}
NodeManager.prototype.draw = function(context2d){
for(var i = 0; i < this.nodes.length; i++){
this.nodes[i].draw(context2d);
}
}
var nodeManager = new NodeManager();
//! ノードクラス
function Node(x, y){
// パラメータはランダムで決定
this.posx = x;
this.posy = y;
this.color = "#"+((Math.floor(Math.random()*255) << 16) | (Math.floor(Math.random()*255) << 8) | Math.floor(Math.random()*255)).toString(16);
this.isFill = Math.random() > 0.5 ? true : false;
this.width = Math.floor(Math.random()*10) + 3;
this.rad = 5;
this.life = Math.floor(Math.random()*10) + 30;
}
//! 更新関数
Node.prototype.update = function(){
this.rad += 10;
this.life--;
if(this.life <= 0){
return false;
}
return true;
}
//! 描画関数
Node.prototype.draw = function(context2d){
context2d.beginPath();
context2d.arc(this.posx, this.posy, this.rad, 0, 360, false);
if(this.isFill == true){
context2d.fillStyle = this.color;
context2d.fill();
}else{
context2d.strokeStyle = this.color;
context2d.lineWidth = this.width;
context2d.stroke();
}
context2d.closePath();
}
//! フレーム管理クラス
function Frame(){
var _this = this;
// クリアカラーとキャンバスサイズ
this.clearColor = "#202030";
// コンテキストの準備
this.canvas = window.document.getElementById("canvas");
this.context2d = this.canvas.getContext('2d');
this.canvas.width = document.body.scrollWidth;
this.canvas.height = document.body.scrollHeight;
// クリアカラーでクリアする
this.context2d.fillStyle = this.clearColor;
this.context2d.fillRect(0, 0, this.canvas.width, this.canvas.height);
// タッチイベントの追加
document.getElementsByTagName("body").item(0).ontouchstart = function(event){
_this.onTouchStart(event);
};
document.getElementsByTagName("body").item(0).ontouchmove = function(event) {
_this.onTouchMove(event);
};
document.getElementsByTagName("body").item(0).ontouchend = function(event) {
_this.onTouchEnd(event);
};
// もしくはクリック
this.canvas.onclick = function(event){
_this.onMouseClick(event);
}
}
Frame.prototype.onMouseClick = function(event){
nodeManager.create(event.clientX, event.clientY);
}
Frame.prototype.onTouchStart = function(event){
event.preventDefault();
event.touches.length;
for(var i = event.touches.length - 1; i >= 0; i--){
nodeManager.create(event.touches[i].pageX, event.touches[i].pageY);
}
}
Frame.prototype.onTouchMove = function(event){
event.preventDefault();
}
Frame.prototype.onTouchEnd = function(event){
event.preventDefault();
}
//! 実行
Frame.prototype.run = function(lastTime){
// クリア
this.context2d.fillStyle = this.clearColor;
this.context2d.fillRect(0, 0, this.canvas.width, this.canvas.width);
nodeManager.update();
nodeManager.draw(this.context2d);
//! 更新を行う
var nowTime = new Date();
// 20FPS
var nextTime = 50 - (nowTime.getTime() - lastTime.getTime());
if(nextTime <= 0){
nextTime = 1;
}
var _this = this;
setTimeout(function(){_this.run(nowTime);}, nextTime);
}
var frame = new Frame();

frame.run(new Date());
</script>
</html>


動くのはこちらから
(動作確認が出来ているのは、Android+OperaMobile、iOS+Safariです。
残念ながらAndroid+標準ブラウザではマルチタッチ認識しないようです。
iOS+OperaMiniはそもそもタッチ認識しませんでした。)

...画面サイズがおかしいです。
フルスクリーンをやりたいなと思ってみたのですが御覧の結果です。
何事も慌ててやってはいけないという事ですね。
反省です。
次回までの課題ですね。

今回の目玉目マルチタッチの取得に関しては

document.getElementsByTagName("body").item(0).ontouchstart = function(event){
_this.onTouchStart(event);
};

この辺が該当の箇所になります。
ちゃんとクロージャな呼び出しも健在です。

次は今回カットした音に関連してデータに関して何かやれたらなと思っています。
ではまた。手(パー)


posted by 管理人 at 21:31 | プログラミング

2012年02月01日

zlib

こんにちは。平尾です。
昨年は病気をすることもなく皆勤でした!
今年も元気いっぱい頑張っていこうと思います わーい(嬉しい顔)

ただ、病気に対しては早期発見が最も有効なので、
今月予定の定期検診では人間ドックを受診します。
会社からも一部補助金が出るので助かります有料ぴかぴか(新しい)


2010-10-14-0.png


製品版になったゲームで、最も時間を必要とする処理は何かご存じですか?

ずばり、ディスクアクセスですCD
その他の処理に関しては 1/60秒, 1/30秒 といった短時間で様々な処理が行われ、
1秒間にも何度も呼ばれますが、
それに比べディスクアクセスの長いこと…時計


というわけで今回は 『 zlib 』 を紹介します。
有名すぎてあえて紹介するまでも無いかもしれませんが、
データの圧縮・展開を行うフリーのライブラリです無料
2012/1/29にも()更新が入っていますね。

また、zlib License というかなり緩やかなライセンスなため、
多くの商用ソフトでも多く使われているようです。
岩崎が書いた 「GDI+でBMP/PNG/JPEGの読み込みを簡単に」 にも、
libpng で zlib が必要という一文が入っていますね。

データ自体が小さくなれば、その分データ読み込み時間も減ります soon
読み込み時間が減ればユーザーの待ち時間も減り、快適にゲームをしていただけます るんるん
学生の方は就職作品などに組み込んでおくと、ちょっと目を惹くかもしれませんね 目


使い方に関してですが、zlib の中にもサンプルコードなどが含まれていますが、
コメントが英語なので読み解くのに時間がかかってしまう…もうやだ〜(悲しい顔)
という方は、こちらの「zlib入門」というページが分かりやすいかと思います。
学生の方は是非チャレンジしてみてくださいパンチ

***


ベクトルやマトリクスといった基本的なクラスを自作するのは、
根本を理解するうえではとても良いことだと思います ひらめき
ただ、実際の開発現場では ”車輪の再発明” を行うのは非効率なため、
既に存在するミドルウェアを使うことが増えてきています。
今回のように zlib で外部ライブラリの使用経験を積んでおく、
というのも実践的で良いのではないかと思いますわーい(嬉しい顔)


2010-10-14-0.png


新卒採用 第一弾の応募締切は2月29日(水) 必着 となっていますので、
我こそは!という方は、こちらの採用ステップをご確認のうえ、
ご応募いただければと思いますメール
お待ちしておりますexclamation


posted by 管理人 at 13:13 | プログラミング