golang实现Direct3D9图形编程绑定插件库d3d9的使用

Golang实现Direct3D9图形编程绑定插件库d3d9的使用

概述

d3d9是一个纯Go语言封装的Microsoft Direct3D9 API库。它提供了完整的Direct3D9功能接口,让开发者可以在Go语言中使用Direct3D9进行图形编程。

安装

使用以下命令获取并安装d3d9库:

go get -u github.com/gonutz/d3d9

运行Direct3D9应用程序需要系统已安装d3d9.dll。从Windows XP开始,所有Windows版本都已预装这个DLL,因此使用此库时不需要额外分发DLL文件。

使用示例

以下是一个使用d3d9库创建Direct3D9设备并渲染简单场景的完整示例:

package main

import (
	"github.com/gonutz/d3d9"
	"github.com/AllenDang/w32"
	"runtime"
	"unsafe"
)

func init() {
	runtime.LockOSThread()
}

func main() {
	// 1. 创建Direct3D对象
	d3d, err := d3d9.Create(d3d9.SDK_VERSION)
	if err != nil {
		panic(err)
	}
	defer d3d.Release()

	// 2. 获取显示模式
	var mode d3d9.DISPLAYMODE
	if err := d3d.GetAdapterDisplayMode(d3d9.ADAPTER_DEFAULT, &mode); err != nil {
		panic(err)
	}

	// 3. 创建窗口
	className := "D3D9WindowClass"
	w32.RegisterClass(&w32.WNDCLASSEX{
		ClassName: className,
		WndProc:   w32.DefWindowProc,
	})
	hwnd := w32.CreateWindow(
		className,
		"Direct3D9 Go Example",
		w32.WS_OVERLAPPEDWINDOW,
		w32.CW_USEDEFAULT, w32.CW_USEDEFAULT,
		800, 600,
		0, 0, 0, nil,
	)
	w32.ShowWindow(hwnd, w32.SW_SHOW)

	// 4. 创建设备参数
	params := d3d9.PRESENT_PARAMETERS{
		BackBufferWidth:  800,
		BackBufferHeight: 600,
		BackBufferFormat: mode.Format,
		BackBufferCount:  1,
		SwapEffect:       d3d9.SWAPEFFECT_DISCARD,
		Windowed:         1,
	}

	// 5. 创建Direct3D设备
	device, _, err := d3d.CreateDevice(
		d3d9.ADAPTER_DEFAULT,
		d3d9.DEVTYPE_HAL,
		uintptr(hwnd),
		d3d9.CREATE_SOFTWARE_VERTEXPROCESSING,
		params,
	)
	if err != nil {
		panic(err)
	}
	defer device.Release()

	// 6. 主渲染循环
	for {
		// 检查消息
		var msg w32.MSG
		if w32.PeekMessage(&msg, 0, 0, 0, w32.PM_REMOVE) {
			if msg.Message == w32.WM_QUIT {
				break
			}
			w32.TranslateMessage(&msg)
			w32.DispatchMessage(&msg)
		} else {
			// 清屏为蓝色
			device.Clear(
				nil,
				d3d9.CLEAR_TARGET,
				d3d9.ColorRGB(0, 0, 255),
				1.0,
				0,
			)

			// 开始渲染场景
			if err := device.BeginScene(); err != nil {
				panic(err)
			}

			// 这里可以添加渲染代码
			
			// 结束渲染场景
			if err := device.EndScene(); err != nil {
				panic(err)
			}

			// 显示到屏幕
			if err := device.Present(nil, nil, 0, nil); err != nil {
				panic(err)
			}
		}
	}
}

命名约定

d3d9库对Direct3D9 API的命名做了以下调整:

  1. 接口类型去掉IDirect3D前缀和9后缀,例如:

    • IDirect3DDevice9d3d9.Device
    • IDirect3D9d3d9.Direct3D
  2. 常量和枚举去掉D3D前缀,保留大写命名:

    • D3DADAPTER_DEFAULTd3d9.ADAPTER_DEFAULT
    • D3DFMT_R8G8B8d3d9.FMT_R8G8B8
  3. 结构体同样去掉D3D前缀:

    • D3DRANGEd3d9.RANGE
  4. 错误处理:

    • 函数返回Go的error而非HRESULT
    • 错误常量变为ERR_OUTOFVIDEOMEMORY

重要注意事项

  1. 线程限制:所有Direct3D9调用必须在创建Direct3D9对象的同一线程中进行,因此需要在main包中添加:
func init() {
    runtime.LockOSThread()
}
  1. 窗口创建:d3d9库本身不提供窗口创建功能,需要使用其他库(如SDL2 Go wrapper或Allen Dang的w32)创建窗口并获取窗口句柄。

  2. 资源锁定:对于IndexBufferVertexBuffer的锁定操作,d3d9提供了方便的方法如GetFloat32sSetFloat32s来处理数据,比直接使用uintptr更符合Go的编程习惯。

实际应用案例

d3d9库已经被用于多个实际项目中:

  1. GopherGala 2016参赛作品: Gophette Screenshot

  2. Ludum Dare Game Jam 2016参赛作品: Reinventing the Wheel Screenshot

文档参考

完整的API文档请参考官方GoDoc文档。对于更详细的Direct3D9 API说明,请参考Microsoft的MSDN文档。

贡献

欢迎通过使用、反馈、fork项目、提交pull request或创建issue来帮助改进这个库。


更多关于golang实现Direct3D9图形编程绑定插件库d3d9的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang实现Direct3D9图形编程绑定插件库d3d9的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang实现Direct3D9图形编程绑定

Direct3D9是微软早期推出的3D图形API,虽然现在已不是主流技术,但在一些遗留系统中仍有应用。下面我将介绍如何在Go语言中使用d3d9绑定库进行Direct3D9图形编程。

准备工作

首先需要安装Go语言的d3d9绑定库:

go get github.com/gonutz/d3d9

这个库提供了对Direct3D9 API的完整封装,让我们可以在Go中调用Direct3D9功能。

基本示例代码

下面是一个简单的Direct3D9初始化示例:

package main

import (
	"github.com/gonutz/d3d9"
	"github.com/gonutz/w32"
	"log"
)

func main() {
	// 1. 创建Direct3D9对象
	d3d, err := d3d9.Create(d3d9.SDK_VERSION)
	if err != nil {
		log.Fatal("创建Direct3D9失败:", err)
	}
	defer d3d.Release()

	// 2. 创建窗口
	className := "MyWindowClass"
	w32.RegisterClassEx(&w32.WNDCLASSEX{
		WndProc:   w32.DefWindowProc,
		ClassName: className,
	})
	hwnd := w32.CreateWindow(
		className,
		"Go Direct3D9示例",
		w32.WS_OVERLAPPEDWINDOW,
		w32.CW_USEDEFAULT, w32.CW_USEDEFAULT,
		800, 600,
		0, 0, 0, nil,
	)
	w32.ShowWindow(hwnd, w32.SW_SHOWDEFAULT)
	w32.UpdateWindow(hwnd)

	// 3. 检查设备能力
	var caps d3d9.CAPS
	if err := d3d.GetDeviceCaps(d3d9.ADAPTER_DEFAULT, d3d9.DEVTYPE_HAL, &caps); err != nil {
		log.Fatal("获取设备能力失败:", err)
	}

	// 4. 创建设备
	device, _, err := d3d.CreateDevice(
		d3d9.ADAPTER_DEFAULT,
		d3d9.DEVTYPE_HAL,
		d3d9.HWND(hwnd),
		d3d9.CREATE_SOFTWARE_VERTEXPROCESSING,
		d3d9.PRESENT_PARAMETERS{
			Windowed:         1,
			SwapEffect:       d3d9.SWAPEFFECT_DISCARD,
			BackBufferFormat: d3d9.FMT_X8R8G8B8,
			BackBufferWidth:  800,
			BackBufferHeight: 600,
		},
	)
	if err != nil {
		log.Fatal("创建设备失败:", err)
	}
	defer device.Release()

	// 5. 主渲染循环
	for {
		// 处理Windows消息
		var msg w32.MSG
		if w32.PeekMessage(&msg, 0, 0, 0, w32.PM_REMOVE) {
			if msg.Message == w32.WM_QUIT {
				break
			}
			w32.TranslateMessage(&msg)
			w32.DispatchMessage(&msg)
		} else {
			// 清屏
			device.Clear(nil, d3d9.CLEAR_TARGET, d3d9.ColorRGB(0, 0, 128), 1.0, 0)
			
			// 开始渲染
			if err := device.BeginScene(); err != nil {
				log.Println("BeginScene失败:", err)
				continue
			}
			
			// 这里可以添加渲染代码
			
			// 结束渲染
			if err := device.EndScene(); err != nil {
				log.Println("EndScene失败:", err)
				continue
			}
			
			// 呈现到屏幕
			if err := device.Present(nil, nil, 0, nil); err != nil {
				log.Println("Present失败:", err)
				continue
			}
		}
	}
}

绘制三角形示例

下面是一个绘制彩色三角形的完整示例:

// 在之前的代码基础上添加以下内容

type Vertex struct {
	X, Y, Z float32
	Color   d3d9.Color
}

func setupScene(device *d3d9.Device) error {
	// 定义顶点格式
	const FVF = d3d9.FVF_XYZ | d3d9.FVF_DIFFUSE
	
	// 创建顶点缓冲区
	vb, err := device.CreateVertexBuffer(3*20, d3d9.USAGE_WRITEONLY, FVF, d3d9.POOL_DEFAULT, nil)
	if err != nil {
		return err
	}
	defer vb.Release()
	
	// 填充顶点数据
	var vertices []Vertex
	vertices = append(vertices, Vertex{-1.0, -1.0, 0.0, d3d9.ColorARGB(255, 255, 0, 0)})   // 红色
	vertices = append(vertices, Vertex{0.0, 1.0, 0.0, d3d9.ColorARGB(255, 0, 255, 0)})     // 绿色
	vertices = append(vertices, Vertex{1.0, -1.0, 0.0, d3d9.ColorARGB(255, 0, 0, 255)})    // 蓝色
	
	// 锁定缓冲区并写入数据
	ptr, err := vb.Lock(0, 0, d3d9.LOCK_DISCARD)
	if err != nil {
		return err
	}
	defer vb.Unlock()
	
	// 将顶点数据复制到缓冲区
	for _, v := range vertices {
		*ptr = v.X
		ptr = ptr[1:]
		*ptr = v.Y
		ptr = ptr[1:]
		*ptr = v.Z
		ptr = ptr[1:]
		*ptr = v.Color
		ptr = ptr[1:]
	}
	
	// 设置渲染状态
	device.SetRenderState(d3d9.RS_LIGHTING, 0) // 禁用光照
	device.SetRenderState(d3d9.RS_CULLMODE, d3d9.CULL_NONE) // 禁用背面剔除
	
	// 设置顶点流
	device.SetStreamSource(0, vb, 0, 20) // 每个顶点20字节(3*float32 + 1*Color)
	device.SetFVF(FVF)
	
	return nil
}

// 在主渲染循环中添加绘制代码
if err := device.DrawPrimitive(d3d9.PT_TRIANGLELIST, 0, 1); err != nil {
	log.Println("DrawPrimitive失败:", err)
}

注意事项

  1. 依赖关系:运行此代码需要系统已安装DirectX 9.0c运行时

  2. 性能考虑:Go语言与C++相比在图形编程上可能有性能损失,不适合高性能游戏开发

  3. 现代替代方案:对于新项目,建议考虑Vulkan、DirectX 12或WebGPU等现代图形API

  4. 错误处理:Direct3D API调用可能会失败,务必检查每个函数的返回值

  5. 资源管理:记得释放所有创建的COM对象(使用Release()方法)

这个示例展示了Go语言中使用Direct3D9的基本方法。虽然Go不是图形编程的主流语言,但这种绑定为特定场景下的集成提供了可能性。

回到顶部