2011年3月24日 星期四

Android 的 level 5.0 錯誤

今天將一個Android的專案資料夾搬到另一台電腦上,Import 至 Eclipse 後,一執行,
下方的狀態就跳出了幾行訊息...

Android requires compiler compliance level 5.0. Please fix project properties.

查了一下,都是教設定 JDK Compliance 改為 1.6

或是使用 Android Tools 下的 Fix Project Properties 功能,然後 Restart Eclipse

不過,都沒有作用...

突然想到以前也有碰到這種情況,剛好有找到解法,只是一時忘了.現在就記下來吧...
重點在每個Android的專案內都有一個 .classpath 的文字檔,打開它.
內容會像這樣...

<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry kind="lib" path="C:/cygwin/android-ndk-r5b/samples/testa/libs/admob-sdk-android.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>

當然了,每個專案的路徑不見得會相同,所以內容會和上面不相同.
我這次出的問題就是最長的那一行, path="C:/cygwin/................admob-sdk-android.jar
就是這個了,把這裡的路徑改為現在這台電腦的路徑就ok了.

2011年3月21日 星期一

建立android開發環境

c:那麼今天來介紹Windows XP下建立android開發環境的過程吧.
路人:我說你上次的MapEdit還沒結束吧,怎麼一下跳到這了...
c:那個不急啦,現在android那麼熱門,就寫些大家想看的啊!
路人:是很熱門啦....,不過類似的教學一堆了,不差你一個吧.
c:網上資料是很多啦,不過我這篇的細節比較多哦.
路人:那我就看看吧,



1.安裝Java開發環境(JDK)

到 http://www.oracle.com/technetwork/java/index.html 網站,找到「Java SE」連結.

從 Java Platform, Standard Edition 表格中點選 Download JDK 連結來下載.
下載前要做一些選擇
總算到下載頁面了,檔案有76.58M還不小.

安裝時一直往下按Next就好了,應該不用再放圖說明.
裝好後會跳出網頁要你註冊,唔...可以先不用管他.


2.安裝Eclipse

到 http://www.eclipse.org/downloads/ 
下載 Eclipse IDE for Java Developers 或 Eclipse IDE for Java EE Developers
這兩種版本選一個就好,我是選 Eclipse IDE for Java EE Developers
看他的說明,是從靜宜大學下載.容量約206M,要耐心等待.
將下載下來的壓縮檔解開後就可以用了,不用安裝.直接執行 eclipse.exe 就可以進入了.
啟動 Eclipse 時會跳出視窗決定預設之工作目錄,直接用預設值就好了.


3.安裝ADT(Android Development Tools plugin)

現在來安裝基於 Eclipse 的 Android開發工具擴充套件.
選Help->Install New Software...
加入新增網站,讓 Eclipse 尋找合適的版本.
名稱輸入 ADT, 網址輸入 http://dl-ssl.google.com/android/eclipse/
這邊要等一下,會上網抓新版本
選擇Developer Tools,然後按Next(這邊要等一下),出現一個視窗再按Next
到了這一步,也只能同意了,接著按下 Finish
然後開始漫長的安裝了...
安裝過程碰到了這個,大意是未簽名或無效性的軟體,我選擇了ok,讓他裝下去...
全部完成後,會提示需重新啟動 Eclipse ,按下 Restart Now 重新啟動.


4.下載 Android SDK

先到http://developer.android.com/sdk/index.html
在右下方,我選了 android-sdk_r10-windows.zip
下載後解壓縮,並設定sdk的路徑
設好路徑再按下ok,如同畫面上看到的,那一堆API要之後才會看到,現在還要再做一些設定.
選單上選擇 Window -> Android SDK and AVD Manager 選項,進入 Android SDK/AVD 管理工具.選 Available Packages 標籤頁,看到可以打勾的都勾起來,省得以後麻煩,然後再按下 Install Selected ,之後會跳出一個視窗 選擇 Accept All 後,再按下 Install Accepted ,
就會開始安裝,如果像我全選的話,會裝滿久的,要耐心等待.

一直到這裡,開發環境就算是建制完畢了.

2011年3月16日 星期三

MapEdit - 地圖筆刷

c:這是地圖材質的更換效果.
路人:我看你就簡介好了,貼了一堆程式碼,也看不出重點.
c:其實把它想成是2D的平面地圖就好了,只是有很多層,有些材質永遠會蓋在其它材質上面.
路人:好簡單的介紹,我看你以後就放影片好了...

2011年3月12日 星期六

MapEdit - 介紹

c:另一個未完成的工具,編輯地圖的工具.

路人:很眼熟耶,就是那個Warcraft III的地圖嘛...,啊又偷拿別人的圖了哦.
c:別說偷嘛,練習總要素材嘛.
路人:我好像有看過別人做過了,而且做得比這個好耶.
c:當然了,這些東西不足以商業化,但是整理一番,做一些入門性質的教學也是不錯的.
路人:其實之前的BoneEdit有點混耶,很多東西都隨便帶過了.
c:嗯,確實是沒有好好的規劃,這次我想介紹仔細點.
路人:對啊,又沒人在趕你,寫詳細點再貼上來吧.
c:嗯,請耐心等待吧.

2011年3月9日 星期三

BoneEdit - 動作

c:終於完成了,看看最後的成果吧.

路人:為什麼我有種空虛的感覺啊,好像沒介紹什麼.
c:其實最後這個影片是有點多餘啦,因為前面的功能做好後,目地就是要可以編動作.
路人:移動那個左上角的刻度有什麼做用嗎?
c:那是一格一格的單張動作,編輯時,就選好某一格,然後調整骨骼的位置.
路人:哦,編了不少嘛...,你是不是很閒啊?
c:編動作確實是花了不少時間,現在不作這種事了.
路人:最後的那些動畫,就是那些單格的動作做內插所做出來的吧.
c:是啊,如果你有注意到,跑步的動作是8~15格作出來的,最後的出拳是43~45格.
路人:我覺得調的動作不夠細,很不專業耶.
c:別管這個了,下次就會再介紹新的工具.

2011年3月8日 星期二

BoneEdit - 權重

c:先來瞧瞧頂點的權重設定:

路人:解釋一下左上角數值要怎麼填吧.
c:那個值就是你在選擇頂點的時候,頂點會被改成這個權重值,最大只能輸入1,
  當你的一個頂點會被2個骨骼平均影響的話,那這個值要填0.5,
  然後先選第一個影響的骨骼,再選那個頂點,之後再選第二個影響的骨骼,
  最後再選同一個點頂就完成了.
路人:你是在繞口令嗎?這樣誰聽得懂呀!
c:配合影片,然後再自行體會吧...


//網格計算
memcpy(Form1->Mmd->Mesh, Form1->Mmd->MeshCopy, sizeof(Vector) * Form1->Mmd->MeshCount );
Form1->BoneCopy->ComputeWPos();
Form1->DeformBone( Form1->BoneCopy->Bone, Form1->Mmd->MeshCopy, Form1->Mmd->Mesh );

//最重要的,將頂點乘上權矩陣後,依對應的骨骼與權重作運算
void TForm1::DeformBone(gBone *rootBone, Vector *meshdata, Vector *defdata)
{
    if( !rootBone || !meshdata || !CV_weight)
        return;
    int loop,boneloop;
    float weight=0;
    Vector pre,post;
    gBone *curBone = rootBone->children;
    for (boneloop = 0; boneloop < rootBone->childCnt; boneloop++)
    {
for (loop=0;loop<Mmd->MeshCount;loop++)
{
            weight = CV_weight[rootBone->children[boneloop].id][loop];
            if (weight > 0.0)
            {
                pre[0] = meshdata[loop][0] - rootBone->children[boneloop].wpos[0];
                pre[1] = meshdata[loop][1] - rootBone->children[boneloop].wpos[1];
                pre[2] = meshdata[loop][2] - rootBone->children[boneloop].wpos[2];
                gVector tpost;
                MultVectorByMatrix(&rootBone->children[boneloop].matrix, pre, &tpost);
                post[0]=tpost.x,post[1]=tpost.y,post[2]=tpost.z;
           //處理權重
                defdata[loop][0] += ((post[0] - meshdata[loop][0]) * weight);
                defdata[loop][1] += ((post[1] - meshdata[loop][1]) * weight);
                defdata[loop][2] += ((post[2] - meshdata[loop][2]) * weight);
            }
        }
        if (curBone->childCnt > 0)
            DeformBone(curBone, meshdata, defdata);
        curBone++;
    }
}

//頂點與矩陣做運算
void TForm1::MultVectorByMatrix(gMatrix *mat, Vector v, gVector *result)
{
result->x = (mat->m[0] * v[0]) +
                    (mat->m[4] * v[1]) +
                    (mat->m[8] * v[2]) +
                    mat->m[12];
result->y = (mat->m[1] * v[0]) +
                    (mat->m[5] * v[1]) +
                    (mat->m[9] * v[2]) +
                    mat->m[13];
result->z = (mat->m[2] * v[0]) +
                    (mat->m[6] * v[1]) +
                    (mat->m[10] * v[2]) +
                    mat->m[14];
}

2011年3月6日 星期日

BoneEdit - 骨骼

c:骨骼的功能操作過程如下:

路人:那個骨骼資料從那裡來的啊?
c:自己先定義一個文字檔,填入編號、位置、相依關係等...
  主要是得到骨架的資料,載入工具後,就可以自由調整了.
路人:這種事用3DMAX來做,再導出骨骼不是更好?
c:沒錯,那這個工具也不用寫了,直接寫3DMAX外掛就好啦.
  反正不是為工作而做的,從無到有弄個編輯器也是有其中的樂趣嘛.
路人:嗯,那就抓些重點出來吧.
c:先看一些定義吧.

typedef struct
{
    float r,g,b;
} gColor;

struct gBone//一根骨骼
{
    long id;     // BONE ID
    char name[32];    // BONE NAME
    gBone *parent;     // POINTER TO PARENT BONE
    int childCnt;//子骨骼數量 // COUNT OF CHILD BONES
    gBone *children;//指向的子骨骼位置 // POINTER TO CHILDREN
    int childrenidx;//指向的子骨骼位置索引
    gMatrix matrix;//矩形的值
    Vector pos;
    Vector rot;
    Vector startrot;//初始旋轉量
    Vector startpos;//初始位置
    Vector wpos;//真實的世界位置
    int length;//長
    int width; //寬
    gColor color;
};
最重要的變數就是matrix了,模型的頂點都要乘上這個值,這樣模型就會跟著骨骼動作了,
它的定義前幾篇就有貼出來了,這裡我再貼一次.
typedef struct
{
    float m[16];
} gMatrix;

class CBone
{
public:
    CBone();
    virtual ~CBone();
    bool LoadBone( char *filename );//載入文字檔
    bool LoadBone_b( char *filename );//載入位元檔
    bool SaveBone_b( char *filename );//存入位元檔
    void Draw( GLenum mode );
    void Destroy( void );
    bool flag( void ){ if( Bone ) return true; else return false; }
    void AllColor( float r, float g, float b );//設定所有骨骼顏色
    void Color( int id, float r, float g, float b );//設定骨骼顏色
    void ComputeWPos( void );//算出每個骨骼的世界位置
    Vector CameraPoint;
    Vector CameraView;
    int BoneCount, Selectid;
    bool Show; //是否顥示出來
    gBone *Bone;
protected:
    void DrawSkeleton( gBone *rootBone, GLenum mode );
    void BoneBox( gBone *curBone );
    void CWPos( gBone *rootBone );//算出每個骨骼的世界位置
};

matrix怎麼算出來的呢?呼叫DrawSkeleton就可得到

void CBone::Draw( GLenum mode )
{
    if( !Bone )
        return;
    glPushMatrix();
    glTranslatef(Bone->startpos[0]+Bone->pos[0],
                 Bone->startpos[1]+Bone->pos[1],
                 Bone->startpos[2]+Bone->pos[2]);
    glRotatef(Bone->rot[2], 0.0f, 0.0f, 1.0f);
    glRotatef(Bone->rot[1], 0.0f, 1.0f, 0.0f);
    glRotatef(Bone->rot[0], 1.0f, 0.0f, 0.0f);
    DrawSkeleton(Bone,mode);
    glPopMatrix();
}

DrawSkeleton是個遞迴函式,因為骨頭是一層一層的

void CBone::DrawSkeleton( gBone *rootBone, GLenum mode )
{
    int loop;
    gBone *curBone;
    curBone = rootBone->children;
    for (loop = 0; loop < rootBone->childCnt; loop++)
    {
        glPushMatrix();
        glTranslatef(curBone->startpos[0]+curBone->pos[0],
                     curBone->startpos[1]+curBone->pos[1],
                     curBone->startpos[2]+curBone->pos[2]);
        glRotatef(curBone->rot[2], 0.0f, 0.0f, 1.0f);
        glRotatef(curBone->rot[1], 0.0f, 1.0f, 0.0f);
        glRotatef(curBone->rot[0], 1.0f, 0.0f, 0.0f);
        if( mode == GL_SELECT )
        {
            if( Show )
            {
                glLoadName(curBone->id);
                BoneBox( curBone );
            }
        }
        else
        {
            if( Show )
                BoneBox( curBone );
        }
        glGetFloatv(GL_MODELVIEW_MATRIX,curBone->matrix.m);///在這裡取得的矩陣就可以給模型用了
if (curBone->childCnt > 0)
   DrawSkeleton( curBone, mode );
glPopMatrix();
        curBone++;
    }
}

2011年3月5日 星期六

BoneEdit - 模型

c:我說明一下,這邊使用到的模型檔為MMD
路人:哦,有什麼意義嗎?
c:沒什麼,就只是一個副檔名
路人:之前你有提到,是從warcraft III提取出來的,
     我記得是叫MDX的模型檔,那從MDX轉MMD是怎麼弄啊?
c:就...一個小工具,然後.....你先看看吧.
路人:怎麼回事啊...
c:你看了就明白了.

路人:這是在做啥?為什麼不是那種按一個鈕就完成的
c:呃,手工的,要自己開檔找出檔案內有VRTX,PUTX,UVBX等標籤,後面會跟著資料的位址.
路人:哇,真是辛苦你了啊,但也太爛了吧,不用介紹了.
C:所以重點不在這裡,還是來看看BoneEdit的模型類別吧.

class CMmd
{
public:
    CMmd();
    virtual ~CMmd();
    bool Load( char *filename );
    void Destroy( void );
    int MeshCount; //頂點資料數量
    int UVCount; //貼圖資料數量
    Vector *Mesh;      //頂點資料
    Vector *MeshCopy;      //頂點資料
    gUV *UV;   //貼圖資料
    Vector *Normal;//向量資料
    char FileName[256];//檔案名稱
}

最主要的功能其實就是把模型載入,附上Load的程式碼

bool CMmd::Load( char *filename ){
    FILE *f;
    strcpy(FileName, filename);
    f = fopen( filename, "rb" );
    char *p;

    if( f )
    {
        int i;
        if( Mesh )
            free( Mesh );
        if( MeshCopy )
            free( MeshCopy );
        if( UV )
            free( UV );
        if( Normal )
            free( Normal );
        fread( &MeshCount, sizeof(int), 1, f );
        Mesh = (Vector *)malloc(sizeof(Vector) * MeshCount );
        MeshCopy = (Vector *)malloc(sizeof(Vector) * MeshCount );
        for( i=0;i<MeshCount;i++)
            fread( Mesh[i], sizeof(Vector), 1, f );
        memcpy( MeshCopy, Mesh, sizeof(Vector) * MeshCount );
        fread( &UVCount, sizeof(int), 1, f );
        UV = (gUV *)malloc(sizeof(gUV) * UVCount );
        for( i=0;i<UVCount;i++)
        {
            fread( &UV[i].u, sizeof(float), 1, f );
            fread( &UV[i].v, sizeof(float), 1, f );
        }
        fclose( f );
        Normal = (Vector *)malloc(sizeof(Vector) * MeshCount );
        memcpy(Normal,Mesh,sizeof(Vector) * MeshCount);
        for( i=0;i<MeshCount;i++)
        {
            Normal[i].Normalize();
        }
    }
    return true;
}

2011年3月4日 星期五

BoneEdit-Camera

我們需要一個攝影機的功能,方便視角轉來轉去,像下面的影片

class CCamera
{
public:
    CCamera();
    virtual ~CCamera();
    void UpData();//更新
    void Move(float vec);//前後移動
    void Strafe(float vec);//左右平移
    void SetPosition(Vector pos);//設定位置(觀看點隨位罝移動)
    Vector Position;//位置
    Vector ViewPoint;//觀看的目標
    Vector UpVector;//頭頂的位置
};

Vector是個向量的類別,包含了xyz的值.
最重要的Updata為
void CCamera::UpData()
{
    gluLookAt(  (GLfloat)Position[0], (GLfloat)Position[1], (GLfloat)Position[2],
                (GLfloat)ViewPoint[0], (GLfloat)ViewPoint[1], (GLfloat)ViewPoint[2],
                (GLfloat)UpVector[0], (GLfloat)UpVector[1], (GLfloat)UpVector[2] );
}
直接使用gluLookAt設定攝影機的參數,其它的函式都是一些數學運算,像是
void CCamera::SetPosition(Vector pos)//設定位置
{
    Vector v;
    v = pos - Position;
    ViewPoint += v;
    Position = pos;
}
其它的函式就不貼程式碼了.

2011年3月3日 星期四

工具BoneEdit

路人:這個工具是用BCB寫的吧,看附圖左上角的LOGO就知了.
c:是啊
路人:看起來沒什麼.
c:雖然這個BoneEdit只是個小軟體,但內容也不少,你看看用到的元件

路人:哇,那程式碼貼出來不就一狗票.
c:這樣好了,先別管元件,我主要介紹類別的功能,有需要的,我再說明裡面程式的寫法.

OpenGL的類別,主要是初始OpenGL
class CGL
{
public:
CGL();
virtual ~CGL();
void Resize(GLsizei width, GLsizei height, GLsizei depth);//視窗大小更動時呼叫
        bool Initial(HWND hWnd, unsigned int Width, unsigned int Height, int bits );//初始化
        void NowDC(void);//建立dc
        HDC m_hDC;
private:
int m_ScrWidth;//寬
int m_ScrHeight;//高
        int m_Depth;//深度
HGLRC m_hRC;//渲染環境
HWND m_hWnd;//渲染環境對應的視窗
};

其實看了上一篇的附圖,就可以知道,這個工具是BCB寫的.
在BCB內的用法為:
CGL *GL;  <--在Unit1.h內的TForm1宣告

Unit1.cpp
void __fastcall TForm1::FormCreate(TObject *Sender)//初始化
{
    GL = new CGL();
    if( GL->Initial( Panel1->Handle, Panel1->ClientWidth, Panel1->ClientHeight, 32 ) )
    {
Timer1->Enabled = true;
    }
}
//更新就如下使用(用到了Timer元件,至於Timer的Interval,就設為1)
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
    GL->NowDC();  //視窗移動時,會破壞畫面,用DC重建RC
    GL->Resize( Panel1->ClientWidth, Panel1->ClientHeight, 50000 );
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);
    glClearColor (0, 0, 0, 0.0f);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    //*******************
    //這裡處理繪製
    //*******************

    SwapBuffers(GL->m_hDC);//繪製好的圖案顯示出來
}

路人:感覺不是很高明耶,而且效率應該很差吧...
c:真是不好意思,就寫寫程式...好玩嘛,
  順便補上使用的到.h

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <math.h>    
#include <iostream.h>
#include <commctrl.h>
#include <windowsx.h>
#include <mmsystem.h>

#include <gl\gl.h> // Header File For The OpenGL32 Library
#include <gl\glu.h> // Header File For The GLu32 Library
#include <gl\glaux.h> // Header File For The GLaux Library

typedef struct
{
    float x,y,z;
} gVector;

typedef struct
{
    float u,v;
} gUV;

typedef struct
{
float m[16];
} gMatrix;

#define SafeDelete(pObject) if(pObject!=NULL) {delete pObject; pObject=NULL;}

2011年3月2日 星期三

一段對話

c:看了上一篇武器光影的效果後,應該會覺得模型很眼熟吧...
路人:哦,這不是Warcraft III的模型嗎.
c:沒錯,就是Warcraft III的模型.
路人:這沒什麼啊,網路上有一堆工具都把資料都解出來了,沒什麼特別的
c:呃,的確是沒什麼特別,不過再看仔細一點,一定會覺得奇怪.
路人:那個動作怎麼怪怪的啊...,好像跟原廠不太一樣耶!Arthas王子有這一招旋風大鐵鎚嗎?
     而且跑步的姿勢也不太一樣了,是把資料導回3DMAX再做新的嗎?
c:唉,若是這樣就好了,我用了最笨的做法,做了一個工具,自己要重建骨架,設定頂點權重,
    再調新的動作,你看,工具長這個樣子

路人:你有病啊,是不是太閒了...
c:知道了,以後會少幹這種傻事了...
路人:那至少交代一下怎麼做的,不要讓以後的人跟著你走錯了.

c:嗯,等我有空吧...
路人:&^%$#$%^&$$@$#$#


下次就從這個工具再往下介紹.


OpenGL 武器光影的效果

先看一下效果:

哦,感覺有點差哩,武器劃出的光影怎麼跟市面上的遊戲差那麼多...
這個嘛,以前練習的作品,就不用太再意了.

順便補上之前的物體發光效果,看影片比較有感覺...
細節是如何做的呢?有時間再慢慢介紹了.