建議讀者對應 hge 的官方的例子:tutorial 02 - using input, sound and rendering 來閱讀本文
渲染:
在 hge 中,四邊形是一種圖元,對應了結構體 hgequad,另外還有三角形圖元,對應 hgetriple,為了渲染,我們現在需要使用 hgequad 結構體,這個結構體如下:
struct hgequad
{
hgevertex v[4]; // 頂點描述了這個四邊形
htexture tex; // 紋理的句柄或者為0
int blend; // 混合模式(blending mode)
};
hge 中圖元對應的結構體總含有這3個部分:頂點,紋理句柄,混合模式
struct hgevertex
float x, y; // 螢幕的 x,y 坐标
float z; // z-order,範圍 [0, 1]
dword col; // 頂點的顔色
float tx, ty; // 紋理的 x,y 坐标(指派前需要規格化坐标間隔,使得 tx,ty 取值範圍在[0,1])
規格化坐标間隔在後面的例子中會談到
1. 顔色的表示:
顔色使用32位表示,從左開始,8位為 alpha 通道,8位紅色,8位綠色,8位藍色
對于後24位,如果全部為0,表示黑色,如果全部為1,表示白色
2. 定義顔色的運算:
我們把顔色看成一個四維向量,即 alpha 通道,紅色,綠色,藍色這四個分量
<1> 顔色是可以相乘的
顔色的相乘是對應的四個分量分别相乘的結果,即:alpha 通道的值與 alpha 通道的值相乘,紅色的值與紅色的值相乘,綠色的值與綠色的值相乘,藍色的值與藍色的值相乘。
<2> 顔色是可以相加的
同上,對應分量相加。
顔色的每個分量使用浮點數表示,範圍是[0-1],相加操作可能導緻溢出,一種處理的方式就是,如果溢出,則設定值為1。
3. 混合模式:
1)blend_coloradd
表示頂點的顔色與紋理的紋元(texel)顔色相加,這使得紋理變亮,可見頂點顔色為 0x00000000 将不造成任何影響。
2)blend_colormul
表示頂點的顔色與紋理的紋元顔色相乘,這使得紋理變暗,可見頂點顔色為 0xffffffff 将不造成任何影響。
注意:必須在1),2)中做一個選擇,且隻能選擇1),2)中的一個。處理的對象是紋理顔色和頂點顔色。
這裡有一個技巧:
如果我們需要在程式中顯示一個氣球,這個氣球的顔色不斷變化,這時候我們并不需要準備多張不同顔色的氣球紋理,而隻需要一張白色的氣球紋理,設定 blend 為 blend_colormul,白色的r,g,b值被表示成 1.0,也就是說,紋理顔色和頂點顔色相乘的結果是頂點的顔色,那麼就可以通過修改頂點顔色,得到任意顔色的氣球了。
3)blend_alphablend
渲染時,将對象的像素顔色(而非頂點的顔色)與目前螢幕的對應像素顔色進行 alpha 混合。alpha 混合使用到 alpha 通道,對于兩個像素顔色進行如下操作,得到一個顔色:
r(c)=alpha*r(b)+(1-alpha)*r(a)
g(c)=alpha*g(b)+(1-alpha)*g(a)
b(c)=alpha*b(b)+(1-alpha)*b(a)
這裡的blend_alphablend使用的是對象像素的顔色的 alpha 通道。可見如果對象像素顔色 alpha 通道為 0,那麼結果就是隻有目前螢幕的像素顔色,也就是常常說的 100% 透明,是以,我們可以了解 alpha 混合就是一個是圖像透明的操作,0 表示完全透明,255 表示完全不透明。
4)blend_alphaadd
渲染時,将對象的像素顔色與目前螢幕的對應像素顔色相加,結果是有了變亮的效果。
注意:這裡的3),4)必選其一,且隻能選其一。處理的對象是對象像素顔色和螢幕像素顔色。
5)blend_zwrite
渲染時,寫像素的 z-order 到 z-buffer
6)blend_nozwrite
渲染時,不寫像素的 z-order 到 z-buffer
這裡一樣是二者選一
設定舉例:
quad.blend=blend_alphaadd | blend_colormul | blend_zwrite; // quad 為 hgequad 變量
4. hge 渲染
1)定義和初始化 hgequad 結構體:
hgequad quad; // 定義四邊形
2)初始化 hgequad 變量:
// 設定混合模式
quad.blend=blend_alphaadd | blend_colormul | blend_zwrite;
// 加載紋理
quad.tex = phge->texture_load("particles.png");
注意,讀取硬碟上資源的時候,可能會失敗,是以通常都需要檢查,例如:
if (!quad.tex)
messagebox(null, "load particles.png", "error", 0);
}
// 初始化頂點
for(int i=0;i<4;i++)
// 設定頂點的 z 坐标
quad.v[i].z=0.5f;
// 設定頂點的顔色,顔色的格式為 0xaarrggbb
quad.v[i].col=0xffffa000;
// 這裡假定載入的紋理大小為 128*128,現在截取由點(96,64),(128,64),(128,96),(96,96)這四個點圍成的圖形。
quad.v[0].tx=96.0/128.0; quad.v[0].ty=64.0/128.0; // 規格化坐标間隔
quad.v[1].tx=128.0/128.0; quad.v[1].ty=64.0/128.0;
quad.v[2].tx=128.0/128.0; quad.v[2].ty=96.0/128.0;
quad.v[3].tx=96.0/128.0; quad.v[3].ty=96.0/128.0;
注意,對于 hgequad 結構體,頂點 quad.v[0] 表示左上那個點,quad.v[1] 表示右上的點,quad.v[2] 表示右下的點,quad.v[3] 表示左下的點。
// 設定 hgequad 在螢幕中的位置
float x=100.0f, y=100.0f;
quad.v[0].x=x-16; quad.v[0].y=y-16;
quad.v[1].x=x+16; quad.v[1].y=y-16;
quad.v[2].x=x+16; quad.v[2].y=y+16;
quad.v[3].x=x-16; quad.v[3].y=y+16;
3)設定渲染函數(render function):
system_setstate(hge_renderfunc,renderfunc);
renderfunc 原型和幀函數一樣:
bool renderfunc();
4)編寫 renderfunc 函數:
bool renderfunc()
phge->gfx_beginscene(); // 在如何渲染之前,必須調用這個函數
phge->gfx_clear(0); // 清屏,使用黑色,即顔色為 0
phge->gfx_renderquad(&quad); // 渲染
phge->gfx_endscene(); // 結束渲染,并且更新視窗
return false; // 必須傳回 false
補充:load 函數是和 free 函數成對出現的,即在硬碟上加載了資源之後,需要 free 它們,例如:
quad.tex = phge->texture_load("particles");
// ...
phge->texture_free(quad.tex);
音效:
使用音效是很簡單的
1. 載入音效:
heffect heffect = phge->effect_load("sound.mp3");
2. 播放:
phge->effect_playex(heffect);
或者 phge->effect_play(heffect);
1)effect_play 函數隻接受一個參數就是音效的句柄 heffect xx;
2)effect_playex 函數較為強大,一共有四個參數:
hchannel effect_playex(
heffect effect, // 音效的句柄
int volume = 100, // 音量,100為最大,範圍是[0, 100]
int pan = 0, // 範圍是[-100, 100],-100表示隻使用左聲道,100表示隻使用右聲道
float pitch = 1.0, // 播放速度,1.0 表示正常速度,值越大播放速度越快,值越小播放越慢。這個值要大于0才有效(不可以等于0)
bool loop = false // 是否循環播放,false表示不循環
);
輸入:
僅僅需要調用函數 phge->input_getkeystate(hgek_xxx); 來判斷輸入,應該在幀函數中調用它,例如:
bool framefunc()
if (phge->input_getkeystate(hgek_lbuttom))
// ...
if (phge->input_getkeystate(hgek_up))