专做热血电影的网站宝安区简介

张小明 2025/12/30 15:51:27
专做热血电影的网站,宝安区简介,百度关键字搜索到自己的网站,vs做网站通过e浏览器上一篇#xff1a;几何体系统 | 下一篇#xff1a;多渲染通道 | 返回目录 #x1f4da; 快速导航 目录 简介学习目标资源系统架构 为什么需要资源系统统一加载接口可插拔加载器 资源类型定义资源加载器模式 加载器结构加载器注册 内置加载器实现 文本加载器二进制加载器图像…上一篇几何体系统 | 下一篇多渲染通道 | 返回目录 快速导航目录简介学习目标资源系统架构为什么需要资源系统统一加载接口可插拔加载器资源类型定义资源加载器模式加载器结构加载器注册内置加载器实现文本加载器二进制加载器图像加载器材质加载器资源系统集成自定义加载器常见问题练习 简介在之前的教程中,我们实现了多个独立的资源管理系统:纹理系统、材质系统、几何体系统。每个系统都有自己的加载逻辑,这导致代码重复和维护困难。本教程将介绍资源系统(Resource System),它提供了一个统一的、可扩展的资源加载框架。通过加载器模式(Loader Pattern),资源系统将资源加载逻辑模块化,让不同类型的资源可以通过注册加载器来实现加载。Existing Systems 现有系统File System 文件系统Resource System 资源系统Loaders 加载器Texture System纹理系统Material System材质系统File System文件系统Resource System资源系统核心Text Loader文本加载器Binary Loader二进制加载器Image Loader图像加载器Material Loader材质加载器Custom Loader自定义加载器 学习目标目标描述理解资源系统的必要性了解为什么需要统一的资源加载框架掌握加载器模式学习可插拔加载器的设计和实现实现内置加载器实现文本、二进制、图像、材质加载器资源类型管理理解资源类型枚举和扩展机制系统集成将资源系统与现有系统集成️ 资源系统架构为什么需要资源系统在没有资源系统之前,每个系统都有自己的加载逻辑:❌ 问题: ┌─────────────────┐ │ Texture System │ → 加载 PNG/JPG │ - load_texture()│ └─────────────────┘ ┌─────────────────┐ │ Material System │ → 加载 .kmt 文件 │ - load_material│ └─────────────────┘ ┌─────────────────┐ │ Geometry System │ → 加载顶点数据 │ - load_geometry│ └─────────────────┘ 问题: 1. 代码重复 (文件读取、路径处理) 2. 难以扩展 (添加新类型需要修改多处) 3. 不一致的错误处理 4. 难以统一管理资源生命周期资源系统通过统一接口解决这些问题:✅ 解决方案: ┌──────────────────┐ │ Resource System │ │ │ │ register_loader │ │ load_resource │ │ unload_resource │ └────────┬─────────┘ │ ┌───────────────┼───────────────┐ │ │ │ ┌────▼────┐ ┌────▼────┐ ┌────▼────┐ │ Text │ │ Image │ │Material │ │ Loader │ │ Loader │ │ Loader │ └─────────┘ └─────────┘ └─────────┘ 优势: 1. 统一的加载接口 2. 可插拔的加载器 3. 一致的错误处理 4. 易于扩展新类型统一加载接口资源系统提供了简单的加载接口:// engine/src/systems/resource_system.h// 加载资源b8resource_system_load(constchar*name,resource_type type,resource*out_resource);// 卸载资源voidresource_system_unload(resource*resource);// 使用示例resource my_resource;if(resource_system_load(test.png,RESOURCE_TYPE_IMAGE,my_resource)){// 使用资源image_resource_data*image_data(image_resource_data*)my_resource.data;KINFO(Loaded image: %dx%d,image_data-width,image_data-height);// 卸载资源resource_system_unload(my_resource);}可插拔加载器资源系统通过注册加载器来支持不同的资源类型:// 注册加载器b8resource_system_register_loader(resource_loader*loader);// 示例:注册自定义加载器resource_loader my_loader;my_loader.typeRESOURCE_TYPE_CUSTOM;my_loader.custom_typemy_format;my_loader.loadmy_custom_load_function;my_loader.unloadmy_custom_unload_function;resource_system_register_loader(my_loader); 资源类型定义资源系统支持多种资源类型:// engine/src/resources/resource_types.h/** * brief 资源类型枚举 */typedefenumresource_type{RESOURCE_TYPE_TEXT,// 文本文件 (.txt, .json, .xml)RESOURCE_TYPE_BINARY,// 二进制文件 (通用)RESOURCE_TYPE_IMAGE,// 图像文件 (.png, .jpg)RESOURCE_TYPE_MATERIAL,// 材质配置 (.kmt)RESOURCE_TYPE_STATIC_MESH,// 静态网格 (.obj, .fbx)RESOURCE_TYPE_CUSTOM// 自定义类型}resource_type;/** * brief 资源结构 */typedefstructresource{u32 loader_id;// 加载器 IDconstchar*name;// 资源名称char*full_path;// 完整路径u64 data_size;// 数据大小void*data;// 资源数据}resource;/** * brief 图像资源数据 */typedefstructimage_resource_data{u8 channel_count;// 通道数u32 width;// 宽度u32 height;// 高度u8*pixels;// 像素数据}image_resource_data;资源类型的组织:资源类型层次: ┌────────────────────────────────┐ │ Resource (通用资源) │ │ - loader_id │ │ - name │ │ - full_path │ │ - data_size │ │ - data (void*) │ └────────┬───────────────────────┘ │ ├─► TEXT → data char* │ ├─► BINARY → data u8* │ ├─► IMAGE → data image_resource_data* │ ├─ width │ ├─ height │ ├─ channel_count │ └─ pixels │ ├─► MATERIAL → data material_config* │ └─► CUSTOM → data 自定义结构 资源加载器模式加载器结构每个加载器实现统一的接口:// engine/src/systems/resource_system.h/** * brief 资源加载器结构 */typedefstructresource_loader{u32 id;// 加载器 IDresource_type type;// 资源类型constchar*custom_type;// 自定义类型名称constchar*type_path;// 资源路径 (如 textures/)/** * brief 加载资源 * param self 加载器自身 * param name 资源名称 * param out_resource 输出资源 * return 成功返回 true */b8(*load)(structresource_loader*self,constchar*name,resource*out_resource);/** * brief 卸载资源 * param self 加载器自身 * param resource 要卸载的资源 */void(*unload)(structresource_loader*self,resource*resource);}resource_loader;加载器接口设计:加载器生命周期: ┌──────────────┐ │ Register │ → resource_system_register_loader() │ 注册加载器 │ └──────┬───────┘ │ ▼ ┌──────────────┐ │ Load │ → loader-load() │ 加载资源 │ ├─ 构建文件路径 │ │ ├─ 读取文件内容 └──────┬───────┘ ├─ 解析数据 │ └─ 返回 resource │ ▼ ┌──────────────┐ │ Use │ → 使用 resource-data │ 使用资源 │ └──────┬───────┘ │ ▼ ┌──────────────┐ │ Unload │ → loader-unload() │ 卸载资源 │ ├─ 释放 resource-data │ │ └─ 释放 resource-full_path └──────────────┘加载器注册资源系统维护加载器数组:// engine/src/systems/resource_system.c#defineMAX_LOADER_COUNT32typedefstructresource_system_state{resource_system_config config;resource_loader registered_loaders[MAX_LOADER_COUNT];}resource_system_state;staticresource_system_state*state_ptr0;b8resource_system_register_loader(resource_loader*loader){if(state_ptr0){returnfalse;}// 分配加载器 IDu32 countstate_ptr-config.max_loader_count;for(u32 i0;icount;i){if(state_ptr-registered_loaders[i].idINVALID_ID){state_ptr-registered_loaders[i]*loader;state_ptr-registered_loaders[i].idi;KINFO(Registered loader for type %d at index %d,loader-type,i);returntrue;}}KERROR(resource_system_register_loader - No available loader slots);returnfalse;} 内置加载器实现文本加载器加载纯文本文件:// engine/src/resources/loaders/text_loader.ctypedefstructtext_loader{// 基础路径 (如 assets/text/)charbase_path[512];}text_loader;staticb8text_loader_load(resource_loader*self,constchar*name,resource*out_resource){if(self0||name0||out_resource0){returnfalse;}text_loader*loader(text_loader*)self;// 构建完整路径charfull_path[512];string_format(full_path,%s%s%s,loader-base_path,name,.txt);// 读取文件file_handle f;if(!filesystem_open(full_path,FILE_MODE_READ,false,f)){KERROR(text_loader_load - Failed to open file: %s,full_path);returnfalse;}// 获取文件大小u64 file_size0;if(!filesystem_size(f,file_size)){KERROR(text_loader_load - Failed to get file size: %s,full_path);filesystem_close(f);returnfalse;}// 分配内存 (1 for null terminator)char*resource_datakallocate(file_size1,MEMORY_TAG_STRING);// 读取内容u64 read_size0;if(!filesystem_read_all_bytes(f,(u8*)resource_data,read_size)){KERROR(text_loader_load - Failed to read file: %s,full_path);kfree(resource_data,file_size1,MEMORY_TAG_STRING);filesystem_close(f);returnfalse;}filesystem_close(f);// 添加 null terminatorresource_data[file_size]\0;// 填充 resourceout_resource-full_pathstring_duplicate(full_path);out_resource-namename;out_resource-dataresource_data;out_resource-data_sizefile_size;out_resource-loader_idself-id;returntrue;}staticvoidtext_loader_unload(resource_loader*self,resource*resource){if(resource){if(resource-data){kfree(resource-data,resource-data_size1,MEMORY_TAG_STRING);}if(resource-full_path){u32 lengthstring_length(resource-full_path);kfree(resource-full_path,length1,MEMORY_TAG_STRING);}kzero_memory(resource,sizeof(resource));}}二进制加载器加载二进制文件:// engine/src/resources/loaders/binary_loader.cstaticb8binary_loader_load(resource_loader*self,constchar*name,resource*out_resource){if(self0||name0||out_resource0){returnfalse;}// 构建完整路径 (不添加扩展名,使用原始名称)charfull_path[512];string_format(full_path,%s%s,self-type_path,name);// 读取文件file_handle f;if(!filesystem_open(full_path,FILE_MODE_READ,true,f)){KERROR(binary_loader_load - Failed to open file: %s,full_path);returnfalse;}u64 file_size0;if(!filesystem_size(f,file_size)){KERROR(binary_loader_load - Failed to get file size: %s,full_path);filesystem_close(f);returnfalse;}// 分配内存u8*resource_datakallocate(file_size,MEMORY_TAG_ARRAY);// 读取内容u64 read_size0;if(!filesystem_read_all_bytes(f,resource_data,read_size)){KERROR(binary_loader_load - Failed to read file: %s,full_path);kfree(resource_data,file_size,MEMORY_TAG_ARRAY);filesystem_close(f);returnfalse;}filesystem_close(f);out_resource-full_pathstring_duplicate(full_path);out_resource-namename;out_resource-dataresource_data;out_resource-data_sizefile_size;out_resource-loader_idself-id;returntrue;}staticvoidbinary_loader_unload(resource_loader*self,resource*resource){if(resource){if(resource-data){kfree(resource-data,resource-data_size,MEMORY_TAG_ARRAY);}if(resource-full_path){u32 lengthstring_length(resource-full_path);kfree(resource-full_path,length1,MEMORY_TAG_STRING);}kzero_memory(resource,sizeof(resource));}}图像加载器加载图像文件 (PNG/JPG):// engine/src/resources/loaders/image_loader.c#defineSTB_IMAGE_IMPLEMENTATION#includevendor/stb_image.hstaticb8image_loader_load(resource_loader*self,constchar*name,resource*out_resource){if(self0||name0||out_resource0){returnfalse;}// 构建完整路径charfull_path[512];string_format(full_path,%s%s,self-type_path,name);// 使用 stb_image 加载image_resource_data*resource_datakallocate(sizeof(image_resource_data),MEMORY_TAG_TEXTURE);i32 width,height,channel_count;stbi_set_flip_vertically_on_load(true);resource_data-pixelsstbi_load(full_path,width,height,channel_count,0);if(!resource_data-pixels){KERROR(image_loader_load - Failed to load image: %s,full_path);kfree(resource_data,sizeof(image_resource_data),MEMORY_TAG_TEXTURE);returnfalse;}resource_data-widthwidth;resource_data-heightheight;resource_data-channel_countchannel_count;// 填充 resourceout_resource-full_pathstring_duplicate(full_path);out_resource-namename;out_resource-dataresource_data;out_resource-data_sizewidth*height*channel_count;out_resource-loader_idself-id;KINFO(Loaded image: %s (%dx%d, %d channels),name,width,height,channel_count);returntrue;}staticvoidimage_loader_unload(resource_loader*self,resource*resource){if(resource){if(resource-data){image_resource_data*data(image_resource_data*)resource-data;if(data-pixels){stbi_image_free(data-pixels);}kfree(data,sizeof(image_resource_data),MEMORY_TAG_TEXTURE);}if(resource-full_path){u32 lengthstring_length(resource-full_path);kfree(resource-full_path,length1,MEMORY_TAG_STRING);}kzero_memory(resource,sizeof(resource));}}材质加载器加载材质配置文件:// engine/src/resources/loaders/material_loader.ctypedefstructmaterial_config{charname[MATERIAL_NAME_MAX_LENGTH];b8 auto_release;vec4 diffuse_colour;chardiffuse_map_name[TEXTURE_NAME_MAX_LENGTH];}material_config;staticb8material_loader_load(resource_loader*self,constchar*name,resource*out_resource){if(self0||name0||out_resource0){returnfalse;}// 构建完整路径charfull_path[512];string_format(full_path,%s%s%s,self-type_path,name,.kmt);// 读取文件file_handle f;if(!filesystem_open(full_path,FILE_MODE_READ,false,f)){KERROR(material_loader_load - Failed to open file: %s,full_path);returnfalse;}// 读取配置material_config*resource_datakallocate(sizeof(material_config),MEMORY_TAG_MATERIAL);// 设置默认值resource_data-auto_releasefalse;string_ncopy(resource_data-name,name,MATERIAL_NAME_MAX_LENGTH);resource_data-diffuse_colourvec4_one();// 默认白色kzero_memory(resource_data-diffuse_map_name,TEXTURE_NAME_MAX_LENGTH);// 逐行解析charline_buf[512];char*pline_buf[0];u64 line_length0;while(filesystem_read_line(f,511,p,line_length)){// 去除前后空格char*trimmedstring_trim(line_buf);line_lengthstring_length(trimmed);// 跳过注释和空行if(line_length1||trimmed[0]#){continue;}// 解析 keyvaluei32 equal_indexstring_index_of(trimmed,);if(equal_index-1){KWARN(Potential formatting issue found in file %s: token not found,full_path);continue;}// 提取 key 和 valuecharkey[64];string_mid(key,trimmed,0,equal_index);char*key_trimmedstring_trim(key);charvalue[512];string_mid(value,trimmed,equal_index1,-1);char*value_trimmedstring_trim(value);// 解析具体配置if(strings_equali(key_trimmed,version)){// 版本号}elseif(strings_equali(key_trimmed,name)){string_ncopy(resource_data-name,value_trimmed,MATERIAL_NAME_MAX_LENGTH);}elseif(strings_equali(key_trimmed,diffuse_map_name)){string_ncopy(resource_data-diffuse_map_name,value_trimmed,TEXTURE_NAME_MAX_LENGTH);}elseif(strings_equali(key_trimmed,diffuse_colour)){// 解析颜色 (r g b a)if(!string_to_vec4(value_trimmed,resource_data-diffuse_colour)){KWARN(Failed to parse diffuse_colour in file %s,full_path);}}}filesystem_close(f);// 填充 resourceout_resource-full_pathstring_duplicate(full_path);out_resource-namename;out_resource-dataresource_data;out_resource-data_sizesizeof(material_config);out_resource-loader_idself-id;returntrue;}staticvoidmaterial_loader_unload(resource_loader*self,resource*resource){if(resource){if(resource-data){kfree(resource-data,sizeof(material_config),MEMORY_TAG_MATERIAL);}if(resource-full_path){u32 lengthstring_length(resource-full_path);kfree(resource-full_path,length1,MEMORY_TAG_STRING);}kzero_memory(resource,sizeof(resource));}} 资源系统集成系统初始化在资源系统初始化时注册所有内置加载器:// engine/src/systems/resource_system.cb8resource_system_initialize(u64*memory_requirement,void*state,resource_system_config config){if(config.max_loader_count0){KFATAL(resource_system_initialize - config.max_loader_count must be 0);returnfalse;}*memory_requirementsizeof(resource_system_state);if(state0){returntrue;}state_ptrstate;state_ptr-configconfig;// 初始化加载器数组for(u32 i0;iconfig.max_loader_count;i){state_ptr-registered_loaders[i].idINVALID_ID;}KINFO(Resource system initialized with %d loader slots,config.max_loader_count);// 注册内置加载器resource_loader text_loader;text_loader.typeRESOURCE_TYPE_TEXT;text_loader.custom_type0;text_loader.type_pathassets/text/;text_loader.loadtext_loader_load;text_loader.unloadtext_loader_unload;resource_system_register_loader(text_loader);resource_loader binary_loader;binary_loader.typeRESOURCE_TYPE_BINARY;binary_loader.custom_type0;binary_loader.type_pathassets/;binary_loader.loadbinary_loader_load;binary_loader.unloadbinary_loader_unload;resource_system_register_loader(binary_loader);resource_loader image_loader;image_loader.typeRESOURCE_TYPE_IMAGE;image_loader.custom_type0;image_loader.type_pathassets/textures/;image_loader.loadimage_loader_load;image_loader.unloadimage_loader_unload;resource_system_register_loader(image_loader);resource_loader material_loader;material_loader.typeRESOURCE_TYPE_MATERIAL;material_loader.custom_type0;material_loader.type_pathassets/materials/;material_loader.loadmaterial_loader_load;material_loader.unloadmaterial_loader_unload;resource_system_register_loader(material_loader);returntrue;}加载资源统一的加载接口:b8resource_system_load(constchar*name,resource_type type,resource*out_resource){if(state_ptr0||name0||out_resource0){returnfalse;}// 查找对应类型的加载器resource_loader*loader0;for(u32 i0;istate_ptr-config.max_loader_count;i){if(state_ptr-registered_loaders[i].id!INVALID_IDstate_ptr-registered_loaders[i].typetype){loaderstate_ptr-registered_loaders[i];break;}}if(loader0){KERROR(resource_system_load - No loader for type %d,type);returnfalse;}// 调用加载器KINFO(Loading resource %s with loader id %d,name,loader-id);returnloader-load(loader,name,out_resource);}voidresource_system_unload(resource*resource){if(state_ptr0||resource0){return;}// 查找加载器if(resource-loader_idstate_ptr-config.max_loader_count){KERROR(resource_system_unload - Invalid loader_id %d,resource-loader_id);return;}resource_loader*loaderstate_ptr-registered_loaders[resource-loader_id];if(loader-idINVALID_ID){KERROR(resource_system_unload - Loader %d is not registered,resource-loader_id);return;}KINFO(Unloading resource %s with loader id %d,resource-name,loader-id);loader-unload(loader,resource);}与现有系统集成纹理系统可以使用资源系统加载图像:// engine/src/systems/texture_system.c (修改后)b8texture_system_load(constchar*texture_name,texture*t){// 使用资源系统加载图像resource image_resource;if(!resource_system_load(texture_name,RESOURCE_TYPE_IMAGE,image_resource)){KERROR(Failed to load texture %s,texture_name);returnfalse;}// 提取图像数据image_resource_data*data(image_resource_data*)image_resource.data;// 创建纹理t-widthdata-width;t-heightdata-height;t-channel_countdata-channel_count;// 上传到 GPUrenderer_create_texture(data-pixels,t);// 卸载资源 (像素数据已上传到 GPU)resource_system_unload(image_resource);returntrue;}材质系统同样可以使用资源系统:// engine/src/systems/material_system.c (修改后)material*material_system_acquire(constchar*material_name){// 使用资源系统加载材质配置resource material_resource;if(!resource_system_load(material_name,RESOURCE_TYPE_MATERIAL,material_resource)){KERROR(Failed to load material %s,material_name);return0;}material_config*config(material_config*)material_resource.data;// 创建材质material*mcreate_material(config);// 卸载配置资源resource_system_unload(material_resource);returnm;}⚙️ 自定义加载器开发者可以注册自定义加载器以支持新的资源类型:// 示例:音频加载器typedefstructaudio_resource_data{u32 sample_rate;u32 channel_count;u32 sample_count;f32*samples;}audio_resource_data;staticb8audio_loader_load(resource_loader*self,constchar*name,resource*out_resource){// 构建路径charfull_path[512];string_format(full_path,%s%s%s,self-type_path,name,.wav);// 打开文件file_handle f;if(!filesystem_open(full_path,FILE_MODE_READ,true,f)){KERROR(audio_loader_load - Failed to open file: %s,full_path);returnfalse;}// 解析 WAV 文件头// ... (解析 RIFF, fmt, data chunks)audio_resource_data*audio_datakallocate(sizeof(audio_resource_data),MEMORY_TAG_AUDIO);// 读取音频数据// ...filesystem_close(f);// 填充 resourceout_resource-full_pathstring_duplicate(full_path);out_resource-namename;out_resource-dataaudio_data;out_resource-data_sizeaudio_data-sample_count*sizeof(f32)*audio_data-channel_count;out_resource-loader_idself-id;returntrue;}staticvoidaudio_loader_unload(resource_loader*self,resource*resource){if(resource){if(resource-data){audio_resource_data*data(audio_resource_data*)resource-data;if(data-samples){kfree(data-samples,resource-data_size,MEMORY_TAG_AUDIO);}kfree(data,sizeof(audio_resource_data),MEMORY_TAG_AUDIO);}if(resource-full_path){u32 lengthstring_length(resource-full_path);kfree(resource-full_path,length1,MEMORY_TAG_STRING);}kzero_memory(resource,sizeof(resource));}}// 注册音频加载器voidregister_audio_loader(){resource_loader audio_loader;audio_loader.typeRESOURCE_TYPE_CUSTOM;audio_loader.custom_typeaudio;audio_loader.type_pathassets/audio/;audio_loader.loadaudio_loader_load;audio_loader.unloadaudio_loader_unload;if(resource_system_register_loader(audio_loader)){KINFO(Audio loader registered successfully);}}// 使用音频加载器resource audio_resource;if(resource_system_load(background_music,RESOURCE_TYPE_CUSTOM,audio_resource)){audio_resource_data*audio(audio_resource_data*)audio_resource.data;KINFO(Loaded audio: %d Hz, %d channels, %d samples,audio-sample_rate,audio-channel_count,audio-sample_count);// 播放音频audio_system_play(audio);// 卸载resource_system_unload(audio_resource);}❓ 常见问题1. 为什么需要资源系统?直接在各个系统里加载文件不行吗?问题:代码重复:每个系统都要实现文件读取、路径处理难以维护:修改文件格式需要改多处不一致:错误处理、日志输出不统一难以扩展:添加新类型需要修改多个系统资源系统的优势:统一接口:所有资源通过resource_system_load()加载可插拔:新增类型只需注册新加载器易于测试:可以 mock 加载器进行单元测试统一管理:所有资源生命周期在一处管理没有资源系统: ┌────────────┐ ┌────────────┐ ┌────────────┐ │ System A │ │ System B │ │ System C │ │ load_A() │ │ load_B() │ │ load_C() │ └─────┬──────┘ └─────┬──────┘ └─────┬──────┘ │ │ │ └───────────────┴───────────────┘ 重复的文件操作代码 有资源系统: ┌────────────┐ ┌────────────┐ ┌────────────┐ │ System A │ │ System B │ │ System C │ └─────┬──────┘ └─────┬──────┘ └─────┬──────┘ │ │ │ └───────────────┴───────────────┘ │ ┌──────────▼──────────┐ │ Resource System │ │ 统一的加载接口 │ └─────────────────────┘2. resource_loader 的 id 和 type 有什么区别?区别:type (resource_type): 资源的类型,是枚举值RESOURCE_TYPE_TEXT- 文本RESOURCE_TYPE_IMAGE- 图像RESOURCE_TYPE_MATERIAL- 材质用于查找加载器(根据类型找到对应加载器)id (u32): 加载器的实例 ID,是唯一标识在注册时自动分配 (数组索引)用于反向查找(卸载时根据 ID 找到加载器)类型 vs ID: ┌──────────────────────────────────┐ │ registered_loaders 数组 │ ├──────────────────────────────────┤ │ [0] id0, typeRESOURCE_TYPE_TEXT │ ← ID 是数组索引 │ [1] id1, typeRESOURCE_TYPE_BINARY │ Type 是资源类型 │ [2] id2, typeRESOURCE_TYPE_IMAGE │ │ [3] id3, typeRESOURCE_TYPE_MATERIAL │ │ [4] idINVALID_ID (未使用) │ └──────────────────────────────────┘ 加载流程: 1. 用户调用: resource_system_load(test, RESOURCE_TYPE_IMAGE, ...) 2. 遍历数组,找到 type RESOURCE_TYPE_IMAGE 的加载器 3. 调用 loader-load() 4. 保存 loader_id 到 resource-loader_id 卸载流程: 1. 用户调用: resource_system_unload(resource) 2. 根据 resource-loader_id 直接访问数组 [loader_id] 3. 调用 loader-unload()3. 自定义加载器如何设置 custom_type?使用 custom_type 的场景:当你需要加载引擎预定义类型之外的资源时,使用RESOURCE_TYPE_CUSTOMcustom_type:// 音频加载器resource_loader audio_loader;audio_loader.typeRESOURCE_TYPE_CUSTOM;// 自定义类型audio_loader.custom_typeaudio;// 自定义类型名称audio_loader.type_pathassets/audio/;// 场景加载器resource_loader scene_loader;scene_loader.typeRESOURCE_TYPE_CUSTOM;scene_loader.custom_typescene;// 不同的自定义类型scene_loader.type_pathassets/scenes/;// 字体加载器resource_loader font_loader;font_loader.typeRESOURCE_TYPE_CUSTOM;font_loader.custom_typefont;font_loader.type_pathassets/fonts/;查找自定义加载器:resource_loader*find_custom_loader(constchar*custom_type){for(u32 i0;istate_ptr-config.max_loader_count;i){resource_loader*loaderstate_ptr-registered_loaders[i];if(loader-id!INVALID_IDloader-typeRESOURCE_TYPE_CUSTOMstrings_equal(loader-custom_type,custom_type)){returnloader;}}return0;}为什么不直接添加新的 resource_type 枚举值?因为resource_type是引擎核心枚举,添加新值需要修改引擎代码。使用custom_type可以在不修改引擎的情况下扩展新类型。4. 为什么图像加载器返回的是 image_resource_data,而不是直接返回 texture?分层设计:资源系统负责文件到内存的转换,而不涉及 GPU 资源:文件系统层: 磁盘上的文件 (test.png) │ ▼ 资源系统层: 内存中的数据 (image_resource_data) - width, height, channel_count - pixels (CPU 内存) │ ▼ 渲染系统层: GPU 资源 (texture) - VkImage - VkImageView - VkSampler职责分离:资源系统: 只负责加载数据读取文件解码格式 (PNG → 像素数组)返回 CPU 内存中的数据纹理系统: 负责GPU 资源管理上传像素数据到 GPU创建 VkImage、VkImageView管理纹理生命周期// 正确的使用方式:// 1. 资源系统加载图像数据resource image_resource;resource_system_load(test.png,RESOURCE_TYPE_IMAGE,image_resource);image_resource_data*data(image_resource_data*)image_resource.data;// 2. 纹理系统使用数据创建 GPU 纹理texture*ttexture_system_acquire(test);renderer_create_texture(data-pixels,t);// 上传到 GPU// 3. 卸载 CPU 数据 (GPU 已有副本)resource_system_unload(image_resource);// 4. 后续使用纹理 (从 GPU 读取)renderer_bind_texture(t);优势:资源系统不依赖渲染 API (可以换 OpenGL/DirectX)可以加载图像用于非渲染目的 (如 CPU 图像处理)测试更容易 (不需要初始化 GPU)5. 资源系统会缓存资源吗?当前实现不缓存:资源系统只负责加载和卸载,不负责缓存和引用计数:// 每次调用都会重新加载resource res1,res2;resource_system_load(test.png,RESOURCE_TYPE_IMAGE,res1);// 从磁盘加载resource_system_load(test.png,RESOURCE_TYPE_IMAGE,res2);// 再次从磁盘加载// 两次独立的内存res1.data!res2.data// 需要分别卸载resource_system_unload(res1);resource_system_unload(res2);缓存由上层系统负责:// 纹理系统缓存纹理texture*t1texture_system_acquire(test);// 加载texture*t2texture_system_acquire(test);// 返回缓存t1t2// 同一个指针// 引用计数texture_system_release(test);// ref_count--texture_system_release(test);// ref_count-- → 卸载为什么不在资源系统缓存?职责单一: 资源系统只做加载/卸载灵活性: 不同资源类型有不同的缓存策略纹理: 长期缓存 (GPU 内存贵)配置文件: 不缓存 (支持热重载)音频: 短期缓存 (磁盘 I/O 慢)引用计数: 由专门的系统管理更合适架构: ┌──────────────────┐ │ Texture System │ ← 缓存、引用计数、GPU 资源 ├──────────────────┤ │ Material System │ ← 缓存、引用计数 ├──────────────────┤ │ Resource System │ ← 只负责加载/卸载 └──────────────────┘ 练习练习 1: 实现 JSON 加载器任务:实现一个 JSON 文件加载器,返回解析后的 JSON 对象。// json_loader.ctypedefstructjson_object{// 使用 cJSON 或自定义 JSON 解析器void*root;// cJSON* root}json_object;staticb8json_loader_load(resource_loader*self,constchar*name,resource*out_resource){// 1. 构建路径: assets/config/{name}.json// 2. 读取文件内容// 3. 使用 cJSON_Parse() 解析// 4. 填充 out_resource// TODO: 实现returntrue;}staticvoidjson_loader_unload(resource_loader*self,resource*resource){// 1. 调用 cJSON_Delete() 释放 JSON 对象// 2. 释放路径字符串// TODO: 实现}使用:resource json_res;if(resource_system_load(config,RESOURCE_TYPE_CUSTOM,json_res)){json_object*json(json_object*)json_res.data;// 读取配置cJSON*root(cJSON*)json-root;constchar*titlecJSON_GetObjectItem(root,title)-valuestring;intwidthcJSON_GetObjectItem(root,width)-valueint;resource_system_unload(json_res);}练习 2: 实现资源缓存任务:为资源系统添加缓存功能,避免重复加载。// resource_system.ctypedefstructcached_resource{charname[256];resource_type type;resource resource;u32 ref_count;}cached_resource;typedefstructresource_system_state{resource_system_config config;resource_loader registered_loaders[MAX_LOADER_COUNT];// 缓存cached_resource*cache;u32 cache_count;u32 cache_capacity;}resource_system_state;b8resource_system_load(constchar*name,resource_type type,resource*out_resource){// 1. 检查缓存for(u32 i0;istate_ptr-cache_count;i){cached_resource*cachedstate_ptr-cache[i];if(cached-typetypestrings_equal(cached-name,name)){// 命中缓存cached-ref_count;*out_resourcecached-resource;KINFO(Cache hit for %s (ref_count%d),name,cached-ref_count);returntrue;}}// 2. 未命中,加载资源resource_loader*loaderfind_loader_for_type(type);if(!loader-load(loader,name,out_resource)){returnfalse;}// 3. 添加到缓存if(state_ptr-cache_countstate_ptr-cache_capacity){// 扩展缓存数组// ...}cached_resource*cachedstate_ptr-cache[state_ptr-cache_count];string_ncopy(cached-name,name,256);cached-typetype;cached-resource*out_resource;cached-ref_count1;KINFO(Cached resource %s,name);returntrue;}voidresource_system_unload(resource*resource){// 1. 查找缓存条目for(u32 i0;istate_ptr-cache_count;i){cached_resource*cachedstate_ptr-cache[i];if(cached-resource.dataresource-data){// 2. 减少引用计数cached-ref_count--;KINFO(Released %s (ref_count%d),cached-name,cached-ref_count);// 3. 引用计数为 0 时真正卸载if(cached-ref_count0){resource_loader*loaderstate_ptr-registered_loaders[resource-loader_id];loader-unload(loader,cached-resource);// 从缓存移除 (交换到末尾再 pop)cached_resource tempstate_ptr-cache[state_ptr-cache_count-1];state_ptr-cache[i]temp;state_ptr-cache_count--;KINFO(Unloaded resource %s,cached-name);}return;}}}练习 3: 实现异步加载任务:实现异步资源加载,避免阻塞主线程。// resource_system.htypedefvoid(*resource_loaded_callback)(resource*resource,void*user_data);/** * brief 异步加载资源 * param name 资源名称 * param type 资源类型 * param callback 加载完成回调 * param user_data 用户数据 * return 异步任务 ID */u32resource_system_load_async(constchar*name,resource_type type,resource_loaded_callback callback,void*user_data);/** * brief 取消异步加载 * param task_id 任务 ID */voidresource_system_cancel_async(u32 task_id);// resource_system.ctypedefstructasync_load_task{u32 id;charname[256];resource_type type;resource_loaded_callback callback;void*user_data;b8 completed;resource result;}async_load_task;// 工作线程函数voidresource_loader_worker_thread(void*arg){while(state_ptr-running){// 1. 从队列获取任务async_load_task*taskpop_task_from_queue();if(!task){// 等待新任务thread_sleep(10);continue;}// 2. 加载资源resource_loader*loaderfind_loader_for_type(task-type);b8 successloader-load(loader,task-name,task-result);// 3. 标记完成task-completedtrue;// 4. 回调将在主线程执行 (通过 resource_system_update)}}// 主线程更新函数voidresource_system_update(){// 处理完成的异步任务for(u32 i0;istate_ptr-async_task_count;i){async_load_task*taskstate_ptr-async_tasks[i];if(task-completed){// 在主线程执行回调task-callback(task-result,task-user_data);// 移除任务remove_task(i);--i;}}}// 使用示例voidon_texture_loaded(resource*resource,void*user_data){texture*t(texture*)user_data;image_resource_data*data(image_resource_data*)resource-data;renderer_create_texture(data-pixels,t);resource_system_unload(resource);KINFO(Texture loaded asynchronously);}// 异步加载纹理texture my_texture;resource_system_load_async(large_texture,RESOURCE_TYPE_IMAGE,on_texture_loaded,my_texture);恭喜!你已经掌握了资源系统的实现!下一教程:034 静态网格加载关注公众号「上手实验室」,获取更多游戏引擎开发教程!
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

搭建租号网的网站个人网站可以做淘宝客

智能体互联网是在传统互联网基础上实现智能体互联互通和任务协作的新型网络架构。其总体架构包含三个互联层面、四种互联关系和一个管理平面。关键技术包括智能体标识发现、转发路由、认证授权和互联协作,以及智能体赋能网络运维和组件。智能体互联网将推动互联网从…

张小明 2025/12/30 4:10:41 网站建设

做美食的网站有那一些wordpress 开发 表单

第一章:为什么顶级团队都在用Open-AutoGLM本地部署?在人工智能快速发展的今天,越来越多的技术团队选择将大模型能力本地化部署。Open-AutoGLM 作为一款支持自动化任务调度与本地推理优化的开源框架,正成为头部研发团队构建私有AI系…

张小明 2025/12/30 12:17:53 网站建设

润滑油 东莞网站建设石家庄微信网站建设公司

还在为QQ音乐下载的加密音频无法在其他播放器正常播放而烦恼吗?🔥 QMCDecode这款专为macOS用户设计的强大工具,让你轻松突破QMC格式限制,实现真正的音频格式自由转换!无论是高品质的无损音乐还是日常欣赏的曲目&#x…

张小明 2025/12/30 21:21:22 网站建设

聋哑工作设计做网站建设手机网站赚钱吗

以成都鼎讯信通科技有限公司的精心打造为代表的CM-K60(敲缆仪)光缆普查仪已成为光纤网络的运维领域的重要的专业利器.。依托于其高精的定位与智能的诊断功能,使其能快速的对光缆的路由进行准确的识别,精准的对故障点的判断&#x…

张小明 2025/12/30 15:12:25 网站建设

三项措施做好门户网站建设网站没权重

还在为复杂的AI模型配置而头疼吗?作为数据科学家的你,是否渴望在熟悉的Jupyter环境中直接调用AI能力?这个强大的AI助手插件正是为你量身定制。今天,我将带你用五分钟时间,从零开始掌握这个改变工作流的利器。 【免费下…

张小明 2025/12/30 14:55:48 网站建设

比较好的网站建设网站开发界面设计

在知识变现行业,“AI 焦虑” 与 “落地无效” 形成诡异的双重困境:创始人花重金让团队学习 AI 提示词、操作技巧,最终却只有少数人能熟练使用;引入多款 AI 工具,却因流程割裂、场景适配差,沦为 “演示道具”…

张小明 2025/12/30 22:51:03 网站建设