#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef _DEBUG #include #endif//_DEBUG #include #include #include #include #include //#include #include #include #include using namespace hgl; using namespace hgl::io; using namespace hgl::graph; namespace hgl{namespace graph { bool InitShaderCompiler(); void CloseShaderCompiler(); }}//namespace hgl::graph class VulkanApplicationFramework:WindowEvent { protected: Window * win =nullptr; VulkanInstance * inst =nullptr; protected: GPUDevice * device =nullptr; RenderPass * device_render_pass =nullptr; RTSwapchain * sc_render_target =nullptr; protected: int32_t swap_chain_count =0; RenderCmdBuffer ** cmd_buf =nullptr; Color4f clear_color; protected: RenderResource * db =nullptr; protected: ViewportInfo vp_info; DeviceBuffer * ubo_vp_info =nullptr; public: virtual void BindRenderResource(RenderResource *rr) { if(!rr) return; rr->static_descriptor.AddUBO(mtl::SBS_ViewportInfo.name,ubo_vp_info); } virtual ~VulkanApplicationFramework() { CloseShaderCompiler(); win->Unjoin(this); SAFE_CLEAR(db); SAFE_CLEAR_OBJECT_ARRAY_OBJECT(cmd_buf,swap_chain_count); SAFE_CLEAR(device); SAFE_CLEAR(win); SAFE_CLEAR(inst); } virtual bool Init(uint w,uint h) { logger::InitLogger(OS_TEXT("VulkanTest")); if(!InitShaderCompiler()) return(false); SetClearColor(COLOR::MozillaCharcoal); #ifdef _DEBUG if(!CheckStrideBytesByFormat()) return(false); #endif// InitNativeWindowSystem(); InitVulkanInstanceProperties(); win=CreateRenderWindow(OS_TEXT("VulkanTest")); if(!win) return(false); if(!win->Create(w,h)) return(false); { CreateInstanceLayerInfo cili; hgl_zero(cili); cili.lunarg.standard_validation = true; cili.khronos.validation = true; inst=CreateInstance("VulkanTest",nullptr,&cili); if(!inst) return(false); } { VulkanHardwareRequirement vh_req; vh_req.wideLines=VulkanHardwareRequirement::SupportLevel::Want; device=CreateRenderDevice(inst,win,&vh_req); if(!device) return(false); } device_render_pass=device->GetRenderPass(); db=new RenderResource(device); InitCommandBuffer(); win->Join(this); { vp_info.Set(w,h); ubo_vp_info=db->CreateUBO("Viewport",sizeof(ViewportInfo),&vp_info); } BindRenderResource(db); return(true); } virtual void Resize(uint w,uint h) { vp_info.Set(w,h); ubo_vp_info->Write(&vp_info); } ViewportInfo *GetViewportInfo() { return &vp_info; } DeviceBuffer *GetViewportInfoBuffer() { return ubo_vp_info; } void SetClearColor(const Color4f &cc) { clear_color=cc; } void SetClearColor(const enum class COLOR &ce) { clear_color=GetColor4f(ce,1.0f); } void OnResize(uint w,uint h) override { if(w>0&&h>0) device->Resize(w,h); InitCommandBuffer(); Resize(w,h); } void InitCommandBuffer() { if(cmd_buf) SAFE_CLEAR_OBJECT_ARRAY_OBJECT(cmd_buf,swap_chain_count); sc_render_target=device->GetSwapchainRT(); swap_chain_count=sc_render_target->GetImageCount(); { const VkExtent2D extent=sc_render_target->GetExtent(); cmd_buf=hgl_zero_new(swap_chain_count); for(int32_t i=0;iCreateRenderCommandBuffer(device->GetPhysicalDevice()->GetDeviceName()+AnsiString(":RenderCmdBuffer_")+AnsiString::numberOf(i)); } } bool BuildCommandBuffer(RenderCmdBuffer *cb,RenderPass *rp,Framebuffer *fb,Renderable *ri) { if(!ri)return(false); cb->Begin(); cb->BindFramebuffer(rp,fb); cb->SetClearColor(0,clear_color); cb->BeginRenderPass(); cb->BindPipeline(ri->GetPipeline()); cb->BindDescriptorSets(ri->GetMaterial()); cb->BindDataBuffer(ri->GetDataBuffer()); cb->Draw(ri->GetDataBuffer(),ri->GetRenderData()); cb->EndRenderPass(); cb->End(); return(true); } void BuildCommandBuffer(RenderCmdBuffer *cb,RenderTarget *rt,Renderable *ri) { if(!cb||!rt||!ri) return; BuildCommandBuffer(cb,rt->GetRenderPass(),rt->GetFramebuffer(),ri); } bool BuildCommandBuffer(uint32_t index,Renderable *ri) { if(!ri)return(false); return BuildCommandBuffer(cmd_buf[index],sc_render_target->GetRenderPass(),sc_render_target->GetFramebuffer(index),ri); } bool BuildCommandBuffer(Renderable *ri) { if(!ri)return(false); for(int32_t i=0;iGetCurrentFrameIndices(),ri); } void BuildCommandBuffer(uint32_t index,RenderList *rl) { if(!rl)return; RenderCmdBuffer *cb=cmd_buf[index]; cb->Begin(); cb->BindFramebuffer(sc_render_target->GetRenderPass(),sc_render_target->GetFramebuffer(index)); cb->SetClearColor(0,clear_color); cb->BeginRenderPass(); rl->Render(cb); cb->EndRenderPass(); cb->End(); } void BuildCommandBuffer(RenderList *rl) { for(int32_t i=0;iGetCurrentFrameIndices(),rl); } template Pipeline *CreatePipeline(ARGS...args) { Pipeline *p=device_render_pass->CreatePipeline(args...); if(!p) return(nullptr); #ifdef _DEBUG DebugUtils *du=device->GetDebugUtils(); if(du) du->SetPipeline(*p,"Pipeline:"+p->GetName()); #endif//_DEBUG return p; } public: int AcquireNextImage() { return sc_render_target->AcquireNextImage(); } virtual void SubmitDraw(int index) { VkCommandBuffer cb=*cmd_buf[index]; sc_render_target->Submit(cb); sc_render_target->PresentBackbuffer(); sc_render_target->WaitQueue(); sc_render_target->WaitFence(); } virtual void Draw() { int index=AcquireNextImage(); if(index<0||index>=swap_chain_count)return; SubmitDraw(index); } bool Run() { if(!win->Update())return(false); if(win->IsVisible()) Draw(); device->WaitIdle(); return(true); } };//class VulkanApplicationFramework class CameraKeyboardControl:public KeyboardStateEvent { FirstPersonCameraControl *camera; float move_speed; public: CameraKeyboardControl(FirstPersonCameraControl *wc) { camera=wc; move_speed=1.0f; } bool OnPressed(const KeyboardButton &kb)override { if(!KeyboardStateEvent::OnPressed(kb)) return(false); if(kb==KeyboardButton::Minus )move_speed*=0.9f;else if(kb==KeyboardButton::Equals )move_speed*=1.1f; return(true); } void Update() { if(HasPressed(KeyboardButton::W ))camera->Forward (move_speed);else if(HasPressed(KeyboardButton::S ))camera->Backward (move_speed);else if(HasPressed(KeyboardButton::A ))camera->Left (move_speed);else if(HasPressed(KeyboardButton::D ))camera->Right (move_speed);else //if(HasPressed(KeyboardButton::R ))camera->Up (move_speed);else //if(HasPressed(KeyboardButton::F ))camera->Down (move_speed);else //if(HasPressed(KeyboardButton::Left ))camera->HoriRotate( move_speed);else //if(HasPressed(KeyboardButton::Right ))camera->HoriRotate(-move_speed);else //if(HasPressed(KeyboardButton::Up ))camera->VertRotate( move_speed);else //if(HasPressed(KeyboardButton::Down ))camera->VertRotate(-move_speed);else return; } }; class CameraMouseControl:public MouseEvent { FirstPersonCameraControl *camera; double cur_time; double last_time; Vector2f mouse_pos; Vector2f mouse_last_pos; protected: bool OnPressed(int x,int y,MouseButton) override { mouse_last_pos.x=x; mouse_last_pos.y=y; last_time=cur_time; return(true); } bool OnWheel(int,int y) override { if(y==0)return(false); camera->Forward(float(y)/10.0f); return(true); } bool OnMove(int x,int y) override { mouse_pos.x=x; mouse_pos.y=y; bool left=HasPressed(MouseButton::Left); bool right=HasPressed(MouseButton::Right); Vector2f pos(x,y); Vector2f gap=pos-mouse_last_pos; if(left) { gap/=-5.0f; camera->Rotate(gap); } else if(right) { gap/=10.0f; camera->Move(Vector3f(gap.x,0,gap.y)); } last_time=cur_time; mouse_last_pos=Vector2f(x,y); return(true); } public: CameraMouseControl(FirstPersonCameraControl *wc) { camera=wc; cur_time=0; last_time=0; } const Vector2f &GetMouseCoord()const{return mouse_pos;} void Update() { cur_time=GetDoubleTime(); } }; class CameraAppFramework:public VulkanApplicationFramework { protected: Camera * camera =nullptr; DeviceBuffer * ubo_camera_info =nullptr; FirstPersonCameraControl *camera_control=nullptr; CameraKeyboardControl * ckc=nullptr; CameraMouseControl * cmc=nullptr; const Vector2f &GetMouseCoord()const{return cmc->GetMouseCoord();} public: virtual void BindRenderResource(RenderResource *rr) override { if(!rr)return; VulkanApplicationFramework::BindRenderResource(rr); rr->global_descriptor.AddUBO(mtl::SBS_CameraInfo.name,ubo_camera_info); } virtual ~CameraAppFramework() { SAFE_CLEAR(ckc); SAFE_CLEAR(cmc); SAFE_CLEAR(camera); } virtual bool Init(uint w,uint h) override { if(!VulkanApplicationFramework::Init(w,h)) return(false); InitCamera(w,h); BindRenderResource(db); return(true); } virtual void InitCamera(int w,int h) { camera=new Camera; camera->pos=Vector3f(10,10,10); camera_control=new FirstPersonCameraControl(&vp_info,camera); camera_control->Refresh(); //更新矩阵计算 ckc=new CameraKeyboardControl(camera_control); cmc=new CameraMouseControl(camera_control); win->Join(ckc); win->Join(cmc); RefreshCameraInfo(camera_control->GetCameraInfo(),&vp_info,camera); ubo_camera_info=db->CreateUBO("CameraInfo",sizeof(CameraInfo),camera_control->GetCameraInfo()); } void Resize(uint w,uint h)override { vp_info.Set(w,h); camera_control->Refresh(); ubo_camera_info->Write(camera_control->GetCameraInfo()); } CameraInfo *GetCameraInfo() { return camera_control->GetCameraInfo(); } DeviceBuffer *GetCameraInfoBuffer() { return ubo_camera_info; } virtual void BuildCommandBuffer(uint32_t index)=0; virtual void Draw()override { camera_control->Refresh(); //更新相机矩阵 ubo_camera_info->Write(camera_control->GetCameraInfo()); //写入缓冲区 const uint32_t index=AcquireNextImage(); BuildCommandBuffer(index); SubmitDraw(index); ckc->Update(); cmc->Update(); } };//class CameraAppFramework class SceneAppFramework:public CameraAppFramework { protected: SceneNode render_root; RenderList * render_list =nullptr; public: SceneAppFramework()=default; virtual ~SceneAppFramework() { SAFE_CLEAR(render_list); } virtual bool Init(uint width,uint height) override { if(!CameraAppFramework::Init(width,height)) return(false); render_list=new RenderList(device); return(true); } virtual void BuildCommandBuffer(uint32 index) override { VulkanApplicationFramework::BuildCommandBuffer(index,render_list); } virtual void Resize(uint w,uint h) override { CameraAppFramework::Resize(w,h); VulkanApplicationFramework::BuildCommandBuffer(render_list); } };//class SceneAppFramework:public CameraAppFramework template int RunApp(uint w,uint h) { T app; if(!app.Init(w,h)) return(-1); while(app.Run()); return 0; }