Easyx图形库应用(和lua结合使用)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

lua本身是一门胶水语言。很多项目,在底层逻辑部分,都是用c/c++开发。但是业务代码部分,还是采用lua这种脚本语言来完成。这里面很大一部分原因,就是底层框架偏向于基础和原理、性能,而上层脚本偏向于应用。底层的部分改动不多,甚至来说没什么改动。但是业务不一样,可能这个项目是这么来写,那个项目是那么来处理。所以,就需要看怎么把底层结构和上层区分开来。不过今天我们说的lua和easyx,它是比较简单的。主要就是api级别的适配。

1、nuget安装

本身lua是可以自己安装第三方代码,编译生成静态库、动态库的。不过vs2017本身有nuget工具,可以通过它直接下载lua库。里面包含了头文件、静态库、动态库。

2、设置include目录

下载后的lua不能直接使用,需要手动设置下include目录,这一点稍微注意下。

3、api适配

这里的适配,主要是分成四种。一种是没有参数的api适配,这种是最简单的,

复制代码
static void cleardevice_function(lua_State* L)
{
	::cleardevice();
}

第二种是有输入参数,但是没有返回值的适配,

复制代码
static void initgraph_function(lua_State *L)
{
	int width = (int)luaL_checkinteger(L, 1);
	int height = (int)luaL_checkinteger(L, 2);

	::initgraph(width, height);
}

第三种,就是有返回值的适配,输入参数可以有,也可以没有。返回值1代表一个返回结果的意思。

复制代码
static int kbhit_function(lua_State* L)
{
	lua_pushinteger(L, _kbhit());

	return 1; // 1 means 1 parameter
}

最后一种,就是需要创建对象的适配,这种适配一般需要返回一个指针,在实际场景中用的非常多。

复制代码
static int getimage_function(lua_State* L)
{
	int x = (int)luaL_checkinteger(L, 1);
	int y = (int)luaL_checkinteger(L, 2);
	int width = (int)luaL_checkinteger(L, 3);
	int height = (int)luaL_checkinteger(L, 4);

	IMAGE* p_image = new IMAGE;
	::getimage(p_image, x, y, width, height);
	lua_pushinteger(L, (lua_Integer)(p_image));

	return 1; // 1 means 1 parameter
}

4、适配之后的lua开发

有了api的适配,那么就可以用lua进行程序开发。一般就是exe+lua开发即可。exe是可执行文件,开发之后就不用管了。而lua是程序文件,可以拿过来开发各种业务,比如下面这个简单的lua流程,

复制代码
-- file:   demo.lua
-- author: feixiaoxing
-- email:  feixiaoxing@163.com
-- date:   2025-10-18

initgraph(640, 480)
setfillcolor(0x0000AA)
solidcircle(320,240, 100)
image = getimage(220, 140, 200, 200)
saveimage("./demo.bmp", image)
rectangle(100, 100, 200, 50)
line(100, 400, 500, 400)

direction = 0
offset = 0
value = 97 -- 'a'

BeginBatchDraw()
while true do
	if 1 == _kbhit() then
		value = _getch() -- update output content
	end

	cleardevice()	
	if offset > 100 then -- no more than 50
		direction = 1
	end
	
	if offset < 0 then -- no less than 0
		direction  = 0
	end
	
	if direction == 0 then -- update offset here
		offset = offset + 1	
	else
		offset = offset - 1
	end
	
	putimage(220+offset, 140, image)
	rectangle(100+offset, 100, 200+offset, 50)
	line(100+offset, 400, 500+offset, 400)
	outtextxy(500+offset, 50, value-0x20)
	outtextxy(500+offset, 75, value-0x20+1)
	outtextxy(500+offset, 100, value-0x20+2)
	
	FlushBatchDraw()
	sleep(100)
end

EndBatchDraw()
closegraph()

实际运行的效果就是这样的,

5、lua开发的一个好处

对于一个公司或者工作室来说,不可能所有人都精通编程。这种情况下,势必会有一部分人需要去做业务开发。如果是业务开发,其实可以用c#、java、lua来做是比较合适的。这里面,lua又是最合适的。不仅适配api非常合适,可以做很多定制开发,而且对使用者的学历没有要求,基本上所见即所得。哪怕是没有基础的同学,也可以短时间内快速上手,这是最大的优势。

lua修改后,快速看到效果,不需要任何编译动作,这就是lua的魅力所在。

6、多线程的处理

lua本身不支持多线程,不过我们可以通过多thread、多vm虚拟机的方法来解决。

7、完整的适配代码

本身api的适配还是不太难的。主要的处理方法,就是创建虚拟机、加载库、加载我们适配的函数,最后运行lua文件即可。这里给出完整的api适配文件,希望对大家有所帮助。一般来说,上层的api并不是很多,一般适配几十个api,就可以让开发业务的同学开始干活了。

复制代码
// add by feixiaoxing, 2025.10.18

#include <stdio.h>
#include <conio.h>
#include <graphics.h>

#include "lua.hpp"

static lua_State* L1 = NULL;

// register init function

static void initgraph_function(lua_State *L)
{
	int width = (int)luaL_checkinteger(L, 1);
	int height = (int)luaL_checkinteger(L, 2);

	::initgraph(width, height);
}

static int getch_function(lua_State* L)
{
	lua_pushinteger(L, _getch());

	return 1; // 1 means 1 parameter
}

static int kbhit_function(lua_State* L)
{
	lua_pushinteger(L, _kbhit());

	return 1; // 1 means 1 parameter
}

static void setfillcolor_function(lua_State* L)
{
	int value = (int)luaL_checkinteger(L, 1);

	::setfillcolor(value);
}

static void putpixel_function(lua_State* L)
{
	int x = (int)luaL_checkinteger(L, 1);
	int y = (int)luaL_checkinteger(L, 2);
	int value = (int)luaL_checkinteger(L, 3);

	::putpixel(x, y, value);
}

static void closegraph_function(lua_State* L)
{
	::closegraph();
}

static void cleardevice_function(lua_State* L)
{
	::cleardevice();
}

static void circle_function(lua_State* L)
{
	int x = (int)luaL_checkinteger(L, 1);
	int y = (int)luaL_checkinteger(L, 2);
	int radius = (int)luaL_checkinteger(L, 3);

	::circle(x, y, radius);
}

static void fillcircle_function(lua_State* L)
{
	int x = (int)luaL_checkinteger(L, 1);
	int y = (int)luaL_checkinteger(L, 2);
	int radius = (int)luaL_checkinteger(L, 3);

	::fillcircle(x, y, radius);
}

static void solidcircle_function(lua_State* L)
{
	int x = (int)luaL_checkinteger(L, 1);
	int y = (int)luaL_checkinteger(L, 2);
	int radius = (int)luaL_checkinteger(L, 3);

	::solidcircle(x, y, radius);
}

static void line_function(lua_State* L)
{
	int x1 = (int)luaL_checkinteger(L, 1);
	int y1 = (int)luaL_checkinteger(L, 2);
	int x2 = (int)luaL_checkinteger(L, 3);
	int y2 = (int)luaL_checkinteger(L, 4);

	::line(x1, y1, x2, y2);
}

static void rectangle_function(lua_State* L)
{
	int x1 = (int)luaL_checkinteger(L, 1);
	int y1 = (int)luaL_checkinteger(L, 2);
	int x2 = (int)luaL_checkinteger(L, 3);
	int y2 = (int)luaL_checkinteger(L, 4);

	::rectangle(x1, y1, x2, y2);
}

static void fillrectangle_function(lua_State* L)
{
	int x1 = (int)luaL_checkinteger(L, 1);
	int y1 = (int)luaL_checkinteger(L, 2);
	int x2 = (int)luaL_checkinteger(L, 3);
	int y2 = (int)luaL_checkinteger(L, 4);

	::fillrectangle(x1, y1, x2, y2);
}

static void solidrectangle_function(lua_State* L)
{
	int x1 = (int)luaL_checkinteger(L, 1);
	int y1 = (int)luaL_checkinteger(L, 2);
	int x2 = (int)luaL_checkinteger(L, 3);
	int y2 = (int)luaL_checkinteger(L, 4);

	::solidrectangle(x1, y1, x2, y2);
}

static void sleep_function(lua_State* L)
{
	int value = (int)luaL_checkinteger(L, 1);
	::Sleep(value);
}

static void outextxy_function(lua_State* L)
{
	int x = (int)luaL_checkinteger(L, 1);
	int y = (int)luaL_checkinteger(L, 2);
	int value = (int)luaL_checkinteger(L, 3);

	::outtextxy(x, y, value);
}

static int inputbox_function(lua_State* L)
{
	char s[10] = {0};
	int speed = 0;

	InputBox((LPTSTR)s, 10, "Input speed:");
	speed = atoi(s);

	lua_pushinteger(L, (lua_Integer)(speed));
	return 1;
}

static int getimage_function(lua_State* L)
{
	int x = (int)luaL_checkinteger(L, 1);
	int y = (int)luaL_checkinteger(L, 2);
	int width = (int)luaL_checkinteger(L, 3);
	int height = (int)luaL_checkinteger(L, 4);

	IMAGE* p_image = new IMAGE;
	::getimage(p_image, x, y, width, height);
	lua_pushinteger(L, (lua_Integer)(p_image));

	return 1; // 1 means 1 parameter
}

static void putimage_function(lua_State* L)
{
	int x = (int)luaL_checkinteger(L, 1);
	int y = (int)luaL_checkinteger(L, 2);
	IMAGE* p_image = (IMAGE*)luaL_checkinteger(L, 3);

	::putimage(x, y, p_image);
}

static void saveimage_function(lua_State* L)
{
	const char *path = lua_tostring(L, 1);
	IMAGE* image = (IMAGE*)luaL_checkinteger(L, 2);

	::saveimage((LPCTSTR)path, image); // need using multi-bytes encode format
}

static void rotateimage_function(lua_State* L)
{
	IMAGE* dst_image = (IMAGE*)luaL_checkinteger(L, 1);
	IMAGE* src_image = (IMAGE*)luaL_checkinteger(L, 2);
	int angle = (int)luaL_checkinteger(L, 3);

	::rotateimage(dst_image, src_image, angle/360.0 * 6.28);
}

static void BeginBatchDraw_function(lua_State* L)
{
	::BeginBatchDraw();
}

static void FlushBatchDraw_function(lua_State* L)
{
	::FlushBatchDraw();
}

static void EndBatchDraw_function(lua_State* L)
{
	::EndBatchDraw();
}

// c read data from lua

static int read_lua_value(lua_State* L)
{
	if(NULL == L)
	{
		return -1;
	}
	
	lua_getglobal(L, "max_players"); // this step is very important, 2025.10.19
    return (int)luaL_checkinteger(L, -1);
}

// launch script and execute script here

static void* launch_script(void* p_file)
{
	int status = 0;

	// create a virtual machine

	L1 = luaL_newstate();
	if (NULL == L1)
	{
		goto exit;
	}

	// register open function here

	luaL_openlibs(L1);

	// basic operation

	lua_register(L1,  "initgraph",       (lua_CFunction)&initgraph_function);
	lua_register(L1,  "_getch",          (lua_CFunction)&getch_function);
	lua_register(L1,  "_kbhit",          (lua_CFunction)&kbhit_function);
	lua_register(L1,  "setfillcolor",    (lua_CFunction)&setfillcolor_function);
	lua_register(L1,  "putpixel",        (lua_CFunction)&putpixel_function);
	lua_register(L1,  "circle",          (lua_CFunction)&circle_function);
	lua_register(L1,  "fillcircle",      (lua_CFunction)&fillcircle_function);
	lua_register(L1,  "solidcircle",     (lua_CFunction)&solidcircle_function);
	lua_register(L1,  "line",            (lua_CFunction)&line_function);
	lua_register(L1,  "rectangle",       (lua_CFunction)&rectangle_function);
	lua_register(L1,  "fillrectangle",   (lua_CFunction)&fillrectangle_function);
	lua_register(L1,  "solidrectangle",  (lua_CFunction)&solidrectangle_function);
	lua_register(L1,  "closegraph",      (lua_CFunction)&closegraph_function);
	lua_register(L1,  "cleardevice",     (lua_CFunction)&cleardevice_function);
	lua_register(L1,  "sleep",           (lua_CFunction)&sleep_function);
	lua_register(L1,  "outtextxy",       (lua_CFunction)&outextxy_function);
	lua_register(L1,  "inputbox",        (lua_CFunction)&inputbox_function);

	// about image operation

	lua_register(L1,  "getimage",        (lua_CFunction)&getimage_function);
	lua_register(L1,  "putimage",        (lua_CFunction)&putimage_function);
	lua_register(L1,  "saveimage",       (lua_CFunction)&saveimage_function); //need multi-bytes setting in vs2017
	lua_register(L1,  "rotateimage",     (lua_CFunction)&rotateimage_function);

	// about buffer acceleration

	lua_register(L1,  "BeginBatchDraw",  (lua_CFunction)&BeginBatchDraw_function);
	lua_register(L1,  "FlushBatchDraw",  (lua_CFunction)&FlushBatchDraw_function);
	lua_register(L1,  "EndBatchDraw",    (lua_CFunction)&EndBatchDraw_function);

	// c call lua, if lua needs invoke c, just using lua_pcall & lua_getglobal

	status = luaL_dofile(L1, (const char*)p_file); // open and execute file
	if (status != LUA_OK)
	{
		printf("failed to open lua file\n");
		lua_close(L1);

		goto exit;
	}

	// close virtual machine

	lua_close(L1);

exit:
	return NULL;
}

int main(int argc, char* argv[])
{
	launch_script((void*)"./demo.lua");
	return 0;
}
相关推荐
AsiaLYF3 小时前
kotlin中MutableStateFlow和MutableSharedFlow的区别是什么?
android·开发语言·kotlin
Asuncion0074 小时前
Docker核心揭秘:轻量级虚拟化的革命
服务器·开发语言·docker·云原生
深思慎考4 小时前
RabbitMQ 入门:基于 AMQP-CPP 的 C++ 实践指南与二次封装
开发语言·c++·分布式·rabbitmq·api
catchadmin4 小时前
PHP8.5 的新 URI 扩展
开发语言·后端·php
似水流年 光阴已逝5 小时前
从Excel姓名匹配案例学Python:由点及面的系统化学习指南
开发语言·python·excel
重生之我要当java大帝5 小时前
java微服务-尚医通-管理平台前端搭建-医院设置管理-4
java·开发语言·前端
Q_Q19632884755 小时前
python+vue的在线租房 房屋租赁系统
开发语言·vue.js·spring boot·python·django·flask·node.js
东巴图5 小时前
分解如何利用c++修复小程序的BUG
开发语言·c++·bug
祁同伟.5 小时前
【C++】二叉搜索树(图码详解)
开发语言·数据结构·c++·容器·stl