|
10 | 10 | - [Example for DirectX12 users](#example-for-directx12-users)
|
11 | 11 | - [Example for SDL_Renderer users](#example-for-sdl_renderer-users)
|
12 | 12 | - [Example for Vulkan users](#example-for-vulkan-users)
|
| 13 | +- [Example for WebGPU users](#example-for-webgpu-users) |
13 | 14 | - [Loading from Memory](#loading-from-memory)
|
14 | 15 | - [About Texture Coordinates](#about-texture-coordinates)
|
15 | 16 |
|
@@ -937,11 +938,176 @@ RemoveTexture(&my_texture);
|
937 | 938 |
|
938 | 939 | ----
|
939 | 940 |
|
| 941 | +## Example for WebGPU users |
| 942 | +
|
| 943 | +We will here use [stb_image.h](https://github.com/nothings/stb/blob/master/stb_image.h) to load images from disk. |
| 944 | +
|
| 945 | +Add at the top of one of your source file: |
| 946 | +```cpp |
| 947 | +#define _CRT_SECURE_NO_WARNINGS |
| 948 | +#define STB_IMAGE_IMPLEMENTATION |
| 949 | +#include "stb_image.h" |
| 950 | +
|
| 951 | +// Simple helper function to load an image into a WebGPU texture with common settings |
| 952 | +bool LoadTextureFromMemory(const void * data, |
| 953 | + size_t data_size, |
| 954 | + WGPUDevice device, |
| 955 | + WGPUQueue queue, |
| 956 | + WGPUTexture * out_texture, |
| 957 | + WGPUTextureView * out_texture_view, |
| 958 | + int * out_width, |
| 959 | + int * out_height) { |
| 960 | + // Load image |
| 961 | + int image_width = 0; |
| 962 | + int image_height = 0; |
| 963 | + // Ask stbi to output 4 channels since WebGPU doesn't have 3-channels texture format |
| 964 | + const int output_channels = 4; |
| 965 | + void * const image_data = stbi_load_from_memory((const unsigned char *)data, |
| 966 | + (int)data_size, |
| 967 | + &image_width, |
| 968 | + &image_height, |
| 969 | + NULL, |
| 970 | + output_channels); |
| 971 | + if (image_data == NULL) |
| 972 | + return false; |
| 973 | +
|
| 974 | + // Create a WebGPU texture |
| 975 | + WGPUTextureDescriptor texture_desc; |
| 976 | + texture_desc.nextInChain = NULL; |
| 977 | + texture_desc.label = NULL; |
| 978 | + texture_desc.usage = WGPUTextureUsage_CopyDst | WGPUTextureUsage_TextureBinding; |
| 979 | + texture_desc.dimension = WGPUTextureDimension_2D; |
| 980 | + texture_desc.size.width = (uint32_t)image_width; |
| 981 | + texture_desc.size.height = (uint32_t)image_height; |
| 982 | + texture_desc.size.depthOrArrayLayers = 1; |
| 983 | + texture_desc.format = WGPUTextureFormat_RGBA8Unorm; |
| 984 | + texture_desc.mipLevelCount = 1; |
| 985 | + texture_desc.sampleCount = 1; |
| 986 | + texture_desc.viewFormatCount = 0; |
| 987 | + texture_desc.viewFormats = NULL; |
| 988 | + WGPUTexture image_texture = wgpuDeviceCreateTexture(device, &texture_desc); |
| 989 | +
|
| 990 | + // Write loaded data to texture |
| 991 | + WGPUImageCopyTexture dest; |
| 992 | + dest.nextInChain = NULL; |
| 993 | + dest.texture = image_texture; |
| 994 | + dest.mipLevel = 0; |
| 995 | + dest.origin.x = 0; |
| 996 | + dest.origin.y = 0; |
| 997 | + dest.origin.z = 0; |
| 998 | + dest.aspect = WGPUTextureAspect_All; |
| 999 | +
|
| 1000 | + WGPUTextureDataLayout src; |
| 1001 | + src.nextInChain = NULL; |
| 1002 | + src.offset = 0; |
| 1003 | + src.bytesPerRow = (uint32_t)(output_channels * image_width); |
| 1004 | + src.rowsPerImage = (uint32_t)image_height; |
| 1005 | +
|
| 1006 | + const size_t bytes = src.bytesPerRow * src.rowsPerImage; |
| 1007 | + WGPUExtent3D write_size; |
| 1008 | + write_size.width = (uint32_t)image_width; |
| 1009 | + write_size.height = (uint32_t)image_height; |
| 1010 | + write_size.depthOrArrayLayers = 1; |
| 1011 | + wgpuQueueWriteTexture(queue, &dest, image_data, bytes, &src, &write_size); |
| 1012 | +
|
| 1013 | + // Create a WebGPU texture view |
| 1014 | + WGPUTextureViewDescriptor view_desc; |
| 1015 | + view_desc.nextInChain = NULL; |
| 1016 | + view_desc.label = NULL; |
| 1017 | + view_desc.format = WGPUTextureFormat_RGBA8Unorm; |
| 1018 | + view_desc.dimension = WGPUTextureViewDimension_2D; |
| 1019 | + view_desc.baseMipLevel = 0; |
| 1020 | + view_desc.mipLevelCount = 1; |
| 1021 | + view_desc.baseArrayLayer = 0; |
| 1022 | + view_desc.arrayLayerCount = 1; |
| 1023 | + view_desc.aspect = WGPUTextureAspect_All; |
| 1024 | +
|
| 1025 | + *out_texture = image_texture; |
| 1026 | + *out_texture_view = wgpuTextureCreateView(image_texture, &view_desc); |
| 1027 | + *out_width = image_width; |
| 1028 | + *out_height = image_height; |
| 1029 | +
|
| 1030 | + return true; |
| 1031 | +} |
| 1032 | +
|
| 1033 | +// Open and read a file, then forward to LoadTextureFromMemory() |
| 1034 | +bool LoadTextureFromFile(const char * file_name, |
| 1035 | + WGPUDevice device, |
| 1036 | + WGPUQueue queue, |
| 1037 | + WGPUTexture * out_texture, |
| 1038 | + WGPUTextureView * out_texture_view, |
| 1039 | + int * out_width, |
| 1040 | + int * out_height) { |
| 1041 | + FILE * f = fopen(file_name, "rb"); |
| 1042 | + if (f == NULL) |
| 1043 | + return false; |
| 1044 | + fseek(f, 0, SEEK_END); |
| 1045 | + long file_size = ftell(f); |
| 1046 | + if (file_size == -1) |
| 1047 | + return false; |
| 1048 | + fseek(f, 0, SEEK_SET); |
| 1049 | + void * file_data = IM_ALLOC(file_size); |
| 1050 | + fread(file_data, 1, (size_t)file_size, f); |
| 1051 | + bool ret = LoadTextureFromMemory(file_data, |
| 1052 | + (size_t)file_size, |
| 1053 | + device, |
| 1054 | + queue, |
| 1055 | + out_texture, |
| 1056 | + out_texture_view, |
| 1057 | + out_width, |
| 1058 | + out_height); |
| 1059 | + IM_FREE(file_data); |
| 1060 | + return ret; |
| 1061 | +} |
| 1062 | +``` |
| 1063 | + |
| 1064 | +After initializing a `WGPUDevice` and a `WGPUQueue`, load our texture: |
| 1065 | +```cpp |
| 1066 | +WGPUDevice device = /* ... */; |
| 1067 | +WGPUQueue queue = /* ... */; |
| 1068 | + |
| 1069 | +WGPUTexture my_texture = NULL; |
| 1070 | +WGPUTextureView my_texture_view = NULL; |
| 1071 | +int my_image_width = 0; |
| 1072 | +int my_image_height = 0; |
| 1073 | +bool ret = LoadTextureFromFile("../../MyImage01.jpg", |
| 1074 | + device, |
| 1075 | + queue, |
| 1076 | + &my_texture, |
| 1077 | + &my_texture_view, |
| 1078 | + &my_image_width, |
| 1079 | + &my_image_height); |
| 1080 | +IM_ASSERT(ret); |
| 1081 | +``` |
| 1082 | +
|
| 1083 | +In the snippet of code above, we added an assert `IM_ASSERT(ret)` to check if the image file was loaded correctly. You may also use your Debugger and confirm that `my_image_texture` is not zero and that `my_image_width` `my_image_height` are correct. |
| 1084 | +
|
| 1085 | +Now that we have a WebGPU texture view and its dimensions, we can display it in our main loop: |
| 1086 | +```cpp |
| 1087 | +ImGui::Begin("WebGPU Texture Test"); |
| 1088 | +ImGui::Text("pointer = %p", my_texture_view); |
| 1089 | +ImGui::Text("size = %d x %d", my_image_width, my_image_height); |
| 1090 | +ImGui::Image((void *)my_texture_view, ImVec2(my_image_width, my_image_height)); |
| 1091 | +ImGui::End(); |
| 1092 | +``` |
| 1093 | + |
| 1094 | +Don't forget to clean the memory at the end of the program: |
| 1095 | +```cpp |
| 1096 | +wgpuTextureViewRelease(my_texture_view); |
| 1097 | +wgpuTextureRelease(my_texture); |
| 1098 | +``` |
| 1099 | +
|
| 1100 | + |
| 1101 | +
|
| 1102 | +##### [Return to Index](#index) |
| 1103 | +
|
| 1104 | +---- |
| 1105 | +
|
940 | 1106 | ## Loading from Memory
|
941 | 1107 |
|
942 | 1108 | If instead of loading from a file you would like to load from memory, you can call `stbi_load_from_memory()` instead of `stbi_load()`.
|
943 | 1109 | All `LoadTextureFromFile()` function could be reworked to call `LoadTextureFromMemory()` which contains most of the code.
|
944 |
| -See our implementation of `LoadTextureFromFile()` for OpenGL, DX11 and DX12 examples. |
| 1110 | +See our implementation of `LoadTextureFromFile()` for OpenGL, DX11, DX12 and WebGPU examples. |
945 | 1111 |
|
946 | 1112 | ##### [Return to Index](#index)
|
947 | 1113 |
|
|
0 commit comments