火焰傀偶的挣扎旅程

纯爷们的一生就是不停地燃烧,keep on burning soul!!
随笔 - 6, 文章 - 5, 评论 - 4, 引用 - 0
数据加载中……

2016年8月17日

cocos2d-x 3.10 lua版本中,listview的优化(基于cocostudio3.10)

众所周知,cocos的ListView控件并不好用,他最明显的缺点有两个:
1.加载大量item时会有明显卡顿
2.不支持2维列表

·关于listview中item的加载


listview中的用法,大约看起来是这样的:
1.首先有一个item,并且调用setItemModel
2.调用pushBackDefaultItem插入列表,然后从列表取出item并初始化
(通过阅读代码可知,这个其实就是1中的item调用clone函数,生成插入item,然后addChild,是一样的)

相关代码:

 1 void ListView::addChild(cocos2d::Node *child, int zOrder, int tag)
 2 {
 3     ScrollView::addChild(child, zOrder, tag);
 4 
 5     Widget* widget = dynamic_cast<Widget*>(child);
 6     //这里可以看出,不是Widget 的话,并不会有布局的功能……
 7     if (nullptr != widget)
 8     {
 9         _items.pushBack(widget);
10         onItemListChanged();
11     }
12 }

 1 void ListView::pushBackDefaultItem()
 2 {
 3     if (nullptr == _model)
 4     {
 5         return;
 6     }
 7     Widget* newItem = _model->clone();
 8     remedyLayoutParameter(newItem);//布局排位
 9     addChild(newItem);
10     requestDoLayout();//设置重新渲染的标记
11 }

可以看出,listview的item只支持继承自widget的控件,或者说他的本意如此。

基类不是widget的类型,也没有clone方法,那么setItemModel和pushBackDefaultItem这套体系就形同虚设

然而……cocostudio的新建文件,根本就没有一个父节点是继承自widget的

开发过程中,一般一个item就是一个单独的csd,如果想要使用clone,则要每个item的父节点都必须使用一个的panel类型(即“基础容器”,实际上只是一个ccui.layout类型……)来替代node节点,这个panel的大小影响布局,而如果item中有嵌套csd的场合,情况则会变得更加麻烦,因为node是无法复制的。

综上所述,基本可以得出结论,为了节省工作量,clone这套机制,不如不用。直接create一个csd,再addChild的方案,更加可靠,当然,为了避免上述的布局问题,即使create了csd,还是要先加在一个panel上……

·关于clone方法的效率

那么直接使用create的效率比之clone又如何呢?
就直接用代码看看呗。

cocostudio是可以直接把csb文件导出成lua的,而lua本身又可以再一次压缩luac,这看起来效率还可以

试着测试这样一个简单结构的item,创建100个这东东:



local a = require("testItem").create().root:getChildByName("panel_base");
local osClock1 = os.clock();
for i = 1, 100 do
    a:clone();
end
print("time:" .. os.clock() - osClock1);

local osClock2 = os.clock();
for i = 1, 100 do
    local a = require("testItem").create().root;
end
print("time:" .. os.clock() - osClock2);

输出结果为:

好吧,虽然create慢了点,但还是可以接受的

如果item里面的东西复杂,比如我把btn_test(一个默认的按钮控件),在cocostudio中复制50个,则:


后来又测试了几个以往项目用的比较复杂的item,基本都是直接create更快了,可见这cocos的clone也是很挫的方法。

去瞧瞧c++里的代码,发现他各种属性都要遍历一遍赋值,即是说他没有方法找出重复的值,所以所有的值都要设置一次……上面的使用,想必是因为有很多重复赋值的缘故,才导致慢吧 - -

//clone方法的核心代码,一坨属性的赋值
void Widget::copyProperties(Widget *widget)
{
    setEnabled(widget->isEnabled());
    setVisible(widget->isVisible());
    setBright(widget->isBright());
    setTouchEnabled(widget->isTouchEnabled());
    setLocalZOrder(widget->getLocalZOrder());
    setTag(widget->getTag());
    setName(widget->getName());
    setActionTag(widget->getActionTag());
    _ignoreSize = widget->_ignoreSize;
    this->setContentSize(widget->_contentSize);
    _customSize = widget->_customSize;
    _sizeType = widget->getSizeType();
    _sizePercent = widget->_sizePercent;
    _positionType = widget->_positionType;
    _positionPercent = widget->_positionPercent;
    setPosition(widget->getPosition());
    setAnchorPoint(widget->getAnchorPoint());
    setScaleX(widget->getScaleX());
    setScaleY(widget->getScaleY());
    setRotation(widget->getRotation());
    setRotationSkewX(widget->getRotationSkewX());
    setRotationSkewY(widget->getRotationSkewY());
    setFlippedX(widget->isFlippedX());
    setFlippedY(widget->isFlippedY());
    setColor(widget->getColor());
    setOpacity(widget->getOpacity());
    _touchEventCallback = widget->_touchEventCallback;
    _touchEventListener = widget->_touchEventListener;
    _touchEventSelector = widget->_touchEventSelector;
    _clickEventListener = widget->_clickEventListener;
    _focused = widget->_focused;
    _focusEnabled = widget->_focusEnabled;
    _propagateTouchEvents = widget->_propagateTouchEvents;

    copySpecialProperties(widget);

    Map<int, LayoutParameter*>& layoutParameterDic = widget->_layoutParameterDictionary;
    for (auto iter = layoutParameterDic.begin(); iter != layoutParameterDic.end(); ++iter)
    {
        setLayoutParameter(iter->second->clone());
    }
}

·二维布局以及加载优化

这个单从原理上来说,很简单,大致说说我的思路
假设listview为竖着滑动的,则通过item的宽度,以及listview的宽度,计算出每一行可以摆的下多少个item,并且得到这个行的高度,以此宽高创建一个panel,并把item都算好坐标addChild到这个panel之中,
而这个panel则会被addChild到listview中,这样就实现了二维。

然而,加载的问题还是没有解决,listview就是这样的,你的列表有多少个,就给你加载多少个,一次搞定,cocos又没有做到很好的资源剪裁,于是item一多,就卡到爆炸。

能想到的解决方案:
1.分帧加载
2.随滚动加载
3.创建固定数量的item(即用户可见的最大数量item),监听滑动事件,根据滑动位置来改变各个item位置,并且根据需要重新初始化item中的内容

虽然已经没办法给出具体代码,但是方法1和方法2,甚至方法1和方法2的结合我都有实际在以前项目中使用过。

说实话体验比较一般,特别是item复杂的情况,还是会有很明显的卡顿

……总之多番试验之后,发现方法3才是最好的。

那么怎么用listview去实现呢?listview每添加一个widget类就会自动布局,自己设置滑动范围,对于3的想法来说,实在太不便利,而且我只想在lua中完成这个事情,于是pass。

再看看类似的控件怎么做吧,比如cocos2d-iphone时代就有的控件的tableView……

这个控件虽然使用起来比较麻烦,但是我认为其性能和扩展性都还可以……该说不愧是元祖鬼佬的cocos2d控件吗,反正比国人设计的这个根本不能商用的玩意要好

listview的item在tableview中的名字叫cell,tableview是动态创建item的,他只会创建冒头显示的cell,而且创建的只是一个空的cell,里面的实际内容可以自己定义。

tableview也是默认不支持二维数组的,如要需要用上述类似方法自己封装一下,至于动态加载方法,使用一个缓存item的对象池,配合滑动监听和cell初始化的回调方法来实现应该就可以了。

……好吧,说了这么多,我最终还是没有选择tableview,而是选择了更底层的scrollview,理由比较单纯,因为cocostudio里面的控件有滑动容器(scrollview),没有tableview。这样可以节省一定的ui工作量……

·实现细节

既然决定了,就创建一个叫CCListViewDynamic的class

首先来总结一下,一般初始化一个滑动列表需要的东东:
一个lua table,里面存储了一组数据结构(比如排行版的玩家列表)
一个scrollView控件,一个item的资源文件,用于重复create
一个初始化item的函数指针(比如 通过读取玩家数据,来设置 排名啊 玩家头像 玩家名字之类 )

这些都作为必要的初始化参数传入到CCListViewDynamic中

大致流程:(以下是假设滑动方向为垂直,如果是水平也是类似思路)

1.通过scrollView的宽高获取应初始化item的个数(可见的行数+1 * 每行的个数)
2.创建这些item,并且都addChild到list中,设置坐标为 -width,-height,让其不可见
3.遍历一遍lua table,算出每行由哪些item构成,并且算出每个item的坐标,每一行的显示范围并记录(即scrollview:getInnerContainer():getPositionY()在哪个区间时,这行的item依然显示),这个计算只是预计算数据,是没有做渲染相关工作的
4.根据上面的遍历,也算出了scrollview的滑动范围。
5.根据当前显示范围,通过3中的数据,计算要显示哪些行,如果没有变化,则不继续往下走,否则,和上次显示的范围做比较,计算出今次不显示和新显示的item行数,不显示的item要走一遍2中设置坐标为 -width,-height,让其不可见的流程,新显示的item则要跑一次初始化item的函数指针,并且传入对应的lua table数据
6.监听滑动事件,跑一次5的流程(需要注意的是,这个事件在c++中的枚举值是ScrollView::EventType.CONTAINER_MOVED,不知道什么时候添加的,cocos2d-x3.5的版本是没有这个事件的,如果没有就要自己整一个了……)


上面这里,我试着创建了1000个item,顶点数量和fps还算正常 总体都可以接受……就是初始化速度有点慢,要0.8s,这个还有一些细节有待优化吧。

目前只是粗略的做法,还有一些缺点:
1.目前还没实现插入自定义item,但是如果要做的话,其实思路也是类似的
2.数据和页面耦合太深,如果想做分离式的排序会变得不容易……(比如一个listview里面有两套排序规则的数据)……这个,如果真要有这种变态需求的话,还是有不少地方要改的,但是大体思路依然不变

最后附上代码:/Files/WhiteDummy/mycode/CCListViewDynamic.txt

posted @ 2016-08-17 17:14 WhiteDummy 阅读(6155) | 评论 (1)编辑 收藏

2013年6月25日

关于android的webview屏幕适应

这是我2,3个月前遇到的问题,随手记一下。

主要是关于webview打开网页后的屏幕适应问题。

首先贴一段网上流传的代码:

 1 
 2
 3         //Support different screens     
 4         int screenDensity = mMyActivity.getResources().getDisplayMetrics().densityDpi;  
 5         switch (screenDensity){   
 6         case DisplayMetrics.DENSITY_LOW :  
 7             mWebView.getSettings().setDefaultZoom(ZoomDensity.CLOSE);  
 8             break;  
 9         case DisplayMetrics.DENSITY_MEDIUM:  
10             mWebView.getSettings().setDefaultZoom(ZoomDensity.MEDIUM);  
11             break;  
12         case DisplayMetrics.DENSITY_HIGH:  
13             mWebView.getSettings().setDefaultZoom(ZoomDensity.FAR);  
14             break ;
15         case DisplayMetrics.DENSITY_XHIGH:  
16             mWebView.getSettings().setDefaultZoom(ZoomDensity.FAR); 
17             break ;  
18         case DisplayMetrics.DENSITY_TV:  
19             mWebView.getSettings().setDefaultZoom(ZoomDensity.FAR);  
20             break ; 
21         }

这段代码的不靠谱之处在于:
1.明明case下有五种dpi,android库却只提供close,medium,far三个缩放因子(分别对应LOW,MEDIUM,HIGH,默认是MEDIUM),即便当dpi达到XHIGH(既320DPI)时,也只能设置far,显然是不正常的。

2.实际设备的实际dpi无法获取,因为无法得知设备的物理英寸,上面方法得到dpi值仅是个近似值。

如果单纯用上面的代码做屏幕缩放,对于一些机型肯定是不正常,并且无法估计长宽,比如一张1280宽的图片在实际dpi为X(X > 240 且 x < 320),分辨率为1280的设备上,有可能会被放大1.25倍,或是1.5倍。

如果想要得到正常的倍率,是需要配合网页端的。(这里仅讨论html5的场合,跨平台嘛)

个人认为,由网页方面写死一个宽,再提供一个js的缩放函数(包括图片,字体),根据不同设备的分辨率来调用,是比较理想的。(当然,也可以用穷举法,一个分辨率进一个网页,用不同css和不同大小资源 =_=!)

假设宽定位1280,则html5方面必须有:

1 <meta name="viewport" content="width=1280, initial-scale=1.0,maximum-scale=2.0, minimum-scale=0.5, user-scalable=no,target-densitydpi=device-dpi" />

其中,target-densitydpi
是最重要的,它将配合android端的以下代码使用。


1         //use html5 viewport attribute
2         settings.setLoadWithOverviewMode(true);
3         settings.setUseWideViewPort(true);


表示我们的代码支持html5网页自适应。所谓杀什么畜生用什么刀,网页的事情,dpi适应什么的,就交给html5去做好了 = =,不用我们在更外面一层蛋疼。

这样做之后,1280宽的图片无论在什么设备的分辨率都是正常的尺寸,不会被做倍数不明的拉伸,方便我们控制。


posted @ 2013-06-25 17:30 WhiteDummy 阅读(5433) | 评论 (2)编辑 收藏

2013年3月21日

乱七八糟的android心得


真的很乱七八糟,就当写给自己看吧,囧

1.多线程更新ui的方法:
众所周知,android的系统ui十分蛋疼,只能在主线程更新,也就是说,只能在ui所在的主activity处更新,包括一切的弹出对话框,动态控件的显示等。
 
在其他线程时,只能通过间接更新来实现。我所用的方法就是在主线程实现一个handler成员,通过发送消息给它来更新ui。
 
以下为一个简单例子:
   public class MyActivity extends Activity
    { 
        
public static final int UI_MSG1 = 0;//UI更新消息1 
        public static final int UI_MSG2 = 1;//UI更新消息2 
 
 
        
private Handler mHandler = new Handler()
        { 
            
public void handleMessage (Message msg)
            {
 
                
switch(msg.what)
                { 
                
case UI_MSG1: 
                    
//做一些更新
                    break;
                
case UI_MSG2
                    
//做一些更新
                    break
                } 
            } 
        }; 
 
        Handler GetHandler() {
return mHandler;}
        
//省略其他代码
    } 
 
    
//如果其他地方需要更新ui,则发送更新消息给主activity对象即可
    activity.GetHandler().sendEmptyMessage(MyActivity.UI_MSG1);//此处activity假设为一个MyActivity对象,这里只做示例用
 
 
2.关于findViewById:
如果是代码中自定义的控件(即layout中没有,也无资源id),需要在程序运行中实际显示出来,也就是show的时点后,通过id获取的view才会有效。
 
这里举一个获取AlertDialog的例子,下面的代码通过获取view来实现居中显示:
1 
2 dlg.show();
3 TextView messageText = (TextView)dlg.findViewById(android.R.id.message);//如果这行代码放在show之前,则messageText的值为0
4    messageText.setGravity(android.view.Gravity.CENTER_HORIZONTAL);
 
 
 
3.获取屏幕的宽高
受android的横屏竖屏切换机制所影响,Activity中getWindowManager().getDefaultDisplay()的getWidth() 或者getHeight()方法常常会获得颠倒的宽高,如果你的程序需要使用固定的横屏或固定的竖屏,只需比较所获取宽高的大小再根据情况重新赋值给自己的宽高变量即可,如果宽比高大则表示横屏,反之则竖屏。
 
4.在view中拦截触摸/按键事件
 
其实这个网上的资料很多,就是重写view类的onKeyDown/onKeyUp/onTouchEvent方法来处理自己的事件,其中onTouchEvent中又包括ACTION_MOVE,ACTION_DOWN,ACTION_UP这些事件。
 
如果view有调用requestFocus,则上述方法优先响应于activity的同名方法。反之,可能会无响应。
 
然后说说返回值。
 
一般来说,都是直接返回父类的方法,例如:return super.onTouchEvent(event);
 
上述方法最后都要返回一个布尔值,key事件的返回值只是表示是否只被这个view截取(既返回true时),如果想要继续传递给其他view,则可返回false。
 
touch事件中,返回值则意味着事件是否被处理,如果返回false,则不会继续接下去的事件响应(move和up事件),如果想要保证触摸事件被处理,可以一直返回true。也可以在view初始化时设置setClickab(true)。
 
5.关于waiting for the debugger to attach
 
有时候一些设备通过eclipse的debug模式安装程序后,只能通过eclipse来运行,设备上则不能直接运行,这样很不方便。
 
解决方法:
 
在你项目的manifest.xls中,加入以下权限
 
<uses-permission android:name="android.permission.SET_DEBUG_APP"></uses-permission>

posted @ 2013-03-21 15:35 WhiteDummy 阅读(1189) | 评论 (0)编辑 收藏

2012年12月14日

在hge中实现自己的滚动条

     摘要: 关于hge gui的资料似乎很少,刚好我又想用到hge的滚动条,于是就来就随便扯一下hge的滚动条。让我们先来分析一下它的实现代码吧。Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->/***以下为声明** hgeGUISlider*/BARR...  阅读全文

posted @ 2012-12-14 17:22 WhiteDummy 阅读(2085) | 评论 (1)编辑 收藏

2012年12月13日

在hge中实现对静态图片的动态模糊 (box blur版)


http://blog.csdn.net/jia20003/article/details/7201069

在该前辈的博客处找了段java的均值模糊(box blur)的代码,我把它换成hge的了,效率还可以,不过应该比不上前一篇的方法。但box blur是比较正统的模糊算法,不像前一篇的那般“邪道”,他直接处理像素,其思想方法类似高斯算法,实现上又比高斯算法要简单,虽然效果上比高斯差,但也值得了。

这里我简单讲一下均值模糊的步骤,当然各位也可以看那位前辈的博客:)

1.输入一个半径r,定义模糊的方向,r越大,则越模糊(虽然说是半径r,但是模糊的方向只取一条线,或两条线,例如横,竖,横与竖)。

2.根据1建立一个索引,其实就是空间换时间,提前算好了r范围内所有可能出现的颜色数值之和的均值,这是个固定的值,所以可以一开始就建)。

3.计算第一个r区域的各个像素值之和(r,g,b,a分别算)

4.开始遍历想要输出的纹理像素(注意原纹理矩阵依然保留),每行第一个像素,直接给他赋予2中的均值,往后每遍历一个像素,3计算的像素值之和都加上x+r +1和 x - r 之间的差(或者是y+r+1和y-r-1的差),然后再次赋予新的均值。

代码(使用横方向模糊,每摁一下L键开始模糊,半径为10):


/*
**
** motion blur demo
** based off of tutorial4..
*/
 
 
#include 
"..\..\include\hge.h"
#include 
"..\..\include\hgesprite.h"
 
 
HGE 
*hge=0;
 
 
hgeSprite
* spt1;

float x=0.0f, y=0.0f;


HTEXTURE boxblur( HTEXTURE 
inint radius ) ;

bool FrameFunc()
{
    
if(hge->Input_KeyDown(HGEK_L))
    {
        HTEXTURE dumptex 
= spt1->GetTexture();
        HTEXTURE tex2 
= boxblur(dumptex,10);
        spt1
->SetTexture(tex2);
        hge
->Texture_Free(dumptex);
    }

    hge
->Gfx_BeginScene();
    hge
->Gfx_Clear(0);
 
    spt1
->Render(x, y);

    hge
->Gfx_EndScene();

    
return false;
}
 

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
    hge 
= hgeCreate(HGE_VERSION);

    hge
->System_SetState(HGE_FRAMEFUNC, FrameFunc);
    hge
->System_SetState(HGE_TITLE, "HGE RealTime Blur Demo");
    hge
->System_SetState(HGE_FPS, 100);
    hge
->System_SetState(HGE_WINDOWED, true);
    hge
->System_SetState(HGE_SCREENWIDTH, 1024);
    hge
->System_SetState(HGE_SCREENHEIGHT, 768);
    hge
->System_SetState(HGE_SCREENBPP, 32);
 
    
if(hge->System_Initiate()) {
        
        HTEXTURE tex
=hge->Texture_Load("alley_normal.jpg");
        
if(!tex)
        {
            MessageBox(NULL, 
"Can't load the picture file""Error", MB_OK | MB_ICONERROR | MB_SYSTEMMODAL);
            hge
->System_Shutdown();
            hge
->Release();
            
return 0;
        }
 
        spt1
=new hgeSprite(tex, 001024768);//这是最后会显示的精灵
               
        hge
->System_Start();

        hge
->Texture_Free(spt1->GetTexture());

        delete spt1;
    }
 
    
// Clean up and shutdown
    hge->System_Shutdown();
    hge
->Release();
    
return 0;
}

HTEXTURE boxblur( HTEXTURE 
inint radius ) 
{  
    
int width, height;
    width 
= hge->Texture_GetWidth(in);
    height 
= hge->Texture_GetHeight(in);
    HTEXTURE 
out = hge->Texture_Create(width, height);

    
int widthMinus1 = width-1;  
    
int tableSize = 2*radius+1;  
    unsigned 
int* divide = new unsigned int[256*tableSize];  

    
// the value scope will be 0 to 255, and number of 0 is table size  
    
// will get means from index not calculate result again since   
    
// color value must be  between 0 and 255.  
    for ( int i = 0; i < 256*tableSize; i++ )  
        divide[i] 
= i/tableSize;   

    
int inIndex = 0;  

    unsigned 
int* in_  = (unsigned int*)hge->Texture_Lock(in);
    unsigned 
int* out_ = (unsigned int*)hge->Texture_Lock(outfalse);

    
//   
    for ( int y = 0; y < height; y++ ) {  
        
int outIndex = y;  
        unsigned 
int ta = 0, tr = 0, tg = 0, tb = 0// ARGB -> prepare for the alpha, red, green, blue color value.  

        
for ( int i = -radius; i <= radius; i++ ) 
        {  
            
int clamp = (i < 0? 0 : (i > (width-1)) ? (width-1) : i;
            unsigned 
int rgb = in_[inIndex + clamp]; // read input pixel data here. table size data.  
            ta += (rgb >> 24& 0xff;  
            tr 
+= (rgb >> 16& 0xff;  
            tg 
+= (rgb >> 8& 0xff;  
            tb 
+= rgb & 0xff;  
        }  

        
for ( int x = 0; x < width; x++ ) 
        { 
// get output pixel data.  
            out_[ outIndex*width + x ] = (divide[ta] << 24| (divide[tr] << 16| (divide[tg] << 8| divide[tb]; // calculate the output data.  

            
int i1 = x+radius+1;  
            
if ( i1 > widthMinus1 )  
                i1 
= widthMinus1;  
            
int i2 = x-radius;  
            
if ( i2 < 0 )  
                i2 
= 0;  
            
int rgb1 = in_[inIndex+i1];  
            
int rgb2 = in_[inIndex+i2];  

            ta 
+= ((rgb1 >> 24& 0xff)-((rgb2 >> 24& 0xff);  
            tr 
+= ((rgb1 & 0xff0000)-(rgb2 & 0xff0000)) >> 16;  
            tg 
+= ((rgb1 & 0xff00)-(rgb2 & 0xff00)) >> 8;  
            tb 
+= (rgb1 & 0xff)-(rgb2 & 0xff);
        }  
        inIndex 
+= width; // next (i+ column number * n, n=1.n-1)  
    } 

    hge
->Texture_Unlock(in);
    hge
->Texture_Unlock(out);
    delete [] divide;
    
return out;
}



posted @ 2012-12-13 16:24 WhiteDummy 阅读(1989) | 评论 (0)编辑 收藏

在hge中实现对静态图片的动态模糊


可以用来模拟那种刚睡醒然后睁开眼睛的场景效果。

实现方法很简单,就是几张坐标有点不一致的alpha图片慢慢靠在一起,并且同时让alpha恢复正常。虽说是静态图片的模糊,但这方法其实和
和运动模糊(motion blur)极其类似。

这里我使用BLEND_COLORMUL | BLEND_ALPHAADD | BLEND_NOZWRITE的混合模式,该模式下的纹理叠加在一起会显得亮,在这里,顺便复习一下BLEND几个参数的含义,以下内容转自互联网:

1)BLEND_COLORADD

表示顶点的颜色与纹理的纹元(texel)颜色相加,这使得纹理变亮,可见顶点颜色为 0x00000000,将不造成任何影响。

2)BLEND_COLORMUL

表示顶点的颜色与纹理的纹元颜色相乘,这使得纹理变暗,可见顶点颜色为 0xFFFFFFFF 将不造成任何影响。


3)BLEND_ALPHABLEND

渲染时,将对象的像素颜色(而非顶点的颜色)与当前屏幕的对应像素颜色进行 alpha 混合。

4)BLEND_ALPHAADD

渲染时,将对象的像素颜色与当前屏幕的对应像素颜色相加,结果是有了变亮的效果。


5)BLEND_ZWRITE
写像素的 Z-order 到 Z-buffer

6)BLEND_NOZWRITE

渲染时,不写像素的 Z-order 到 Z-buffer


 

以上1和2,3和4,5和6都是互斥的,并且必须选择一个的,默认情况下应该是2,3,6


话不多了,上代码吧,格式啊,取名什么的都比较挫,嘛,反正很短,当demo随便看看就好。如果要自己编译运行需要准备一张图片和设置好自己的图片路径哦(修改在Texture_Load处的参数)


/*
** motion blur demo
** based off of hge tutorial..
*/
 

 
#include 
"..\..\include\hge.h"
#include 
"..\..\include\hgesprite.h"
 
HGE 
*hge=0;
 
 
hgeSprite
*            spt1;
hgeSprite
*            spt2;

HTEXTURE            tex;

float x=0.0f, y=0.0f;
float x2=0.0f, y2=0.0f;

float totaltime = 0;
float endtime = 0.5f;
int offset = 10;
 

bool FrameFunc()
{
    
float dt = hge->Timer_GetDelta();
    totaltime 
+= dt;
 
    
if(totaltime > 0.1f && offset != 0)
    {
        offset 
-=2;
        totaltime 
= 0;
    }

    
    
if(endtime > 0)
    {
        spt2
->SetColor( ARGB( endtime/0.5f*((float)128), 255,255,255 ) );
        endtime 
-= dt;
    }
    
else
        spt2
->SetColor(ARGB(0,255,255,255));//alpha为0时,图片不显示,就看不到发光效果了,实际程序运用时,应该释放掉该精灵更好。

    hge
->Gfx_BeginScene();
    hge
->Gfx_Clear(0);
 
    spt1
->Render(x, y);
    spt2
->Render(x2-offset, y2);
    spt2
->Render(x2+offset, y2);
    
    
if(offset > 2)
    {
    
   spt2->Render(x2-(offset-2), y2);
    
   spt2->Render(x2+(offset-2), y2);
    }
    
    hge
->Gfx_EndScene();
 
    
return false;
}
 
 
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
    hge 
= hgeCreate(HGE_VERSION);

    hge
->System_SetState(HGE_FRAMEFUNC, FrameFunc);
    hge
->System_SetState(HGE_TITLE, "HGE RealTime Blur Demo");
    hge
->System_SetState(HGE_FPS, 100);
    hge
->System_SetState(HGE_WINDOWED, true);
    hge
->System_SetState(HGE_SCREENWIDTH, 1024);
    hge
->System_SetState(HGE_SCREENHEIGHT, 768);
    hge
->System_SetState(HGE_SCREENBPP, 32);
 
    
if(hge->System_Initiate()) {
        
        tex
=hge->Texture_Load("alley_normal.jpg");
        
if(!tex)
        {

            MessageBox(NULL, "Can't load the picture file""Error", MB_OK | MB_ICONERROR | MB_SYSTEMMODAL);
            hge
->System_Shutdown();
            hge
->Release();
            
return 0;
        }
 
        spt1
=new hgeSprite(tex, 001024768);//这是最后会显示的精灵
     
        spt2
=new hgeSprite(tex, 001024768);
        spt2
->SetBlendMode(BLEND_COLORMUL | BLEND_ALPHAADD | BLEND_NOZWRITE);
        spt2
->SetColor(ARGB(128,255,255,255));
        
        hge
->System_Start();
 
        
// Delete created objects and free loaded resources

        delete spt1;
        delete spt2;
        
        hge
->Texture_Free(tex);
    }
 
    
// Clean up and shutdown
    hge->System_Shutdown();
    hge
->Release();
    
return 0;
}

我的效果图:

posted @ 2012-12-13 11:36 WhiteDummy 阅读(1930) | 评论 (0)编辑 收藏