踏入神的领域

kun1234567的专栏

付坤ID:kun1234567
85920次访问,排名1102(-4)好友0人,关注者5
了解DX.熟悉ALLEGRO.熟悉Lua.熟悉CEGUI.了解PhysX
kun1234567的文章
原创 39 篇
翻译 2 篇
转载 3 篇
评论 36 篇
最近评论
frank28_nfls:实在是晕,csdn的blog系统。。。
frank28_nfls:呵呵,我的msn:frank28_nfls AT hotmail.com

研究navi也是大半年前的事儿了,了解其实也有限,现在已经不做ogre的项目了,只是业余时间关心。。。

另:navi的原作者好像基本已经放弃navi了,基于gecko引擎的做法应该是消耗太大(可以看这个帖子:http://www.ogre3d.org/phpBB2/viewt……
frank28_nfls:呵呵,我的msn:frank28_nfls AT hotmail.com

研究navi也是大半年前的事儿了,了解其实也有限,现在已经不做ogre的项目了,只是业余时间关心。。。

另:navi的原作者好像基本已经放弃navi了,基于gecko引擎的做法应该是消耗太大(可以看这个帖子:http://www.ogre3d.org/phpBB2/viewt……
frank28_nfls:呵呵,我的msn:frank28_nfls AT hotmail.com

研究navi也是大半年前的事儿了,了解其实也有限,现在已经不做ogre的项目了,只是业余时间关心。。。

另:navi的原作者好像基本已经放弃navi了,基于gecko引擎的做法应该是消耗太大(可以看这个帖子:http://www.ogre3d.org/phpBB2/viewt……
frank28_nfls:Gecko还有个问题是不好调试;
Debug版的Gecko运行速度奇慢;还有Debug版的Gecko对于html完全不容错,一遇html语法错误就段错误,这对于实际开发影响甚大。。。
文章分类
收藏
    相册
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 Lua学习笔记四--返回值和UserData收藏

    新一篇: Lua学习笔记五--真正的入门:编写Lua扩展库 | 旧一篇: Lua学习笔记三--表的应用

     

    Lua学习笔记四

    通过上一节的知识,我们学会了如何利用表来作为参数,这样我们能实现的功能更多了。但是有一点是没有涉及到的,那就是返回值,而返回值的讨论不能不提userdata类型。
    本节的目的:讨论如何处理Lua返回值和Userdata类型的应用。 

     


     

    本章涉及一些Allegro的知识,但是这不是重点。所以当你看到不熟悉的代码段时,不必太在意,把注意力放在编写Lua函数的套路上。


    现在我可以在脚本中写下“CreateWindow{x=0,y=0,w=1024,h=768} ”这样的语句来控制程序在内存中创建一个窗口了,很美妙是不是?

    但是我现在要实现“AddButton{x=100,y=100,w=75,h=25}”这样添加控件,应该如何做呢?
    首先我得让AddButton接受一个类似窗口句柄的参数,那样AddButton才知道往哪个窗口里添加一个新按钮。
    因此CreateWindow就得返回这个窗口句柄。

    OK。新的LUA语句象这个样子:
    NewWindow = CreateWindow{ x = 0,y = 0, w = 1024, h = 768} ;
    AddButton{hWindow = NewWindow , x =100, y = 100, w = 75, h = 25};

    看起来真好,现在让我们来实现它。
     


     RRRRRRRTFS

    -------以下是Lua脚本--------
    --test.lua
    NewWindow = CreateWindow{ x = 0, y = 0, w = 1024, h = 768} ;
    AddButton{hWindow = NewWindow , x =100, y = 100, w = 75, h = 25};

    ---------绝对不会通过LuaEdit语法测试--------------

    //------------以下是test.cpp文件----------------
    // 由于总是在上一次的基础上进行的添加,因此已经实现过了的函数体我就省略了。
    // 这也是与“给出完整可编译代码段”的原则的妥协---不然代码就太多了。
    // 另外这次的代码是没办法直接通过编译的,因为使用到了Allegro库和一套自己编写的控件。
    // 但是这些代码跟包含Allegro相关的代码没有区别--注意如何使用Lua的套路就好。

    //================================================================================================================
    //           Lua Test Object
    //           C++ Source lua_test.cpp
    //================================================================================================================
    //================================================================================================================
    //           Include Files
    //================================================================================================================
    extern "C"
    {
     #include "D:\\My Documents\\Visual Studio 2005\\Projects\\lua\\lua\\lua.h"
     #include "D:\\My Documents\\Visual Studio 2005\\Projects\\lua\\lua\\lualib.h"
     #include "D:\\My Documents\\Visual Studio 2005\\Projects\\lua\\lua\\lauxlib.h"
    }
    // 这是一套控件,利用了Allegro库,不必在意。
    #include "d:\My Documents\Visual Studio 2005\Projects\Demo\Demo\Components.h"

    #include <windows.h>
    #include <stdio.h>
    #include <string>
    using namespace std;
    //================================================================================================================
    //           Libraries
    //================================================================================================================
    #pragma comment( lib ,"D:\\My Documents\\Visual Studio 2005\\Projects\\lua\\release\\lua.lib")
    //===================================================================================================
    //            macro
    //===================================================================================================
    // 计算Dialog数组长度
    #define DLG_COUNT(x)   ( sizeof(x)/sizeof(DIALOG))
    // 计算Dialog数组的大小
    #define DLG_SIZEOF(x)   ( sizeof( *x) + (x##->count -1) * sizeof( x##->lpdialog[0]))
    // 在堆上初始化变量
    #define NEW(x)    ( (x##_PTR)malloc( sizeof(x)))
    //================================================================================================================
    //           Global Variables
    //================================================================================================================
    // 定义的结构体。因为在Allegro中,窗体是一个Dialog类型的数组。不必在意。

    typedef struct DIALOG_ARRAY_TAG
    {
     int    count;
     DIALOG  lpdialog[1];
    }DIALOG_ARRAY, *DIALOG_ARRAY_PTR;

    //================================================================================================================
    //           Global Variables
    //================================================================================================================
    lua_State *L;
    //================================================================================================================
    //           Lua Functions
    //================================================================================================================
    double f( double x, double y )
    {

    }
    //================================================================================================================
    //           C/C++ Helper Functions
    //================================================================================================================
    // 获取t[k](表t中字段k)的值
    void _lua_getfield( lua_State* L, char* key, void* ret, int type_flags)
    {
    }

    //================================================================================================================
    //           C/C++ Functions
    //================================================================================================================
    int LuaC_MessageBox( lua_State *L)
    {
    }

    int LuaC_MessageBoxEx( lua_State *L)
    {
    }

    // 创建一个新DIALOG数组
    // 返回该数组指针
    int CreateWindow( lua_State* L)
    {
     // Lua Var
     int x,y,w,h;
     void* lp;

     // NewWindow = CreateWindow{ x = __in, y = __in, w = __in, h = __in}
     // 从堆栈上获取参数
     _lua_getfield( L, "x", &x, GTC_INT);
     _lua_getfield( L, "y", &y, GTC_INT);
     _lua_getfield( L, "w", &w, GTC_INT);
     _lua_getfield( L, "h", &h, GTC_INT);

     // allegro var 不必在意
     DIALOG_ARRAY_PTR new_dialog = NEW(DIALOG_ARRAY);
     new_dialog->count = 0;

     DIALOG lpbasic_dialog[] = //一个基本的Allegro窗体数组模板,不必在意
     {
      /* (dialog proc)(x)(y)(w)(h)(fg)(bg)(key)(flags)(d1)(d2)(dp)(dp2)(dp3) */
      { d_clear_proc,  0, 0, 0, 0, 0,  0,   0,   0,    0,  0,  NULL,NULL,NULL},
      { d_yield_proc,  0, 0, 0, 0, 0,  0,   0,   0,    0,  0,  NULL,NULL,NULL},
      { NULL}
     };

    // 将窗体模板添加到新的数据结构DIALOG_ARRAY,不必在意
     new_dialog = add_object( DLG_COUNT(lpbasic_dialog), new_dialog, lpbasic_dialog);

    //使用获得的参数
     new_dialog->lpdialog[0].x = x;
     new_dialog->lpdialog[0].y = y;
     new_dialog->lpdialog[0].w = w;
     new_dialog->lpdialog[0].h = h;

     // 返回值压栈
     lp = lua_newuserdata( L, DLG_SIZEOF(new_dialog));
     // 拷贝数组内容
     memcpy( lp, new_dialog, DLG_SIZEOF(new_dialog));

     // 返回压栈参数的个数
     return 1;
    }

    //================================================================================================================
    //           Main Functions
    //================================================================================================================
    int main( void)
    {
     int error;

     L = lua_open();
     luaopen_base(L);
     luaL_openlibs(L);

      // 注册C/C++函数
      lua_register( L, "LuaC_MessageBox", LuaC_MessageBox);
      lua_register( L, "LuaC_MessageBoxEx", LuaC_MessageBoxEx);
      lua_register( L, "CreateWindow", CreateWindow);


    // load the script 
    // 加入了错误处理
     if ( (error = luaL_dofile(L, "test.lua")) != 0)
     {
      MessageBox( NULL, "出错啦:执行脚本出错!", "Lua Test", MB_OK );
      return 0;
     }
     
     getchar();
     lua_close( L);
     return 1;
    }

     

     


    恩,这次笔记需要注意的地方是不是醒目多了?

    现在让我们来逐个分析:

    返回值为UserData类型。
    OK,我知道我违反了介绍的原则---先易后难,但是普通的返回值确实是很简单的事情,所以在我们讨论清楚userdata类型之后,再一句话带过普通类型的返回值。

    int CreateWindow( lua_State* L)
    该函数中第1个有意思的地方在于结尾对返回值的压栈:
     // 返回值压栈
     lp = lua_newuserdata( L, DLG_SIZEOF(new_dialog));
    Lua中有很多把各类返回值压栈的函数,只要你在Lua参考手册中搜索“lua_push”,你可以得到如下结果:
    lua_pushboolean
    lua_pushinteger
    lua_pushfstring
    lua_pushlstring
    lua_pushnil
    lua_pushnumber
    .....
    有很多这样的函数,解释可以参看参考手册。

    我想谈的是他们的共性:这一系列的类型压栈都是已经分配了内存空间的类型。
    所以你找不到函数 lua_pushuserdata,原因是Userdata实际是指一块内存空间,就象malloc出来的一样。不同的是,这段空间是在Lua用于交互的栈(luaState* L)上进行分配的。所以你要将自己的数据类型压栈的话,就需要按照以下步骤来:
    1、调用lua_newuserdata()函数申请指定大小的 userdata类型,该函数返回指向新内存的指针。如:
    lp = lua_newuserdata( L, DLG_SIZEOF(new_dialog));
    2、改变lp指向的这段内存的内容--随便写些000111进去,或者改成你要的数据。但是有一点需要注意的是,不要尝试改变该块内存的大小,否则会对Lua的栈造成破坏。何况Lua也不会让你改变这块内存~

    第2个有意思的地方是如何利用刚刚申请的这段空间。因为在Lua的栈上,所以操作起来不如在堆上的数据那么自由,把堆上的数据往这个栈拷贝的时候会出现失败的情况---至少我用memmove函数进行操作时失败了。

     // 拷贝数组内容
     memcpy( lp, new_dialog, DLG_SIZEOF(new_dialog));

    现在再来谈谈普通的返回值压栈:调用对应类型的函数!

     最后,告诉Lua,你要返回的参数个数,在这里,我要返回刚才创建的窗体树组,所以是1个。

     // 返回压栈参数的个数
     return 1;

    发表于 @ 2008年01月05日 16:36:00|评论(loading...)|编辑

    新一篇: Lua学习笔记五--真正的入门:编写Lua扩展库 | 旧一篇: Lua学习笔记三--表的应用

    评论:没有评论。

    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
    Csdn Blog version 3.1a
    Copyright © kun(小龙)