2011年7月18日 星期一

收到了google寄的AdSense PIN 碼

照張像,記念一下.

2011年5月21日 星期六

android WebView 放入 LinearLayout 的問題

  在將 WebView 放入 LinearLayout 時發現點擊網頁的連結有問題,
像是用 google 搜尋的網址,下一頁功能只能使用一次,之後點擊也沒有反應,
不過FaceBook給的函式庫就不會了,趕緊再看一下它的程式碼,發現我少了這個參數...

final FrameLayout.LayoutParams FILL =
      new FrameLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
                        ViewGroup.LayoutParams.FILL_PARENT);


然後將這個參數設定給 WebView

mWebView.setLayoutParams(FILL);  <--- 這樣網頁的功能就正常了

感覺這個參數和點擊不正常之間沒什麼關係...,有誰了解原理就解答一下吧.

2011年5月1日 星期日

android 離開程式的 dialog

  想寫個功能,出現錯誤時,秀個dialog,然後使用者按下ok,程式就退出,
不過使用 finish(); 時沒那麼順利,要在Activity類別範圍內才能呼叫.
可能有其它的做法吧...,不過懶得研究了,就先使用 System.exit(0); 代替.
另外還有個問題,若是使用者不按ok,直接按離開鈕,那就把dialog關掉了.
所以先如下解決:

public class exitDialog extends AlertDialog {
    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event){
        System.exit(0);
        return false;
    }
}

反正不管按下什麼鈕,離開就對了.

2011年4月18日 星期一

android fackbook feed

  依照facebook的範例,用dialog開了塗鴉牆的網頁,不過要怎麼預先輸入訊息呢?
查了一下,發現在Facebook.java內還有另一個dialog

public void dialog(Context context, String action, Bundle parameters,
            final DialogListener listener)

最後都會呼叫到這一個函式.
而多了一個parameters參數,就可以用來預先替使用者輸入訊息,
其實要傳給網頁的參數都可以靠這個.
參數產生方法如下:
Bundle parameters=new Bundle();
parameters.putString("message", "hi");//進塗鴉牆頁面自動填入的訊息

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 武器光影的效果

先看一下效果:

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

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

2011年2月27日 星期日

OpenGL 發射火焰的效果

光看靜止的圖片有時候還是看不出個所以然,所以這次我用CamStudio來抓取影像,
只是效果不是是很好.頓頓的,有空的話,再試試別種軟體來抓影片.
下面就是音速小子發射火焰槍的效果:

我把重點程式碼貼上,火焰槍就是這樣做出來的:

Flamethrower.h

struct Flame //火的資料(很多的火組成火焰)
{
Vector Position; //位置
Vector ViewPoint;//方向
int Life;//生命
    float Size; //大小
    float Rotate; //不斷的旋轉角度,使火焰看起來較活
};
const int MAX_FLAME_COUNT = 1000;

class Flamethrower
{
public:
    Flamethrower();
    ~Flamethrower();
    bool Initial(char *texture);
    void Fire(Vector Position,
              Vector ViewPoint,
              int Life);//發射火焰
    void UpData(Vector CameraPosition, int time);
    void Draw(Vector up, Vector right);
    CTexture Texture;
protected:
    Flame FlamePool[MAX_FLAME_COUNT];//一個火焰"坑"(就是存放很多的火)
    int SortIndex[MAX_FLAME_COUNT]; //排序的索引陣列
    int Count; //火的數量
    int time1,time2;//更新的變數
};

這個類別應該是很簡單,不用多做解釋,直接看Flamethrower.cpp
Flamethrower::Flamethrower()
{
   Count = 0;
   time1 = 0;
}

Flamethrower::~Flamethrower()
{

}

bool Flamethrower::Initial(char *texture)
{
    srand(GetTickCount());
    if( !Texture.LoadTGA(texture) )
       return false;
    return true;
}

void Flamethrower::Fire(Vector Position, Vector ViewPoint, int Life)
{
    int i,temp;
    if (Count < MAX_FLAME_COUNT) //若沒有超過限制數量
    {
        temp = Count;
        for(i=0;i<Count;i++)
        {
            if(FlamePool[i].Life == 0)
            {
                temp = i;
                break;
            }
        }
        if(temp==MAX_FLAME_COUNT)
            return;
        FlamePool[temp].Position = Position;
//配合音速小子攻擊時槍會"上下"震動
if(rand()%100 < 50)
        FlamePool[temp].Position[1] += rand()%3;
else
   FlamePool[temp].Position[1] -= rand()%3;
//
        FlamePool[temp].ViewPoint = ViewPoint;
        //往x軸擴展出去的效果
        if(rand()%100<50)
            FlamePool[temp].ViewPoint[0] += (float)((rand()%100)/500.00);
        else
            FlamePool[temp].ViewPoint[0] -= (float)((rand()%100)/500.00);

        //往y軸上升的效果
        FlamePool[temp].ViewPoint[1] += (float)((rand()%100)/90.00);

        //往z軸擴展出去的效果
        if(rand()%100<50)
            FlamePool[temp].ViewPoint[2] += (float)((rand()%100)/500.00);
        else
            FlamePool[temp].ViewPoint[2] -= (float)((rand()%100)/500.00);

        FlamePool[temp].Life = Life;
        FlamePool[temp].Size = 1;
        FlamePool[temp].Rotate = rand()%360;
        SortIndex[temp] = temp;

        if (temp == Count && Count < MAX_FLAME_COUNT-1) //若沒有超過限制數量
            Count++;
    }
}

void Flamethrower::UpData(Vector CameraPosition, int time)
{
    int i,j;

    if(time-time1 > 1)
    {
        time1 = time;
        for (i=0;i<Count;i++)
        {
            if (FlamePool[i].Life > 0)
            {
                Vector delta(FlamePool[i].ViewPoint[0]-FlamePool[i].Position[0],
                             0,
                             FlamePool[i].ViewPoint[2]-FlamePool[i].Position[2]);
                FlamePool[i].Position += delta * 6;
                FlamePool[i].ViewPoint += delta * 6;
                FlamePool[i].Life--;
                FlamePool[i].Size += .6;
                FlamePool[i].Rotate += 4+rand()%8;
                if( FlamePool[i].Rotate > 360 )
                    FlamePool[i].Rotate = 1;
            }
        }

        //做排序(離Camera越遠,就要越先畫出來)
        for (i=Count-1;i>0;i--)
        {
            for (j=1;j<=i;j++)
            {
                Vector v1 = FlamePool[SortIndex[j-1]].Position - CameraPosition;
                Vector v2 = FlamePool[SortIndex[j]].Position - CameraPosition;
                double length1 = (v1[0] * v1[0]) + (v1[1] * v1[1]) + (v1[2] * v1[2]);
                double length2 = (v2[0] * v2[0]) + (v2[1] * v2[1]) + (v2[2] * v2[2]);
                if ( length1 < length2 ) //v2距離較遠,與v1交換
                {
                    int temp = SortIndex[j-1];
                    SortIndex[j-1] = SortIndex[j];
                    SortIndex[j] = temp;
                }
            }
        }
    }
}

void Flamethrower::Draw(Vector up, Vector right)
{
    int i,j;
    Vector v;
    for (i=0;i<Count;i++)
    {
        if (FlamePool[SortIndex[i]].Life > 0
   && SphereTest(FlamePool[SortIndex[i]].Position[0], FlamePool[SortIndex[i]].Position[1], FlamePool[SortIndex[i]].Position[2], FlamePool[SortIndex[i]].Size))
        {
            glPushMatrix();
                glTranslatef(FlamePool[SortIndex[i]].Position[0], FlamePool[SortIndex[i]].Position[1], FlamePool[SortIndex[i]].Position[2]);
                glColor4f(1.0f,1.0f,1.0f,FlamePool[SortIndex[i]].Life/96.00);
                if( up[1] == 1 ) //正上方是頭頂,所以方塊對z軸旋轉
                    glRotatef(FlamePool[SortIndex[i]].Rotate,0,0,1);
                if( up[2] == -1 )//正上方是眼前,所以方塊對y軸旋轉
                    glRotatef(FlamePool[SortIndex[i]].Rotate,0,1,0);
   glBegin(GL_QUADS);
   v = up*(-FlamePool[SortIndex[i]].Size) + right*(-FlamePool[SortIndex[i]].Size);
       glTexCoord2f(0.0f, 0.0f);
   glVertex3fv(v);
   v = up*(-FlamePool[SortIndex[i]].Size) + right*FlamePool[SortIndex[i]].Size;
     glTexCoord2f(1.0f, 0.0f);
   glVertex3fv(v);
                    v = up*(FlamePool[SortIndex[i]].Size) + right*(FlamePool[SortIndex[i]].Size);
                    glTexCoord2f(1,1);
                    glVertex3fv(v);
   v = up*(FlamePool[SortIndex[i]].Size) + right*(-FlamePool[SortIndex[i]].Size);
     glTexCoord2f(0, 1);
   glVertex3fv(v);
   glEnd();
            glPopMatrix();
        }
    }
}

做出來的效果雖不是最佳,但也有幾分樣了,而且沒有加入讓火焰貼圖面向攝影機的功能,所以實用性質不大,(那....為什麼放上來啊?....)

OpenGL物體發光效果

以前有一段時間,練習過OpenGL,現在很少用了,最近整理資料時,把以前練習寫的程式翻出來了,執行了一下,畫面如下:

雖然只是個小程式,但其實也包含了不少東西,有地形,影子,水波,公告板,雨水,各式特效等...
其中比較特別的是人物身上會有向外發散的淡淡金光,怎麼做的呢?其實就是把人物畫到貼圖上去,因為是向外發散的光,所以在一個frame內要多畫幾次,還要調整大小,這樣做好的貼圖再繪製出來就有這種效果了,
下面貼上程式碼片斷:

//先準備好貼圖
void HeroLight::Initial( void )
{
unsigned int* data;

// Create Storage Space For Texture Data (128x128x4)
data = (unsigned int*)new GLuint[((128 * 128)* 4 * sizeof(unsigned int))];
ZeroMemory(data,((128 * 128)* 4 * sizeof(unsigned int)));// Clear Storage Memory

glGenTextures(1, &Texture); // Create 1 Texture
glBindTexture(GL_TEXTURE_2D, Texture); // Bind The Texture
glTexImage2D(GL_TEXTURE_2D, 0, 4, 128, 128, 0,
GL_RGBA, GL_UNSIGNED_BYTE, data);// Build Texture Using Information In data
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

delete [] data;
}


RenderToTextureBegin與RenderToTextureEnd是拿來夾住要繪製的模型的
void HeroLight::RenderToTextureBegin( int w, int h )
{
    GLfloat glfMaterialColor[]={0.2f,0.2f,.1f,.4f}; // Set The Material Color
GLfloat specular[]={1.0f,1.0f,1.0f,1.0f};
    glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,glfMaterialColor);
glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,specular);
    
    Witch = w;
    Height = h;
    glViewport(0,0,128,128);
}

void HeroLight::RenderToTextureEnd( void )
{
    glBindTexture(GL_TEXTURE_2D,Texture);  
    //Copy Our ViewPort To The Texture (From 0,0 To 128,128... No Border)
    glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 0, 0, 128, 128, 0);
    //glClearColor(.0f, .0f, .5f, .5);// Set The Clear Color To Medium Blue
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// Clear The Screen And Depth Buffer
    glViewport(0 , 0, Witch, Height);
}

要像這樣使用...

HeroLight.RenderToTextureBegin(Width,Height);
    glDepthFunc(GL_LESS);
    glCullFace(GL_BACK);

    glDisable(GL_BLEND);
    glDisable(GL_TEXTURE_GEN_S);
    glDisable(GL_TEXTURE_GEN_T);

    glEnable(GL_TEXTURE_2D);
    glEnable(GL_CULL_FACE);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_FOG);
    glDepthFunc(GL_LEQUAL);
    glFrontFace(GL_CW);
    glPolygonMode(GL_FRONT, GL_FILL);
    //角色///////////////////////////////////////////////////////////////////
    glDepthFunc(GL_LEQUAL);
    glFrontFace(GL_CW);
    glPolygonMode(GL_FRONT, GL_FILL);
    Md2Model.GetAnimate(time);
    Md2Model.SetPosition(Vector(Md2Model.GetXPosition(),
                                26,//Terrain.GetHeight(Md2Model.GetPosition())+26,
                                Md2Model.GetZPosition()));
    glBindTexture(GL_TEXTURE_2D,Md2Model.texture);
    //glDisable(GL_TEXTURE_2D);
    Md2Model.DrawModel();
    glFrontFace(GL_CCW);
    ////////////////////////////////////////////////////////////////////////
HeroLight.RenderToTextureEnd();


    //畫出模型
    /////////////////////////////////////////////////////////////////////
    glDepthFunc(GL_LESS);
    glCullFace(GL_BACK);

    glDisable(GL_BLEND);
    glDisable(GL_TEXTURE_GEN_S);
    glDisable(GL_TEXTURE_GEN_T);

    glEnable(GL_TEXTURE_2D);
    glEnable(GL_CULL_FACE);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_FOG);
    glDepthFunc(GL_LEQUAL);
    glFrontFace(GL_CW);
    glPolygonMode(GL_FRONT, GL_FILL);
    Md2Model.GetAnimate(time);
    Md2Model.SetPosition(Vector(Md2Model.GetXPosition(),
                                26,//Terrain.GetHeight(Md2Model.GetPosition())+26,
                                Md2Model.GetZPosition()));
    glBindTexture(GL_TEXTURE_2D,Md2Model.texture);
    //glDisable(GL_TEXTURE_2D);
    Md2Model.DrawModel();
    glFrontFace(GL_CCW);
    ////////////////////////////////////////////////////////////////////////


    HeroLight.Draw(10,.03);//最後將特效畫出

畫出的程式碼:

void HeroLight::Draw( int times, float inc ) //time約1 - 30 inc約 0.02 - 0.09
{
    float spost = 0.0f; // Starting Texture Coordinate Offset
float alphainc = 0.9f / times; // Fade Speed For Alpha Blending
float alpha = 0.2f; // Starting Alpha Value

// Disable AutoTexture Coordinates
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);

glEnable(GL_TEXTURE_2D);// Enable 2D Texture Mapping
glDisable(GL_DEPTH_TEST);// Disable Depth Testing
    glDisable(GL_LIGHTING);
glBlendFunc(GL_SRC_ALPHA,GL_ONE);// Set Blending Mode
glEnable(GL_BLEND); // Enable Blending
glBindTexture(GL_TEXTURE_2D,Texture);// Bind To The Blur Texture
ViewOrtho(); // Switch To An Ortho View

alphainc = alpha / times;// alphainc=0.2f / Times To Render Blur

glBegin(GL_QUADS); // Begin Drawing Quads
for (int num = 0;num < times;num++)
{
glColor4f(1.0f, 1.0f, .0f, alpha);
glTexCoord2f(0+spost,1-spost);
glVertex2f(0,0);

glTexCoord2f(0+spost,0+spost);
glVertex2f(0,Height);

glTexCoord2f(1-spost,0+spost);
glVertex2f(Witch,Height);

glTexCoord2f(1-spost,1-spost);
glVertex2f(Witch,0);

spost += inc; // Gradually Increase spost (Zooming Closer To Texture Center)
alpha = alpha - alphainc;// Gradually Decrease alpha (Gradually Fading Image Out)
}
glEnd();// Done Drawing Quads

ViewPerspective();// Switch To A Perspective View
}


//調整為2D繪製
void HeroLight::ViewOrtho( void )
{
    glMatrixMode(GL_PROJECTION); // Select Projection
glPushMatrix(); // Push The Matrix
glLoadIdentity(); // Reset The Matrix
glOrtho( 0, Witch , Height , 0, -1, 1 );
glMatrixMode(GL_MODELVIEW); // Select Modelview Matrix
glPushMatrix(); // Push The Matrix
glLoadIdentity();

}

//恢復之前的繪製矩陣
void HeroLight::ViewPerspective( void )
{
glMatrixMode( GL_PROJECTION ); // Select Projection
glPopMatrix(); // Pop The Matrix
glMatrixMode( GL_MODELVIEW );// Select Modelview
glPopMatrix(); // Pop The Matrix

}

其實要做到物體發光的效果,應該是有其它更好的做法,沒記錯的話,這應該是8年前寫的東西了,還有其它雜七雜八的東西,也打算整理一下,丟上來做個記錄.

2011年2月26日 星期六

用ACE練習寫個簡單的server class(下)

剩下最後的關鍵了,HA_Proactive_Service主要做傳送接收的處理.


tatic ACE_Recursive_Thread_Mutex _lock;

int HA_Proactive_Service::initiate_read_stream(void)//開始一筆新的接收
{
// ACE_DEBUG( (LM_DEBUG, ACE_TEXT("client id : %d\n"),stAppid.id));
ACE_NEW_NORETURN (recv_data_, ACE_Message_Block (sizeof(PacketHeader), SBN_QUE_NONE));
ACE_HANDLE handle = this->handle ();
this->recv_data_->copy ((const char *)&handle, sizeof(ACE_HANDLE));
this->reader_.read (*recv_data_, recv_data_->space ());
return 0;
}
HA_Proactive_Service::HA_Proactive_Service()
{
recv_data_ = NULL;
stAppid.bOnline = false;
}
HA_Proactive_Service::~HA_Proactive_Service ()
{
if (this->handle () != ACE_INVALID_HANDLE)
ACE_OS::closesocket (this->handle ());
}

void HA_Proactive_Service::init( HA_Proactive_Acceptor *acceptor, int id )
{
  this->acceptor_ = acceptor;
  //this->acceptor_->ser[id].stAppid.id = id;
  stAppid.id = id;
  stAppid.num = 0;
}
void HA_Proactive_Service::SendData(char *buf)
{
#ifdef WIN32
size_t len = strlen(buf)+1;
#else
int len = strlen(buf)+1;
#endif

ACE_Message_Block *temp = new ACE_Message_Block(len);
temp->copy(buf);
temp->wr_ptr(len+1);
int nResult = writer_.write(*temp,len);

//呼叫了傳送後temp這個指標不可再用了

if( nResult != 0 )
ACE_DEBUG( (LM_DEBUG,"Write data failed:%s\n",buf) );
else
ACE_DEBUG( (LM_DEBUG,"send data(%d):%s\n",stAppid.id, buf) );//temp->rd_ptr()
}


void HA_Proactive_Service::handle_time_out(const ACE_Time_Value &tv, const void *p)
{
//ACE_DEBUG((LM_DEBUG,"time out: %d\n",(int*)p));
ACE_Proactor::instance()->cancel_timer(*this);
}

void HA_Proactive_Service::open (ACE_HANDLE h, ACE_Message_Block& message_block)//在這裡完成初始化的準備
{
this->handle(h);//新的socket句柄產生了

if (this->reader_.open (*this) != 0 || this->writer_.open (*this) != 0   )
{

this->acceptor_->free_handler( this );
return;
}

if (this->initiate_read_stream () == -1)
return;

   //取客戶端資料
ACE_INET_Addr addr;
ACE_SOCK_SEQPACK_Association ass=ACE_SOCK_SEQPACK_Association(h);
size_t addr_size=1;
//ass.get_local_addrs(&addr,addr_size);//取本地端
ass.get_remote_addrs(&addr,addr_size);
stAppid.iPort = addr.get_port_number();
stAppid.sIp = addr.get_host_addr();
stAppid.bOnline = true;
stAppid.num = this->acceptor_->cNum;
++this->acceptor_->cNum;
//ACE_Guard <ACE_Recursive_Thread_Mutex> locker (_lock);

acceptor_->mpInfo.insert(std::make_pair(stAppid.id, stAppid));

ACE_Proactor::instance()->schedule_timer(*this, (void *)stAppid.id, ACE_Time_Value(1), ACE_Time_Value(1));

//******************************************************************************************
ACE_Message_Block *putdata;
CmdPacker pack;
pack.id = stAppid.id;
pack.num = stAppid.num;
pack.bsize = 0;
pack.cmd = SBN_QUE_CONNECT;
ACE_NEW_NORETURN (putdata, ACE_Message_Block(sizeof(CmdPacker), SBN_QUE_CONNECT));
putdata->copy ((const char *)&pack, sizeof(CmdPacker));
acceptor_->RQData.putq(putdata);
//*****************************************************************************************

//ACE_DEBUG( (LM_DEBUG, ACE_TEXT("connect: %d %s\n"), stAppid.iPort ,stAppid.sIp.c_str() ) );

}
void HA_Proactive_Service::handle_read_stream (const ACE_Asynch_Read_Stream::Result &result)
{
//result.message_block ().rd_ptr ()[result.bytes_transferred ()] = '\0';//數到的字串流結尾補結束字元

if (!result.success () || result.bytes_transferred () == 0)//傳輸失敗或傳輸0個字節,客戶斷開連接
{
//ACE_DEBUG( (LM_DEBUG, ACE_TEXT("client close : %d %d\n"), result.handle (),this->handle() ) );
result.message_block ().release ();
this->acceptor_->free_handler( this );
}
else
{
//result.message_block ().rd_ptr ()[result.bytes_transferred ()] = '\0';//數到的字串流結尾補結束字元
int len=0;
 
if (this->recv_data_->length() < sizeof(PacketHeader))// 數據包長度信息還未接收完
{
this->reader_.read (*recv_data_, recv_data_->space ());
return;
}
PacketHeader * hdr = reinterpret_cast<PacketHeader *> (this->recv_data_->rd_ptr());
ACE_Message_Block * data_mb = this->recv_data_->cont();
//將收到的4個字元轉成數值
len = (hdr->length[0]-'0')*1000 + (hdr->length[1]-'0')*100 + (hdr->length[2]-'0')*10 + (hdr->length[3]-'0');

if (!data_mb)// 剛剛接收完長度信息
{
//長度不對要做錯誤處理
if( len > 1024 )
len = 1024;
if( len < 1 )
len = 1;

ACE_NEW (data_mb, ACE_Message_Block(len));
this->recv_data_->cont (data_mb);
}
if (data_mb->length () == len)// 數據已接收完
{
//int cmd = (data_mb->rd_ptr()[0]-'0')*1000 + (data_mb->rd_ptr ()[1]-'0')*100 + (data_mb->rd_ptr ()[2]-'0')*10 + (data_mb->rd_ptr ()[3]-'0');//將4個字元轉成命令
ACE_Message_Block *putdata;
//CmdPacker pack;
//if( cmd < CMD_NONE )
// cmd = CMD_NONE;
recvpack.id = stAppid.id;
recvpack.num = stAppid.num;
recvpack.bsize = len;
recvpack.cmd = SBN_QUE_DATA;
#ifdef WIN32
memcpy(recvpack.data,data_mb->rd_ptr(),len);//strcpy_s(recvpack.data,256,data_mb->rd_ptr());
#else
strcpy(recvpack.data,data_mb->rd_ptr());
#endif
ACE_NEW_NORETURN (putdata, ACE_Message_Block(sizeof(CmdPacker), SBN_QUE_DATA));
putdata->copy((const char *)&recvpack, sizeof(CmdPacker));
//ACE_DEBUG( (LM_DEBUG,"read_stream:%d %d %d %s\n", pack.id, pack.num, pack.bsize, pack.data) );

acceptor_->RQData.putq(putdata);//,(ACE_Time_Value *) &ACE_Time_Value::zero);
recv_data_->release();
this->initiate_read_stream();// 再繼續接收下一個數據包
return;
}

this->reader_.read (*data_mb, data_mb->space ());// 否則繼續接收該數據包
}
}

void HA_Proactive_Service::handle_write_stream (const ACE_Asynch_Write_Stream::Result &result)
{
//ACE_DEBUG( (LM_DEBUG,"handle_write_stream:%s\n",result.message_block().rd_ptr ()) );
result.message_block ().release ();
}

而連線,傳送,接收的運用就由 HA_Proactive_Acceptor驅動


HA_Proactive_Acceptor::HA_Proactive_Acceptor() : ACE_Asynch_Acceptor<HA_Proactive_Service>()
{
cNum = 1;
ser = NULL;
}

HA_Proactive_Acceptor::~HA_Proactive_Acceptor(void)
{
Destroy();
}
void HA_Proactive_Acceptor::Destroy(void)
{
if( ser )
delete[] ser;
}
void HA_Proactive_Acceptor::free_handler( HA_Proactive_Service * service )
{
ACE_Guard <ACE_Recursive_Thread_Mutex> locker (_lock);
ACE_OS::closesocket(service->handle ());
std::map<int, CData>::iterator mpIter;
for (mpIter = mpInfo.begin(); mpIter != mpInfo.end(); ++mpIter)  
{
//if( service->stAppid.iPort != mpIter->second.iPort ) continue;
//if( service->stAppid.sIp != mpIter->second.sIp ) continue;
if( service->stAppid.id != mpIter->second.id ) continue;
mpInfo.erase(mpIter);
break;
}


//******************************************************************************************
ACE_Message_Block *putdata;
CmdPacker pack;
pack.id = service->stAppid.id;
pack.num = service->stAppid.num;
pack.bsize = 0;
pack.cmd = SBN_QUE_DISCONNECT;
ACE_NEW_NORETURN (putdata, ACE_Message_Block(sizeof(CmdPacker), SBN_QUE_DISCONNECT));
putdata->copy((const char *)&pack, sizeof(CmdPacker));
RQData.putq(putdata);
//*****************************************************************************************

service->stAppid.bOnline = false;
service->stAppid.num = 0;
this->handler_list_.push_back( service );

}

int HA_Proactive_Acceptor::validate_connection(const ACE_Asynch_Accept::Result& result,  const ACE_INET_Addr &remote, const ACE_INET_Addr& local)
{
return 0;
}

HA_Proactive_Service * HA_Proactive_Acceptor::make_handler (void)
{
if( this->handler_list_.empty() )
{
ACE_DEBUG( (LM_DEBUG,"Connect full\n") );
return 0;
}
HA_Proactive_Service *service = this->handler_list_.front();
this->handler_list_.pop_front();
return service; //得到處理事件的句柄後,前攝器會調用處理事件的open方法   HA_Proactive_Service::open
}

void HA_Proactive_Acceptor::init_handlers(int scount)
{
ServiceCount = scount;
ser = new HA_Proactive_Service[ServiceCount];
for( int i = 0; i < ServiceCount; ++i )
{
//HA_Proactive_Service * service;
//ACE_NEW( service, HA_Proactive_Service );
//service->init( this );
ser[i].init(this,i);
this->handler_list_.push_back( &ser[i] );//service );
}
}

其實主要的用意就只是把ACE再包成一個容易使用的類別,大家可以參考看看

2011年2月25日 星期五

用ACE練習寫個簡單的server class(中)

補上.cpp的程式碼

SBNet.cpp


CSBNet::CSBNet()
{
ACE::init();
Net = new SBaseNet();
}
CSBNet::~CSBNet()
{
ACE::fini();
}
bool CSBNet::Start(int scount)
{
return Net->Start(scount);
}
bool CSBNet::Start(int port,int scount)
{
return Net->Start(port,scount);
}
bool CSBNet::End(void)
{
return Net->End();
}
void CSBNet::Send(int id, char *data )
{
Net->Send(id, data);
}
char *CSBNet::Receive(void)
{
return Net->Receive();
}
上面就是將SBaseNet包裝起來

SBaseNet類別

SBaseNet::SBaseNet():Port(ACE_DEFAULT_SERVER_PORT)
{
}

SBaseNet::~SBaseNet()
{
}

bool SBaseNet::Start(int scount)
{
aio_acceptor.init_handlers(scount);
return this->activate();
}
bool SBaseNet::Start(int port, int scount)
{
Port = port;
aio_acceptor.init_handlers(scount);
return this->activate();
}

int SBaseNet::svc()
{
ACE_INET_Addr addr( Port );
if (0 != aio_acceptor.open (addr,0, 0, ACE_DEFAULT_ASYNCH_BACKLOG, 1, 0, 0))
ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("SBaseNet acceptor open")), 1);

ACE_DEBUG ((LM_DEBUG, ACE_TEXT("SBaseNet start\n")));
//ACE_Time_Value oHdlTime(1);
//while(run)
{
// oHdlTime = 1;
ACE_Proactor::instance()->proactor_run_event_loop();//oHdlTime);
}
ACE_DEBUG ((LM_DEBUG, ACE_TEXT("SBaseNet ended\n")));
return 0;

}

bool SBaseNet::End(void)
{
ACE_Proactor::instance()->proactor_end_event_loop();
this->wait();
aio_acceptor.Destroy();
return 0;
}

void SBaseNet::Send(int id, char *data )
{
aio_acceptor.ser[id].SendData(data);
}
char *SBaseNet::Receive(void)
{
return aio_acceptor.RQData.Receive();
}


接收資料的類別

RecvQueue::RecvQueue()
{
//this->msg_queue_->high_water_mark(655350);
}
RecvQueue::~RecvQueue()
{

}
int RecvQueue::open(void)
{
return this->activate();
}
int RecvQueue::close(void)
{
/*
ACE_Message_Block * hangup;
ACE_NEW_RETURN (hangup, ACE_Message_Block(0, ACE_Message_Block::MB_HANGUP), -1);
this->putq (hangup);
this->wait ();
*/
return 0;
}
char *RecvQueue::Receive( void )
{
ACE_Message_Block *message = NULL;
int result;
result = this->getq(message,(ACE_Time_Value *) &ACE_Time_Value::zero);

if( result > -1 && message )
{
CmdPacker *hdr = reinterpret_cast<CmdPacker *> (message->rd_ptr ());
//ACE_DEBUG((LM_DEBUG, ACE_TEXT("recv:%d %d %d %s\n",hdr->id,hdr->num,hdr->bsize, hdr->data)));
//ACE_DEBUG((LM_DEBUG, ACE_TEXT("recv:%d \n",hdr->id)));
ReadBuf[0] = (char)message->msg_type();
if( SBN_QUE_DATA == ReadBuf[0] )
memcpy(ReadBuf,(char*)hdr,16+hdr->bsize);
else
memcpy(ReadBuf,(char*)hdr,16);
message->release();
}
else
ReadBuf[0] = SBN_QUE_NONE;
return ReadBuf;
}

接下來剩HA_Proactive_Acceptor和HA_Proactive_Service,貼到下篇好了,不然這一堆程式碼,看得頭都昏了...