karl2d_windows.odin 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305
  1. #+build windows
  2. package karl2d
  3. import "base:runtime"
  4. import win32 "core:sys/windows"
  5. import d3d11 "vendor:directx/d3d11"
  6. import dxgi "vendor:directx/dxgi"
  7. import "vendor:directx/d3d_compiler"
  8. import "core:strings"
  9. import "core:log"
  10. import "core:math/linalg"
  11. import "core:slice"
  12. import "core:mem"
  13. import "core:math"
  14. import "core:image"
  15. import hm "handle_map"
  16. import "core:image/bmp"
  17. import "core:image/png"
  18. import "core:image/tga"
  19. _ :: bmp
  20. _ :: png
  21. _ :: tga
  22. _init :: proc(width: int, height: int, title: string,
  23. allocator := context.allocator, loc := #caller_location) -> ^State {
  24. win32.SetProcessDPIAware()
  25. s = new(State, allocator, loc)
  26. s.allocator = allocator
  27. s.custom_context = context
  28. CLASS_NAME :: "karl2d"
  29. instance := win32.HINSTANCE(win32.GetModuleHandleW(nil))
  30. s.run = true
  31. s.width = width
  32. s.height = height
  33. cls := win32.WNDCLASSW {
  34. lpfnWndProc = window_proc,
  35. lpszClassName = CLASS_NAME,
  36. hInstance = instance,
  37. hCursor = win32.LoadCursorA(nil, win32.IDC_ARROW),
  38. }
  39. win32.RegisterClassW(&cls)
  40. r: win32.RECT
  41. r.right = i32(width)
  42. r.bottom = i32(height)
  43. style := win32.WS_OVERLAPPEDWINDOW | win32.WS_VISIBLE
  44. win32.AdjustWindowRect(&r, style, false)
  45. hwnd := win32.CreateWindowW(CLASS_NAME,
  46. win32.utf8_to_wstring(title),
  47. style,
  48. 100, 10, r.right - r.left, r.bottom - r.top,
  49. nil, nil, instance, nil)
  50. s.window = hwnd
  51. assert(hwnd != nil, "Failed creating window")
  52. feature_levels := [?]d3d11.FEATURE_LEVEL{
  53. ._11_1,
  54. ._11_0,
  55. }
  56. base_device: ^d3d11.IDevice
  57. base_device_context: ^d3d11.IDeviceContext
  58. device_flags := d3d11.CREATE_DEVICE_FLAGS {
  59. .BGRA_SUPPORT,
  60. }
  61. when ODIN_DEBUG {
  62. device_flags += { .DEBUG }
  63. }
  64. ch(d3d11.CreateDevice(
  65. nil,
  66. .HARDWARE,
  67. nil,
  68. device_flags,
  69. &feature_levels[0], len(feature_levels),
  70. d3d11.SDK_VERSION, &base_device, nil, &base_device_context))
  71. ch(base_device->QueryInterface(d3d11.IInfoQueue_UUID, (^rawptr)(&s.info_queue)))
  72. ch(base_device->QueryInterface(d3d11.IDevice_UUID, (^rawptr)(&s.device)))
  73. ch(base_device_context->QueryInterface(d3d11.IDeviceContext_UUID, (^rawptr)(&s.device_context)))
  74. dxgi_device: ^dxgi.IDevice
  75. ch(s.device->QueryInterface(dxgi.IDevice_UUID, (^rawptr)(&dxgi_device)))
  76. base_device->Release()
  77. base_device_context->Release()
  78. dxgi_adapter: ^dxgi.IAdapter
  79. ch(dxgi_device->GetAdapter(&dxgi_adapter))
  80. dxgi_device->Release()
  81. dxgi_factory: ^dxgi.IFactory2
  82. ch(dxgi_adapter->GetParent(dxgi.IFactory2_UUID, (^rawptr)(&dxgi_factory)))
  83. swapchain_desc := dxgi.SWAP_CHAIN_DESC1 {
  84. Format = .B8G8R8A8_UNORM,
  85. SampleDesc = {
  86. Count = 1,
  87. },
  88. BufferUsage = {.RENDER_TARGET_OUTPUT},
  89. BufferCount = 2,
  90. Scaling = .STRETCH,
  91. SwapEffect = .DISCARD,
  92. }
  93. ch(dxgi_factory->CreateSwapChainForHwnd(s.device, hwnd, &swapchain_desc, nil, nil, &s.swapchain))
  94. ch(s.swapchain->GetBuffer(0, d3d11.ITexture2D_UUID, (^rawptr)(&s.framebuffer)))
  95. ch(s.device->CreateRenderTargetView(s.framebuffer, nil, &s.framebuffer_view))
  96. depth_buffer_desc: d3d11.TEXTURE2D_DESC
  97. s.framebuffer->GetDesc(&depth_buffer_desc)
  98. depth_buffer_desc.Format = .D24_UNORM_S8_UINT
  99. depth_buffer_desc.BindFlags = {.DEPTH_STENCIL}
  100. ch(s.device->CreateTexture2D(&depth_buffer_desc, nil, &s.depth_buffer))
  101. ch(s.device->CreateDepthStencilView(s.depth_buffer, nil, &s.depth_buffer_view))
  102. rasterizer_desc := d3d11.RASTERIZER_DESC{
  103. FillMode = .SOLID,
  104. CullMode = .BACK,
  105. }
  106. ch(s.device->CreateRasterizerState(&rasterizer_desc, &s.rasterizer_state))
  107. depth_stencil_desc := d3d11.DEPTH_STENCIL_DESC{
  108. DepthEnable = false,
  109. DepthWriteMask = .ALL,
  110. DepthFunc = .LESS,
  111. }
  112. ch(s.device->CreateDepthStencilState(&depth_stencil_desc, &s.depth_stencil_state))
  113. vertex_buffer_desc := d3d11.BUFFER_DESC{
  114. ByteWidth = VERTEX_BUFFER_MAX,
  115. Usage = .DYNAMIC,
  116. BindFlags = {.VERTEX_BUFFER},
  117. CPUAccessFlags = {.WRITE},
  118. }
  119. ch(s.device->CreateBuffer(&vertex_buffer_desc, nil, &s.vertex_buffer_gpu))
  120. s.vertex_buffer_cpu = make([]u8, VERTEX_BUFFER_MAX, allocator, loc)
  121. blend_desc := d3d11.BLEND_DESC {
  122. RenderTarget = {
  123. 0 = {
  124. BlendEnable = true,
  125. SrcBlend = .SRC_ALPHA,
  126. DestBlend = .INV_SRC_ALPHA,
  127. BlendOp = .ADD,
  128. SrcBlendAlpha = .ONE,
  129. DestBlendAlpha = .ZERO,
  130. BlendOpAlpha = .ADD,
  131. RenderTargetWriteMask = u8(d3d11.COLOR_WRITE_ENABLE_ALL),
  132. },
  133. },
  134. }
  135. ch(s.device->CreateBlendState(&blend_desc, &s.blend_state))
  136. s.proj_matrix = make_default_projection(s.width, s.height)
  137. s.view_matrix = 1
  138. sampler_desc := d3d11.SAMPLER_DESC{
  139. Filter = .MIN_MAG_MIP_POINT,
  140. AddressU = .WRAP,
  141. AddressV = .WRAP,
  142. AddressW = .WRAP,
  143. ComparisonFunc = .NEVER,
  144. }
  145. s.device->CreateSamplerState(&sampler_desc, &s.sampler_state)
  146. s.default_shader = _load_shader(string(shader_hlsl), {
  147. .RG32_Float,
  148. .RG32_Float,
  149. .RGBA8_Norm,
  150. })
  151. white_rect: [16*16*4]u8
  152. slice.fill(white_rect[:], 255)
  153. s.shape_drawing_texture = _load_texture_from_memory(white_rect[:], 16, 16)
  154. return s
  155. }
  156. shader_hlsl :: #load("shader.hlsl")
  157. s: ^State
  158. VERTEX_BUFFER_MAX :: 1000000
  159. Handle :: hm.Handle
  160. Texture_Handle :: distinct hm.Handle
  161. TEXTURE_NONE :: Texture_Handle {}
  162. Shader_Constant_Buffer :: struct {
  163. gpu_data: ^d3d11.IBuffer,
  164. cpu_data: []u8,
  165. }
  166. Shader_Builtin_Constant :: enum {
  167. MVP,
  168. }
  169. Shader_Input_Type :: enum {
  170. F32,
  171. Vec2,
  172. Vec3,
  173. Vec4,
  174. }
  175. Shader_Input :: struct {
  176. name: string,
  177. register: int,
  178. type: Shader_Input_Type,
  179. format: Shader_Input_Format,
  180. }
  181. Shader_Default_Inputs :: enum {
  182. Position,
  183. UV,
  184. Color,
  185. }
  186. Shader :: struct {
  187. handle: Shader_Handle,
  188. vertex_shader: ^d3d11.IVertexShader,
  189. pixel_shader: ^d3d11.IPixelShader,
  190. input_layout: ^d3d11.IInputLayout,
  191. constant_buffers: []Shader_Constant_Buffer,
  192. constant_lookup: map[string]Shader_Constant_Location,
  193. constant_builtin_locations: [Shader_Builtin_Constant]Maybe(Shader_Constant_Location),
  194. inputs: []Shader_Input,
  195. input_overrides: []Shader_Input_Value_Override,
  196. default_input_offsets: [Shader_Default_Inputs]int,
  197. vertex_size: int,
  198. }
  199. State :: struct {
  200. swapchain: ^dxgi.ISwapChain1,
  201. framebuffer_view: ^d3d11.IRenderTargetView,
  202. depth_buffer_view: ^d3d11.IDepthStencilView,
  203. device_context: ^d3d11.IDeviceContext,
  204. depth_stencil_state: ^d3d11.IDepthStencilState,
  205. rasterizer_state: ^d3d11.IRasterizerState,
  206. device: ^d3d11.IDevice,
  207. depth_buffer: ^d3d11.ITexture2D,
  208. framebuffer: ^d3d11.ITexture2D,
  209. blend_state: ^d3d11.IBlendState,
  210. shape_drawing_texture: Texture,
  211. sampler_state: ^d3d11.ISamplerState,
  212. default_shader: Shader_Handle,
  213. textures: hm.Handle_Map(_Texture, Texture_Handle, 1024*10),
  214. shaders: hm.Handle_Map(Shader, Shader_Handle, 1024*10),
  215. info_queue: ^d3d11.IInfoQueue,
  216. vertex_buffer_gpu: ^d3d11.IBuffer,
  217. vertex_buffer_cpu: []u8,
  218. vertex_buffer_cpu_used: int,
  219. vertex_buffer_offset: int,
  220. run: bool,
  221. custom_context: runtime.Context,
  222. allocator: runtime.Allocator,
  223. batch_texture: Texture_Handle,
  224. batch_camera: Maybe(Camera),
  225. batch_shader: Shader_Handle,
  226. window: win32.HWND,
  227. width: int,
  228. height: int,
  229. keys_went_down: #sparse [Keyboard_Key]bool,
  230. keys_went_up: #sparse [Keyboard_Key]bool,
  231. keys_is_held: #sparse [Keyboard_Key]bool,
  232. view_matrix: matrix[4,4]f32,
  233. proj_matrix: matrix[4,4]f32,
  234. }
  235. VK_MAP := [255]Keyboard_Key {
  236. win32.VK_A = .A,
  237. win32.VK_B = .B,
  238. win32.VK_C = .C,
  239. win32.VK_D = .D,
  240. win32.VK_E = .E,
  241. win32.VK_F = .F,
  242. win32.VK_G = .G,
  243. win32.VK_H = .H,
  244. win32.VK_I = .I,
  245. win32.VK_J = .J,
  246. win32.VK_K = .K,
  247. win32.VK_L = .L,
  248. win32.VK_M = .M,
  249. win32.VK_N = .N,
  250. win32.VK_O = .O,
  251. win32.VK_P = .P,
  252. win32.VK_Q = .Q,
  253. win32.VK_R = .R,
  254. win32.VK_S = .S,
  255. win32.VK_T = .T,
  256. win32.VK_U = .U,
  257. win32.VK_V = .V,
  258. win32.VK_W = .W,
  259. win32.VK_X = .X,
  260. win32.VK_Y = .Y,
  261. win32.VK_Z = .Z,
  262. win32.VK_LEFT = .Left,
  263. win32.VK_RIGHT = .Right,
  264. win32.VK_UP = .Up,
  265. win32.VK_DOWN = .Down,
  266. }
  267. window_proc :: proc "stdcall" (hwnd: win32.HWND, msg: win32.UINT, wparam: win32.WPARAM, lparam: win32.LPARAM) -> win32.LRESULT {
  268. context = s.custom_context
  269. switch msg {
  270. case win32.WM_DESTROY:
  271. win32.PostQuitMessage(0)
  272. s.run = false
  273. case win32.WM_CLOSE:
  274. s.run = false
  275. case win32.WM_KEYDOWN:
  276. key := VK_MAP[wparam]
  277. s.keys_went_down[key] = true
  278. s.keys_is_held[key] = true
  279. case win32.WM_KEYUP:
  280. key := VK_MAP[wparam]
  281. s.keys_is_held[key] = false
  282. s.keys_went_up[key] = true
  283. }
  284. return win32.DefWindowProcW(hwnd, msg, wparam, lparam)
  285. }
  286. _shutdown :: proc() {
  287. _destroy_texture(s.shape_drawing_texture)
  288. _destroy_shader(s.default_shader)
  289. s.sampler_state->Release()
  290. s.framebuffer_view->Release()
  291. s.depth_buffer_view->Release()
  292. s.depth_buffer->Release()
  293. s.framebuffer->Release()
  294. s.device_context->Release()
  295. s.vertex_buffer_gpu->Release()
  296. //s.constant_buffer->Release()
  297. s.depth_stencil_state->Release()
  298. s.rasterizer_state->Release()
  299. s.swapchain->Release()
  300. s.blend_state->Release()
  301. delete(s.vertex_buffer_cpu, s.allocator)
  302. when ODIN_DEBUG {
  303. debug: ^d3d11.IDebug
  304. if ch(s.device->QueryInterface(d3d11.IDebug_UUID, (^rawptr)(&debug))) >= 0 {
  305. ch(debug->ReportLiveDeviceObjects({.DETAIL, .IGNORE_INTERNAL}))
  306. log_messages()
  307. }
  308. debug->Release()
  309. }
  310. s.device->Release()
  311. s.info_queue->Release()
  312. a := s.allocator
  313. free(s, a)
  314. s = nil
  315. }
  316. _set_internal_state :: proc(new_state: ^State) {
  317. s = new_state
  318. }
  319. Color_F32 :: [4]f32
  320. f32_color_from_color :: proc(color: Color) -> Color_F32 {
  321. return {
  322. f32(color.r) / 255,
  323. f32(color.g) / 255,
  324. f32(color.b) / 255,
  325. f32(color.a) / 255,
  326. }
  327. }
  328. _clear :: proc(color: Color) {
  329. c := f32_color_from_color(color)
  330. s.device_context->ClearRenderTargetView(s.framebuffer_view, &c)
  331. s.device_context->ClearDepthStencilView(s.depth_buffer_view, {.DEPTH}, 1, 0)
  332. }
  333. _Texture :: struct {
  334. handle: Texture_Handle,
  335. tex: ^d3d11.ITexture2D,
  336. view: ^d3d11.IShaderResourceView,
  337. }
  338. _load_texture_from_file :: proc(filename: string) -> Texture {
  339. img, img_err := image.load_from_file(filename, options = {.alpha_add_if_missing}, allocator = context.temp_allocator)
  340. if img_err != nil {
  341. log.errorf("Error loading texture %v: %v", filename, img_err)
  342. return {}
  343. }
  344. return _load_texture_from_memory(img.pixels.buf[:], img.width, img.height)
  345. }
  346. _load_texture_from_memory :: proc(data: []u8, width: int, height: int) -> Texture {
  347. texture_desc := d3d11.TEXTURE2D_DESC{
  348. Width = u32(width),
  349. Height = u32(height),
  350. MipLevels = 1,
  351. ArraySize = 1,
  352. // TODO: _SRGB or not?
  353. Format = .R8G8B8A8_UNORM,
  354. SampleDesc = {Count = 1},
  355. Usage = .IMMUTABLE,
  356. BindFlags = {.SHADER_RESOURCE},
  357. }
  358. texture_data := d3d11.SUBRESOURCE_DATA{
  359. pSysMem = raw_data(data),
  360. SysMemPitch = u32(width * 4),
  361. }
  362. texture: ^d3d11.ITexture2D
  363. s.device->CreateTexture2D(&texture_desc, &texture_data, &texture)
  364. texture_view: ^d3d11.IShaderResourceView
  365. s.device->CreateShaderResourceView(texture, nil, &texture_view)
  366. tex := _Texture {
  367. tex = texture,
  368. view = texture_view,
  369. }
  370. handle := hm.add(&s.textures, tex)
  371. return {
  372. id = handle,
  373. width = width,
  374. height = height,
  375. }
  376. }
  377. _destroy_texture :: proc(tex: Texture) {
  378. if t := hm.get(&s.textures, tex.id); t != nil {
  379. t.tex->Release()
  380. t.view->Release()
  381. }
  382. hm.remove(&s.textures, tex.id)
  383. }
  384. _draw_texture :: proc(tex: Texture, pos: Vec2, tint := WHITE) {
  385. _draw_texture_ex(
  386. tex,
  387. {0, 0, f32(tex.width), f32(tex.height)},
  388. {pos.x, pos.y, f32(tex.width), f32(tex.height)},
  389. {},
  390. 0,
  391. tint,
  392. )
  393. }
  394. _draw_texture_rect :: proc(tex: Texture, rect: Rect, pos: Vec2, tint := WHITE) {
  395. _draw_texture_ex(
  396. tex,
  397. rect,
  398. {pos.x, pos.y, rect.w, rect.h},
  399. {},
  400. 0,
  401. tint,
  402. )
  403. }
  404. Shader_Input_Value_Override :: struct {
  405. val: [256]u8,
  406. used: int,
  407. }
  408. create_vertex_input_override :: proc(val: $T) -> Shader_Input_Value_Override {
  409. assert(size_of(T) < 256)
  410. res: Shader_Input_Value_Override
  411. ((^T)(raw_data(&res.val)))^ = val
  412. res.used = size_of(T)
  413. return res
  414. }
  415. set_vertex_input_override :: proc(shader: Shader_Handle, input_idx: int, override: Shader_Input_Value_Override) {
  416. shd := hm.get(&s.shaders, shader)
  417. if shd == nil {
  418. log.error("Valid shader")
  419. return
  420. }
  421. if input_idx < 0 || input_idx >= len(shd.input_overrides) {
  422. log.error("Override input idx out of bounds")
  423. return
  424. }
  425. shd.input_overrides[input_idx] = override
  426. }
  427. batch_vertex :: proc(v: Vec2, uv: Vec2, color: Color) {
  428. v := v
  429. if s.vertex_buffer_cpu_used == len(s.vertex_buffer_cpu) {
  430. panic("Must dispatch here")
  431. }
  432. shd := hm.get(&s.shaders, s.batch_shader)
  433. if shd == nil {
  434. shd = hm.get(&s.shaders, s.default_shader)
  435. assert(shd != nil, "Failed fetching default shader")
  436. }
  437. base_offset := s.vertex_buffer_cpu_used
  438. pos_offset := shd.default_input_offsets[.Position]
  439. uv_offset := shd.default_input_offsets[.UV]
  440. color_offset := shd.default_input_offsets[.Color]
  441. if pos_offset != -1 {
  442. (^Vec2)(&s.vertex_buffer_cpu[base_offset + pos_offset])^ = v
  443. }
  444. if uv_offset != -1 {
  445. (^Vec2)(&s.vertex_buffer_cpu[base_offset + uv_offset])^ = uv
  446. }
  447. if color_offset != -1 {
  448. (^Color)(&s.vertex_buffer_cpu[base_offset + color_offset])^ = color
  449. }
  450. override_offset: int
  451. for &o, idx in shd.input_overrides {
  452. input := &shd.inputs[idx]
  453. sz := shader_input_format_size(input.format)
  454. if o.used != 0 {
  455. mem.copy(&s.vertex_buffer_cpu[base_offset + override_offset], raw_data(&o.val), o.used)
  456. }
  457. override_offset += sz
  458. }
  459. s.vertex_buffer_cpu_used += shd.vertex_size
  460. }
  461. _draw_texture_ex :: proc(tex: Texture, src: Rect, dst: Rect, origin: Vec2, rot: f32, tint := WHITE) {
  462. if tex.width == 0 || tex.height == 0 {
  463. return
  464. }
  465. if s.batch_texture != TEXTURE_NONE && s.batch_texture != tex.id {
  466. _draw_current_batch()
  467. }
  468. r := dst
  469. r.x -= origin.x
  470. r.y -= origin.y
  471. s.batch_texture = tex.id
  472. tl, tr, bl, br: Vec2
  473. // Rotation adapted from Raylib's "DrawTexturePro"
  474. if rot == 0 {
  475. x := dst.x - origin.x
  476. y := dst.y - origin.y
  477. tl = { x, y }
  478. tr = { x + dst.w, y }
  479. bl = { x, y + dst.h }
  480. br = { x + dst.w, y + dst.h }
  481. } else {
  482. sin_rot := math.sin(rot * math.RAD_PER_DEG)
  483. cos_rot := math.cos(rot * math.RAD_PER_DEG)
  484. x := dst.x
  485. y := dst.y
  486. dx := -origin.x
  487. dy := -origin.y
  488. tl = {
  489. x + dx * cos_rot - dy * sin_rot,
  490. y + dx * sin_rot + dy * cos_rot,
  491. }
  492. tr = {
  493. x + (dx + dst.w) * cos_rot - dy * sin_rot,
  494. y + (dx + dst.w) * sin_rot + dy * cos_rot,
  495. }
  496. bl = {
  497. x + dx * cos_rot - (dy + dst.h) * sin_rot,
  498. y + dx * sin_rot + (dy + dst.h) * cos_rot,
  499. }
  500. br = {
  501. x + (dx + dst.w) * cos_rot - (dy + dst.h) * sin_rot,
  502. y + (dx + dst.w) * sin_rot + (dy + dst.h) * cos_rot,
  503. }
  504. }
  505. ts := Vec2{f32(tex.width), f32(tex.height)}
  506. up := Vec2{src.x, src.y} / ts
  507. us := Vec2{src.w, src.h} / ts
  508. c := tint
  509. batch_vertex(tl, up, c)
  510. batch_vertex(tr, up + {us.x, 0}, c)
  511. batch_vertex(br, up + us, c)
  512. batch_vertex(tl, up, c)
  513. batch_vertex(br, up + us, c)
  514. batch_vertex(bl, up + {0, us.y}, c)
  515. }
  516. _draw_rectangle :: proc(r: Rect, c: Color) {
  517. if s.batch_texture != TEXTURE_NONE && s.batch_texture != s.shape_drawing_texture.id {
  518. _draw_current_batch()
  519. }
  520. s.batch_texture = s.shape_drawing_texture.id
  521. batch_vertex({r.x, r.y}, {0, 0}, c)
  522. batch_vertex({r.x + r.w, r.y}, {1, 0}, c)
  523. batch_vertex({r.x + r.w, r.y + r.h}, {1, 1}, c)
  524. batch_vertex({r.x, r.y}, {0, 0}, c)
  525. batch_vertex({r.x + r.w, r.y + r.h}, {1, 1}, c)
  526. batch_vertex({r.x, r.y + r.h}, {0, 1}, c)
  527. }
  528. _draw_rectangle_outline :: proc(r: Rect, thickness: f32, color: Color) {
  529. t := thickness
  530. // Based on DrawRectangleLinesEx from Raylib
  531. top := Rect {
  532. r.x,
  533. r.y,
  534. r.w,
  535. t,
  536. }
  537. bottom := Rect {
  538. r.x,
  539. r.y + r.h - t,
  540. r.w,
  541. t,
  542. }
  543. left := Rect {
  544. r.x,
  545. r.y + t,
  546. t,
  547. r.h - t * 2,
  548. }
  549. right := Rect {
  550. r.x + r.w - t,
  551. r.y + t,
  552. t,
  553. r.h - t * 2,
  554. }
  555. _draw_rectangle(top, color)
  556. _draw_rectangle(bottom, color)
  557. _draw_rectangle(left, color)
  558. _draw_rectangle(right, color)
  559. }
  560. _draw_circle :: proc(center: Vec2, radius: f32, color: Color) {
  561. }
  562. _draw_line :: proc(start: Vec2, end: Vec2, thickness: f32, color: Color) {
  563. }
  564. _get_screen_width :: proc() -> int {
  565. return s.width
  566. }
  567. _get_screen_height :: proc() -> int {
  568. return s.height
  569. }
  570. _get_default_shader :: proc() -> Shader_Handle {
  571. return s.default_shader
  572. }
  573. _key_went_down :: proc(key: Keyboard_Key) -> bool {
  574. return s.keys_went_down[key]
  575. }
  576. _key_went_up :: proc(key: Keyboard_Key) -> bool {
  577. return s.keys_went_up[key]
  578. }
  579. _key_is_held :: proc(key: Keyboard_Key) -> bool {
  580. return s.keys_is_held[key]
  581. }
  582. _window_should_close :: proc() -> bool {
  583. return !s.run
  584. }
  585. _draw_text :: proc(text: string, pos: Vec2, font_size: f32, color: Color) {
  586. }
  587. _mouse_button_pressed :: proc(button: Mouse_Button) -> bool {
  588. return false
  589. }
  590. _mouse_button_released :: proc(button: Mouse_Button) -> bool {
  591. return false
  592. }
  593. _mouse_button_held :: proc(button: Mouse_Button) -> bool {
  594. return false
  595. }
  596. _mouse_wheel_delta :: proc() -> f32 {
  597. return 0
  598. }
  599. _mouse_position :: proc() -> Vec2 {
  600. return {}
  601. }
  602. _enable_scissor :: proc(x, y, w, h: int) {
  603. }
  604. _disable_scissor :: proc() {
  605. }
  606. _set_window_size :: proc(width: int, height: int) {
  607. }
  608. _set_window_position :: proc(x: int, y: int) {
  609. // TODO: Does x, y respect monitor DPI?
  610. win32.SetWindowPos(
  611. s.window,
  612. {},
  613. i32(x),
  614. i32(y),
  615. 0,
  616. 0,
  617. win32.SWP_NOACTIVATE | win32.SWP_NOZORDER | win32.SWP_NOSIZE,
  618. )
  619. }
  620. _screen_to_world :: proc(pos: Vec2, camera: Camera) -> Vec2 {
  621. return pos
  622. }
  623. Vec3 :: [3]f32
  624. vec3_from_vec2 :: proc(v: Vec2) -> Vec3 {
  625. return {
  626. v.x, v.y, 0,
  627. }
  628. }
  629. _set_camera :: proc(camera: Maybe(Camera)) {
  630. if camera == s.batch_camera {
  631. return
  632. }
  633. _draw_current_batch()
  634. s.batch_camera = camera
  635. if c, c_ok := camera.?; c_ok {
  636. origin_trans := linalg.matrix4_translate(vec3_from_vec2(-c.origin))
  637. translate := linalg.matrix4_translate(vec3_from_vec2(c.target))
  638. rot := linalg.matrix4_rotate_f32(c.rotation * math.RAD_PER_DEG, {0, 0, 1})
  639. camera_matrix := translate * rot * origin_trans
  640. s.view_matrix = linalg.inverse(camera_matrix)
  641. s.proj_matrix = make_default_projection(s.width, s.height)
  642. s.proj_matrix[0, 0] *= c.zoom
  643. s.proj_matrix[1, 1] *= c.zoom
  644. } else {
  645. s.proj_matrix = make_default_projection(s.width, s.height)
  646. s.view_matrix = 1
  647. }
  648. }
  649. _set_scissor_rect :: proc(scissor_rect: Maybe(Rect)) {
  650. }
  651. _set_shader :: proc(shader: Shader_Handle) {
  652. if shader == s.batch_shader {
  653. return
  654. }
  655. _draw_current_batch()
  656. s.batch_shader = shader
  657. }
  658. _set_shader_constant :: proc(shader: Shader_Handle, loc: Shader_Constant_Location, val: $T) {
  659. _draw_current_batch()
  660. shd := hm.get(&s.shaders, shader)
  661. if shd == nil {
  662. return
  663. }
  664. if int(loc.buffer_idx) >= len(shd.constant_buffers) {
  665. log.warnf("Constant buffer idx %v is out of bounds", loc.buffer_idx)
  666. return
  667. }
  668. b := &shd.constant_buffers[loc.buffer_idx]
  669. if int(loc.offset) + size_of(val) > len(b.cpu_data) {
  670. log.warnf("Constant buffer idx %v is trying to be written out of bounds by at offset %v with %v bytes", loc.buffer_idx, loc.offset, size_of(val))
  671. return
  672. }
  673. dst := (^T)(&b.cpu_data[loc.offset])
  674. dst^ = val
  675. }
  676. _set_shader_constant_mat4 :: proc(shader: Shader_Handle, loc: Shader_Constant_Location, val: matrix[4,4]f32) {
  677. _set_shader_constant(shader, loc, val)
  678. }
  679. _set_shader_constant_f32 :: proc(shader: Shader_Handle, loc: Shader_Constant_Location, val: f32) {
  680. _set_shader_constant(shader, loc, val)
  681. }
  682. _set_shader_constant_vec2 :: proc(shader: Shader_Handle, loc: Shader_Constant_Location, val: Vec2) {
  683. _set_shader_constant(shader, loc, val)
  684. }
  685. _process_events :: proc() {
  686. s.keys_went_up = {}
  687. s.keys_went_down = {}
  688. msg: win32.MSG
  689. for win32.PeekMessageW(&msg, nil, 0, 0, win32.PM_REMOVE) {
  690. win32.TranslateMessage(&msg)
  691. win32.DispatchMessageW(&msg)
  692. }
  693. }
  694. _draw_current_batch :: proc() {
  695. if s.vertex_buffer_cpu_used == s.vertex_buffer_offset {
  696. return
  697. }
  698. viewport := d3d11.VIEWPORT{
  699. 0, 0,
  700. f32(s.width), f32(s.height),
  701. 0, 1,
  702. }
  703. dc := s.device_context
  704. vb_data: d3d11.MAPPED_SUBRESOURCE
  705. ch(dc->Map(s.vertex_buffer_gpu, 0, .WRITE_NO_OVERWRITE, {}, &vb_data))
  706. {
  707. gpu_map := slice.from_ptr((^u8)(vb_data.pData), VERTEX_BUFFER_MAX)
  708. copy(
  709. gpu_map[s.vertex_buffer_offset:s.vertex_buffer_cpu_used],
  710. s.vertex_buffer_cpu[s.vertex_buffer_offset:s.vertex_buffer_cpu_used],
  711. )
  712. }
  713. dc->Unmap(s.vertex_buffer_gpu, 0)
  714. dc->IASetPrimitiveTopology(.TRIANGLELIST)
  715. shd := hm.get(&s.shaders, s.batch_shader)
  716. if shd == nil {
  717. shd = hm.get(&s.shaders, s.default_shader)
  718. assert(shd != nil, "Failed fetching default shader")
  719. }
  720. dc->IASetInputLayout(shd.input_layout)
  721. vertex_buffer_offset := u32(0)
  722. vertex_buffer_stride := u32(shd.vertex_size)
  723. dc->IASetVertexBuffers(0, 1, &s.vertex_buffer_gpu, &vertex_buffer_stride, &vertex_buffer_offset)
  724. for mloc, builtin in shd.constant_builtin_locations {
  725. loc, loc_ok := mloc.?
  726. if !loc_ok {
  727. continue
  728. }
  729. switch builtin {
  730. case .MVP:
  731. dst := (^matrix[4,4]f32)(&shd.constant_buffers[loc.buffer_idx].cpu_data[loc.offset])
  732. dst^ = s.proj_matrix * s.view_matrix
  733. }
  734. }
  735. dc->VSSetShader(shd.vertex_shader, nil, 0)
  736. for &c, c_idx in shd.constant_buffers {
  737. if c.gpu_data == nil {
  738. continue
  739. }
  740. cb_data: d3d11.MAPPED_SUBRESOURCE
  741. ch(dc->Map(c.gpu_data, 0, .WRITE_DISCARD, {}, &cb_data))
  742. mem.copy(cb_data.pData, raw_data(c.cpu_data), len(c.cpu_data))
  743. dc->Unmap(c.gpu_data, 0)
  744. dc->VSSetConstantBuffers(u32(c_idx), 1, &c.gpu_data)
  745. dc->PSSetConstantBuffers(u32(c_idx), 1, &c.gpu_data)
  746. }
  747. dc->RSSetViewports(1, &viewport)
  748. dc->RSSetState(s.rasterizer_state)
  749. dc->PSSetShader(shd.pixel_shader, nil, 0)
  750. if t := hm.get(&s.textures, s.batch_texture); t != nil {
  751. dc->PSSetShaderResources(0, 1, &t.view)
  752. }
  753. dc->PSSetSamplers(0, 1, &s.sampler_state)
  754. dc->OMSetRenderTargets(1, &s.framebuffer_view, s.depth_buffer_view)
  755. dc->OMSetDepthStencilState(s.depth_stencil_state, 0)
  756. dc->OMSetBlendState(s.blend_state, nil, ~u32(0))
  757. dc->Draw(u32((s.vertex_buffer_cpu_used - s.vertex_buffer_offset)/shd.vertex_size), u32(s.vertex_buffer_offset/shd.vertex_size))
  758. s.vertex_buffer_offset = s.vertex_buffer_cpu_used
  759. log_messages()
  760. }
  761. make_default_projection :: proc(w, h: int) -> matrix[4,4]f32 {
  762. return linalg.matrix_ortho3d_f32(0, f32(w), f32(h), 0, 0.001, 2)
  763. }
  764. _present :: proc() {
  765. _draw_current_batch()
  766. ch(s.swapchain->Present(1, {}))
  767. s.vertex_buffer_offset = 0
  768. s.vertex_buffer_cpu_used = 0
  769. }
  770. Shader_Constant_Location :: struct {
  771. buffer_idx: u32,
  772. offset: u32,
  773. }
  774. _load_shader :: proc(shader: string, layout_formats: []Shader_Input_Format = {}) -> Shader_Handle {
  775. vs_blob: ^d3d11.IBlob
  776. vs_blob_errors: ^d3d11.IBlob
  777. ch(d3d_compiler.Compile(raw_data(shader), len(shader), nil, nil, nil, "vs_main", "vs_5_0", 0, 0, &vs_blob, &vs_blob_errors))
  778. if vs_blob_errors != nil {
  779. log.error("Failed compiling shader:")
  780. log.error(strings.string_from_ptr((^u8)(vs_blob_errors->GetBufferPointer()), int(vs_blob_errors->GetBufferSize())))
  781. }
  782. vertex_shader: ^d3d11.IVertexShader
  783. ch(s.device->CreateVertexShader(vs_blob->GetBufferPointer(), vs_blob->GetBufferSize(), nil, &vertex_shader))
  784. ref: ^d3d11.IShaderReflection
  785. ch(d3d_compiler.Reflect(vs_blob->GetBufferPointer(), vs_blob->GetBufferSize(), d3d11.ID3D11ShaderReflection_UUID, (^rawptr)(&ref)))
  786. constant_buffers: []Shader_Constant_Buffer
  787. constant_lookup: map[string]Shader_Constant_Location
  788. constant_builtin_locations: [Shader_Builtin_Constant]Maybe(Shader_Constant_Location)
  789. inputs: []Shader_Input
  790. {
  791. context.allocator = s.allocator
  792. d: d3d11.SHADER_DESC
  793. ch(ref->GetDesc(&d))
  794. inputs = make([]Shader_Input, d.InputParameters)
  795. for in_idx in 0..<d.InputParameters {
  796. in_desc: d3d11.SIGNATURE_PARAMETER_DESC
  797. if ch(ref->GetInputParameterDesc(in_idx, &in_desc)) < 0 {
  798. log.errorf("Invalid input: %v in shader %v", in_idx, shader)
  799. continue
  800. }
  801. type: Shader_Input_Type
  802. if in_desc.SemanticIndex > 0 {
  803. log.errorf("Matrix shader input types not yet implemented")
  804. continue
  805. }
  806. switch in_desc.ComponentType {
  807. case .UNKNOWN: log.errorf("Unknown component type")
  808. case .UINT32: log.errorf("Not implemented")
  809. case .SINT32: log.errorf("Not implemented")
  810. case .FLOAT32:
  811. switch in_desc.Mask {
  812. case 0: log.errorf("Invalid input mask"); continue
  813. case 1: type = .F32
  814. case 3: type = .Vec2
  815. case 7: type = .Vec3
  816. case 15: type = .Vec4
  817. }
  818. }
  819. inputs[in_idx] = {
  820. name = strings.clone_from_cstring(in_desc.SemanticName),
  821. register = int(in_idx),
  822. type = type,
  823. }
  824. }
  825. constant_buffers = make([]Shader_Constant_Buffer, d.ConstantBuffers)
  826. for cb_idx in 0..<d.ConstantBuffers {
  827. cb_info := ref->GetConstantBufferByIndex(cb_idx)
  828. if cb_info == nil {
  829. continue
  830. }
  831. cb_desc: d3d11.SHADER_BUFFER_DESC
  832. cb_info->GetDesc(&cb_desc)
  833. if cb_desc.Size == 0 {
  834. continue
  835. }
  836. b := &constant_buffers[cb_idx]
  837. b.cpu_data = make([]u8, cb_desc.Size, s.allocator)
  838. constant_buffer_desc := d3d11.BUFFER_DESC{
  839. ByteWidth = cb_desc.Size,
  840. Usage = .DYNAMIC,
  841. BindFlags = {.CONSTANT_BUFFER},
  842. CPUAccessFlags = {.WRITE},
  843. }
  844. ch(s.device->CreateBuffer(&constant_buffer_desc, nil, &b.gpu_data))
  845. for var_idx in 0..<cb_desc.Variables {
  846. var_info := cb_info->GetVariableByIndex(var_idx)
  847. if var_info == nil {
  848. continue
  849. }
  850. var_desc: d3d11.SHADER_VARIABLE_DESC
  851. var_info->GetDesc(&var_desc)
  852. if var_desc.Name != "" {
  853. loc := Shader_Constant_Location {
  854. buffer_idx = cb_idx,
  855. offset = var_desc.StartOffset,
  856. }
  857. constant_lookup[strings.clone_from_cstring(var_desc.Name)] = loc
  858. switch var_desc.Name {
  859. case "mvp":
  860. constant_builtin_locations[.MVP] = loc
  861. }
  862. }
  863. // TODO add the size or type somewhere so we set it correctly
  864. /*log.info(var_desc)
  865. type_info := var_info->GetType()
  866. type_info_desc: d3d11.SHADER_TYPE_DESC
  867. type_info->GetDesc(&type_info_desc)
  868. log.info(type_info_desc)*/
  869. }
  870. }
  871. }
  872. default_input_offsets: [Shader_Default_Inputs]int
  873. for &d in default_input_offsets {
  874. d = -1
  875. }
  876. input_offset: int
  877. if len(layout_formats) > 0 {
  878. if len(layout_formats) != len(inputs) {
  879. log.error("Passed number of layout formats isn't same as number of shader inputs")
  880. } else {
  881. for &i, idx in inputs {
  882. i.format = layout_formats[idx]
  883. if i.name == "POS" && i.type == .Vec2 {
  884. default_input_offsets[.Position] = input_offset
  885. } else if i.name == "UV" && i.type == .Vec2 {
  886. default_input_offsets[.UV] = input_offset
  887. } else if i.name == "COL" && i.type == .Vec4 {
  888. default_input_offsets[.Color] = input_offset
  889. }
  890. input_offset += shader_input_format_size(i.format)
  891. }
  892. }
  893. } else {
  894. for &i in inputs {
  895. if i.name == "POS" && i.type == .Vec2 {
  896. i.format = .RG32_Float
  897. default_input_offsets[.Position] = input_offset
  898. } else if i.name == "UV" && i.type == .Vec2 {
  899. i.format = .RG32_Float
  900. default_input_offsets[.UV] = input_offset
  901. } else if i.name == "COL" && i.type == .Vec4 {
  902. i.format = .RGBA8_Norm
  903. default_input_offsets[.Color] = input_offset
  904. } else {
  905. switch i.type {
  906. case .F32: i.format = .R32_Float
  907. case .Vec2: i.format = .RG32_Float
  908. case .Vec3: i.format = .RGBA32_Float
  909. case .Vec4: i.format = .RGBA32_Float
  910. }
  911. }
  912. input_offset += shader_input_format_size(i.format)
  913. }
  914. }
  915. input_layout_desc := make([]d3d11.INPUT_ELEMENT_DESC, len(inputs), context.temp_allocator)
  916. for idx in 0..<len(inputs) {
  917. input := inputs[idx]
  918. input_layout_desc[idx] = {
  919. SemanticName = temp_cstring(input.name),
  920. Format = dxgi_format_from_shader_input_format(input.format),
  921. AlignedByteOffset = idx == 0 ? 0 : d3d11.APPEND_ALIGNED_ELEMENT,
  922. InputSlotClass = .VERTEX_DATA,
  923. }
  924. }
  925. input_layout: ^d3d11.IInputLayout
  926. ch(s.device->CreateInputLayout(raw_data(input_layout_desc), u32(len(input_layout_desc)), vs_blob->GetBufferPointer(), vs_blob->GetBufferSize(), &input_layout))
  927. ps_blob: ^d3d11.IBlob
  928. ps_blob_errors: ^d3d11.IBlob
  929. ch(d3d_compiler.Compile(raw_data(shader), len(shader), nil, nil, nil, "ps_main", "ps_5_0", 0, 0, &ps_blob, &ps_blob_errors))
  930. if ps_blob_errors != nil {
  931. log.error("Failed compiling shader:")
  932. log.error(strings.string_from_ptr((^u8)(ps_blob_errors->GetBufferPointer()), int(ps_blob_errors->GetBufferSize())))
  933. }
  934. pixel_shader: ^d3d11.IPixelShader
  935. ch(s.device->CreatePixelShader(ps_blob->GetBufferPointer(), ps_blob->GetBufferSize(), nil, &pixel_shader))
  936. shd := Shader {
  937. vertex_shader = vertex_shader,
  938. pixel_shader = pixel_shader,
  939. input_layout = input_layout,
  940. constant_buffers = constant_buffers,
  941. constant_lookup = constant_lookup,
  942. constant_builtin_locations = constant_builtin_locations,
  943. inputs = inputs,
  944. input_overrides = make([]Shader_Input_Value_Override, len(inputs)),
  945. default_input_offsets = default_input_offsets,
  946. vertex_size = input_offset,
  947. }
  948. h := hm.add(&s.shaders, shd)
  949. return h
  950. }
  951. dxgi_format_from_shader_input_format :: proc(f: Shader_Input_Format) -> dxgi.FORMAT {
  952. switch f {
  953. case .Unknown: return .UNKNOWN
  954. case .RGBA32_Float: return .R32G32B32A32_FLOAT
  955. case .RGBA8_Norm: return .R8G8B8A8_UNORM
  956. case .RGBA8_Norm_SRGB: return .R8G8B8A8_UNORM_SRGB
  957. case .RG32_Float: return .R32G32_FLOAT
  958. case .R32_Float: return .R32_FLOAT
  959. }
  960. log.error("Unknown format")
  961. return .UNKNOWN
  962. }
  963. shader_input_format_size :: proc(f: Shader_Input_Format) -> int {
  964. switch f {
  965. case .Unknown: return 0
  966. case .RGBA32_Float: return 32
  967. case .RGBA8_Norm: return 4
  968. case .RGBA8_Norm_SRGB: return 4
  969. case .RG32_Float: return 8
  970. case .R32_Float: return 4
  971. }
  972. return 0
  973. }
  974. _destroy_shader :: proc(shader: Shader_Handle) {
  975. if shd := hm.get(&s.shaders, shader); shd != nil {
  976. shd.input_layout->Release()
  977. shd.vertex_shader->Release()
  978. shd.pixel_shader->Release()
  979. for c in shd.constant_buffers {
  980. if c.gpu_data != nil {
  981. c.gpu_data->Release()
  982. }
  983. delete(c.cpu_data)
  984. }
  985. delete(shd.constant_buffers)
  986. for k,_ in shd.constant_lookup {
  987. delete(k)
  988. }
  989. delete(shd.constant_lookup)
  990. for i in shd.inputs {
  991. delete(i.name)
  992. }
  993. delete(shd.inputs)
  994. }
  995. hm.remove(&s.shaders, shader)
  996. }
  997. _get_shader_constant_location :: proc(shader: Shader_Handle, name: string) -> Shader_Constant_Location {
  998. shd := hm.get(&s.shaders, shader)
  999. if shd == nil {
  1000. return {}
  1001. }
  1002. return shd.constant_lookup[name]
  1003. }
  1004. temp_cstring :: proc(str: string, loc := #caller_location) -> cstring {
  1005. return strings.clone_to_cstring(str, context.temp_allocator, loc)
  1006. }
  1007. // CHeck win errors and print message log if there is any error
  1008. ch :: proc(hr: win32.HRESULT, loc := #caller_location) -> win32.HRESULT {
  1009. if hr >= 0 {
  1010. return hr
  1011. }
  1012. log.errorf("d3d11 error: %0x", u32(hr), location = loc)
  1013. log_messages(loc)
  1014. return hr
  1015. }
  1016. log_messages :: proc(loc := #caller_location) {
  1017. iq := s.info_queue
  1018. if iq == nil {
  1019. return
  1020. }
  1021. n := iq->GetNumStoredMessages()
  1022. longest_msg: d3d11.SIZE_T
  1023. for i in 0..=n {
  1024. msglen: d3d11.SIZE_T
  1025. iq->GetMessage(i, nil, &msglen)
  1026. if msglen > longest_msg {
  1027. longest_msg = msglen
  1028. }
  1029. }
  1030. if longest_msg > 0 {
  1031. msg_raw_ptr, _ := (mem.alloc(int(longest_msg), allocator = context.temp_allocator))
  1032. for i in 0..=n {
  1033. msglen: d3d11.SIZE_T
  1034. iq->GetMessage(i, nil, &msglen)
  1035. if msglen > 0 {
  1036. msg := (^d3d11.MESSAGE)(msg_raw_ptr)
  1037. iq->GetMessage(i, msg, &msglen)
  1038. log.error(msg.pDescription, location = loc)
  1039. }
  1040. }
  1041. }
  1042. iq->ClearStoredMessages()
  1043. }