CMake 编译stbimage和ffi调用动态库

stb_image 作为头文件库支持大量的图片文件格式,包括9种主流图片格式,而且是零依赖

编译动态链接库

      1、JPEG 
      2、PNG 
      3、TGA 
      4、BMP 
      5、PSD 
      6、GIF 
      7、HDR
      8、PIC
      9、PNM

CMake 编译STB_image动态库 dll 文件,当然在linux 中是 so

cmake_minimum_required(VERSION 3.5)

set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 11)

project(stb)
include_directories(src)
set(STB_SOURCES
    src/stb_image.h
    src/stb_image_write.h
    src/test.c
)
add_library(stb SHARED  ${STB_SOURCES} )
set_target_properties( stb PROPERTIES LINKER_LANGUAGE CXX)
target_link_libraries(stb )

编译dll时候出现一个问题,使用默认的连接器,因为源码都是头文件无法识别是何种代码,无法通过cmake编译,加入下面句子后通过编译

set_target_properties( stbi PROPERTIES LINKER_LANGUAGE CXX)

在这里插入图片描述
将生成的libstb.dll 复制到 luajit 目录位置
linux 复制到/usr/shared 目录下,

ffi 接口调用

ffi 是自带在luajit内的,在ffi调用c api 非常方便,来看一个例子,比如要调用change_a() 函数,change_a()函数定义在test.dll中,我们只需要做如下操作:

  • 在c语言环境下
int * a;
*a = 1;
void change_a(int *a){
	*a = *a + 1;
}
  • 在jitlua环境下
local ffi = require "ffi"
ffi.cedf([[void change_a(int *a);]])
lib = ffi.load(“libtest”) --这里加载对应的dll文件,位置要在luajit需要能访问到的路径里

ptr = ffi.new("int[1]")
--或ptr = ffi.new("int[?]",1)
lib.change_a(ptr)
print(ptr[0])

通过两步就能执行c/c++的二进制文件、甚至是fortan二进制文件,大大提升lua的实用性。输出为 libstbi.dll 动态库文件,大功告成。

stb_image ffi 实操

说了这么多,目的只要在是stbi_load() 和 stbi_image_free(),一个负责加载图像,一个负责

local ffi = require "ffi"
local lj_glfw = require("glfw")
local gllib = require"gl"
gllib.set_loader(lj_glfw)
local gl, glc, glu, glext = gllib.libraries()

ffi.cdef([[
	typedef unsigned char stbi_uc;
	typedef unsigned short stbi_us;
	stbi_uc * stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
	void     stbi_image_free      (void *retval_from_stbi_load);
]])
lib = ffi.load("libstb")

local M = {}

function M.load_image(name)
	local buffered_name = ffi.string(name)
	local xptr = ffi.new("int[1]")
	local yptr = ffi.new("int[1]")
	local chptr = ffi.new("int[1]")
	local pdata = ffi.new("unsigned char *")
	pdata = lib.stbi_load(buffered_name,xptr,yptr,chptr,0)

	gl.glTexParameteri(glc.GL_TEXTURE_2D, glc.GL_TEXTURE_WRAP_S, glc.GL_REPEAT);   
	gl.glTexParameteri(glc.GL_TEXTURE_2D, glc.GL_TEXTURE_WRAP_T, glc.GL_REPEAT);
	gl.glTexParameteri(glc.GL_TEXTURE_2D, glc.GL_TEXTURE_MIN_FILTER, glc.GL_LINEAR);
	gl.glTexParameteri(glc.GL_TEXTURE_2D, glc.GL_TEXTURE_MAG_FILTER, glc.GL_LINEAR);

	texture_ptr = ffi.new("GLuint[1]")
	gl.glGenTextures(1, texture_ptr)
	
	glext.glActiveTexture(glc.GL_TEXTURE0)
	-- gl.glBindTexture(glc.GL_TEXTURE_2D, 0);
    gl.glBindTexture(glc.GL_TEXTURE_2D, texture_ptr[0]);
    gl.glTexImage2D(glc.GL_TEXTURE_2D, 0, glc.GL_RGB, xptr[0], yptr[0], 0, glc.GL_RGB, glc.GL_UNSIGNED_BYTE, pdata)
    glext.glGenerateMipmap(glc.GL_TEXTURE_2D)

	local w = xptr[0]
	local h = yptr[0]
	local ch = chptr[0]
	local texid = texture_ptr[0]

	lib.stbi_image_free(pdata)
	return w,h,ch,texid
end

return M

因为stbi_load()第二、三、四、五个参数是返回在指针里的,这种情况通过ffi指针转换完成,注意参数返回的指针类型,data 是 unsigned char * 类型的数据,浮点类型贴图的需要修改代码,如果是多重贴图,记得打开相应的glActiveTexture参数,
顺道也把贴图环绕方式和Mipmap设定好,返回图形的信息如长宽是否带alpha通道,并返回texture id以备用

最终效果

texture id调用成功后,由于是第一张贴图,所以texture id返回的是1,说明贴图载入成功,可以进行模型贴图

下面是代码,几何图形一个面4个点配上uv,没有使用vbo或vao,不然又是一堆代码,而是直接用glBegin() glEnd()来写,程序不超过60行

local ffi = require("ffi")
local stb = require("stb")
local lj_glfw = require("glfw")

local gllib = require"gl"
gllib.set_loader(lj_glfw)
local gl, glc, glu, glext = gllib.libraries()

local ig = require"cimgui"

lj_glfw.init()
local window = lj_glfw.Window(700,500,"gl Triangle")
window:makeContextCurrent() 

local ig_impl = ig.Imgui_Impl_glfw_opengl3() --standard 

ig_impl:Init(window, true)

w,h,ch,tex_id = stb.load_image("tex.png")
print("tex_info",w,h,ch,tex_id)

gl.glEnable(glc.GL_TEXTURE_2D)
gl.glBindTexture(glc.GL_TEXTURE_2D, tex_id)

while not window:shouldClose() do

    lj_glfw.pollEvents()
    gl.glClearColor(0.1, 0.1, 0.1, 1.0)
    gl.glClear(glc.GL_COLOR_BUFFER_BIT)
    
    gl.glBegin(glc.GL_POLYGON)
    gl.glTexCoord2f(1.0, 1.0)
    gl.glVertex3f(0.5,  0.5, 0.0)

    gl.glTexCoord2f(1.0, 0.0)
    gl.glVertex3f(0.5, -0.5, 0.0)

    gl.glTexCoord2f(0.0, 0.0)
    gl.glVertex3f(-0.5, -0.5, 0.0)

    gl.glTexCoord2f(0.0, 1.0)
    gl.glVertex3f(-0.5,  0.5, 0.0)

    gl.glEnd()
    ig_impl:NewFrame()

    if ig.Button"Texture" then
        -- print"Hello World!!"
        -- do something
    end

    ig_impl:Render()
    window:swapBuffers() 
end

ig_impl:destroy()
window:destroy()
lj_glfw.terminate()

在这里插入图片描述

imgui 其中亦涉及到imgui opengl或vulkan backend 的使用GL和glfw封装都比较繁琐 如何从代码自动生成ffi cedf 。有兴趣可参考大神sonoro1234 的git仓库

后续

用luajit+ffi封装效率很高 容易重构 不需要反复编译

  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要使用 CMake 编译动态库和静态库,你可以按照以下步骤进行操作: 1. 创建一个 CMakeLists.txt 文件,该文件描述了构建过程和项目配置。 2. 在 CMakeLists.txt 文件中,使用 `add_library` 命令来定义要构建的库。使用 `SHARED` 参数来指定动态库,使用 `STATIC` 参数来指定静态库。例如: ```cmake # 构建动态库 add_library(mylib SHARED src/mylib.cpp) # 构建静态库 add_library(mylib_static STATIC src/mylib.cpp) ``` 3. 如果你有多个源文件,可以将它们一起添加到库中: ```cmake # 构建动态库 add_library(mylib SHARED src/mylib.cpp src/other.cpp) # 构建静态库 add_library(mylib_static STATIC src/mylib.cpp src/other.cpp) ``` 4. 如果你想为库定义公共头文件目录,可以使用 `target_include_directories` 命令。例如: ```cmake target_include_directories(mylib PUBLIC include) ``` 5. 如果你希望链接其他库到你的库中,可以使用 `target_link_libraries` 命令。例如: ```cmake target_link_libraries(mylib PUBLIC otherlib) ``` 6. 最后,在 CMakeLists.txt 文件中添加一个 `install` 命令,以便在构建过程完成后安装库文件到指定的目录。例如: ```cmake install(TARGETS mylib DESTINATION lib) install(FILES include/mylib.h DESTINATION include) ``` 7. 运行 CMake 命令来生成构建系统所需的文件: ```shell cmake . ``` 8. 使用生成的构建系统来编译和构建库: ```shell make ``` 在构建过程完成后,你将在指定的目录(例如 `lib`)中找到生成的动态库和静态库文件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值