int main() { //////////////////// // ionEngine Init // //////////////////// Log::AddDefaultOutputs(); SingletonPointer<CGraphicsAPI> GraphicsAPI; SingletonPointer<CWindowManager> WindowManager; SingletonPointer<CTimeManager> TimeManager; SingletonPointer<CSceneManager> SceneManager; SingletonPointer<CAssetManager> AssetManager; SingletonPointer<CGUIManager> GUIManager; GraphicsAPI->Init(new COpenGLImplementation()); WindowManager->Init(GraphicsAPI); TimeManager->Init(WindowManager); SceneManager->Init(GraphicsAPI); AssetManager->Init(GraphicsAPI); CWindow * Window = WindowManager->CreateWindow(vec2i(1920, 1080), "Shadow Maps", EWindowType::Windowed); GUIManager->Init(Window); Window->AddListener(GUIManager); AssetManager->AddAssetPath("Assets/"); AssetManager->SetShaderPath("Shaders/"); AssetManager->SetTexturePath("Images/"); SharedPointer<IGraphicsContext> Context = GraphicsAPI->GetWindowContext(Window); SharedPointer<IRenderTarget> BackBuffer = Context->GetBackBuffer(); BackBuffer->SetClearColor(color3f(0.3f)); SharedPointer<IFrameBuffer> ShadowBuffer = Context->CreateFrameBuffer(); SharedPointer<ITexture2D> ShadowTexture = GraphicsAPI->CreateTexture2D(vec2i(4096), ITexture::EMipMaps::False, ITexture::EFormatComponents::RGBA, ITexture::EInternalFormatType::Fix8); SharedPointer<ITexture2D> ShadowDepth = GraphicsAPI->CreateTexture2D(vec2i(4096), ITexture::EMipMaps::False, ITexture::EFormatComponents::R, ITexture::EInternalFormatType::Depth); ShadowBuffer->AttachColorTexture(ShadowTexture, 0); ShadowBuffer->AttachDepthTexture(ShadowDepth); if (! ShadowBuffer->CheckCorrectness()) { Log::Error("Frame buffer not valid!"); } ///////////////// // Load Assets // ///////////////// CSimpleMesh * SphereMesh = CGeometryCreator::CreateSphere(); CSimpleMesh * PlaneMesh = CGeometryCreator::CreatePlane(vec2f(100.f)); CSimpleMesh * CubeMesh = CGeometryCreator::CreateCube(); SharedPointer<IShader> DiffuseShader = AssetManager->LoadShader("Diffuse"); SharedPointer<IShader> ColorShader = AssetManager->LoadShader("Color"); SharedPointer<IShader> QuadCopyShader = AssetManager->LoadShader("QuadCopy"); //////////////////// // ionScene Setup // //////////////////// CRenderPass * ShadowPass = new CRenderPass(Context); ShadowPass->SetRenderTarget(ShadowBuffer); SceneManager->AddRenderPass(ShadowPass); CRenderPass * ColorPass = new CRenderPass(Context); ColorPass->SetRenderTarget(BackBuffer); SceneManager->AddRenderPass(ColorPass); CRenderPass * PostProcess = new CRenderPass(Context); PostProcess->SetRenderTarget(BackBuffer); SceneManager->AddRenderPass(PostProcess); CPerspectiveCamera * Camera = new CPerspectiveCamera(Window->GetAspectRatio()); Camera->SetPosition(vec3f(15.25f, 7.3f, -11.85f)); Camera->SetFocalLength(0.4f); Camera->SetFarPlane(1000.f); ColorPass->SetActiveCamera(Camera); CCameraController * Controller = new CCameraController(Camera); Controller->SetTheta(2.347f); Controller->SetPhi(-0.326f); Window->AddListener(Controller); TimeManager->MakeUpdateTick(0.02)->AddListener(Controller); COrthographicCamera * LightCamera = new COrthographicCamera(-1, 1, -1, 1); ShadowPass->SetActiveCamera(LightCamera); ///////////////// // Add Objects // ///////////////// CSimpleMeshSceneObject * Sphere1 = new CSimpleMeshSceneObject(); Sphere1->SetMesh(SphereMesh); Sphere1->SetShader(DiffuseShader); Sphere1->SetPosition(vec3f(0, 1, 0)); Sphere1->SetScale(2.f); ColorPass->AddSceneObject(Sphere1); ShadowPass->AddSceneObject(Sphere1); CSimpleMeshSceneObject * Sphere2 = new CSimpleMeshSceneObject(); Sphere2->SetMesh(SphereMesh); Sphere2->SetShader(DiffuseShader); Sphere2->SetPosition(vec3f(4, 4, 0)); Sphere2->SetScale(3.f); Sphere2->GetMaterial().Ambient *= Color::Basic::Yellow; Sphere2->GetMaterial().Diffuse *= Color::Basic::Yellow; ColorPass->AddSceneObject(Sphere2); ShadowPass->AddSceneObject(Sphere2); CSimpleMeshSceneObject * Sphere3 = new CSimpleMeshSceneObject(); Sphere3->SetMesh(SphereMesh); Sphere3->SetShader(DiffuseShader); Sphere3->SetPosition(vec3f(12, 2, 0)); Sphere3->SetScale(4.f); ColorPass->AddSceneObject(Sphere3); ShadowPass->AddSceneObject(Sphere3); CSimpleMeshSceneObject * Sphere4 = new CSimpleMeshSceneObject(); Sphere4->SetMesh(SphereMesh); Sphere4->SetShader(DiffuseShader); Sphere4->SetPosition(vec3f(3, 4, 6)); Sphere4->GetMaterial().Ambient *= Color::Basic::Red; Sphere4->GetMaterial().Diffuse *= Color::Basic::Red; ColorPass->AddSceneObject(Sphere4); ShadowPass->AddSceneObject(Sphere4); CSimpleMeshSceneObject * Cube1 = new CSimpleMeshSceneObject(); Cube1->SetMesh(CubeMesh); Cube1->SetShader(DiffuseShader); Cube1->SetPosition(vec3f(-4, 4, 0)); Cube1->SetScale(3.f); Cube1->GetMaterial().Ambient *= Color::Basic::Cyan; Cube1->GetMaterial().Diffuse *= Color::Basic::Cyan; ColorPass->AddSceneObject(Cube1); ShadowPass->AddSceneObject(Cube1); CSimpleMeshSceneObject * Cube2 = new CSimpleMeshSceneObject(); Cube2->SetMesh(CubeMesh); Cube2->SetShader(DiffuseShader); Cube2->SetPosition(vec3f(-12, 2, 0)); Cube2->SetScale(4.f); Cube2->GetMaterial().Ambient *= Color::Basic::Blue; Cube2->GetMaterial().Diffuse *= Color::Basic::Blue; ColorPass->AddSceneObject(Cube2); ShadowPass->AddSceneObject(Cube2); CSimpleMeshSceneObject * Plane = new CSimpleMeshSceneObject(); Plane->SetMesh(PlaneMesh); Plane->SetShader(DiffuseShader); Plane->GetMaterial().Ambient *= Color::Basic::Green; Plane->GetMaterial().Diffuse *= Color::Basic::Green; ColorPass->AddSceneObject(Plane); ShadowPass->AddSceneObject(Plane); vector<CSimpleMesh *> Meshes = CGeometryCreator::LoadOBJFile("bunny.obj"); for (auto Mesh : Meshes) { CSimpleMeshSceneObject * PlaneObject = new CSimpleMeshSceneObject(); PlaneObject->SetMesh(Mesh); PlaneObject->SetShader(DiffuseShader); PlaneObject->SetPosition(vec3f(3, -1.f, -6)); PlaneObject->SetScale(vec3f(2.5f)); PlaneObject->SetRotation(vec3f(0, 3.14f / 4.f, 0)); ColorPass->AddSceneObject(PlaneObject); ShadowPass->AddSceneObject(PlaneObject); } CLineSceneObject * Lines = new CLineSceneObject(); Lines->SetShader(ColorShader); ColorPass->AddSceneObject(Lines); CSimpleMeshSceneObject * PostProcessObject = new CSimpleMeshSceneObject(); PostProcessObject->SetMesh(CreateScreenQuad()); PostProcessObject->SetShader(QuadCopyShader); PostProcessObject->SetTexture("uTexture", ShadowDepth); PostProcess->AddSceneObject(PostProcessObject); CDirectionalLight * Light1 = new CDirectionalLight(); ColorPass->AddLight(Light1); ShadowPass->AddLight(Light1); CSimpleMeshSceneObject * LightSphere = new CSimpleMeshSceneObject(); LightSphere->SetMesh(SphereMesh); LightSphere->SetShader(DiffuseShader); LightSphere->SetScale(0.4f); LightSphere->GetMaterial().Ambient = 1.f / 0.75f; LightSphere->GetMaterial().Diffuse = 0; ColorPass->AddSceneObject(LightSphere); CUniform<bool> uDebugShadows = false; CUniform<float> uShadowBias = 0.005f; CUniform<glm::mat4> uLightMatrix; ColorPass->SetUniform("uLightMatrix", uLightMatrix); ColorPass->SetUniform("uDebugShadows", uDebugShadows); ColorPass->SetUniform("uShadowBias", uShadowBias); ColorPass->SetTexture("uShadowMap", ShadowDepth); // Obviously the shadow pass does not need these, but this will suppress warnings // An object that supports different shaders for different passes is needed ShadowPass->SetUniform("uLightMatrix", uLightMatrix); ShadowPass->SetUniform("uDebugShadows", uDebugShadows); ShadowPass->SetUniform("uShadowBias", uShadowBias); ShadowPass->SetTexture("uShadowMap", ShadowDepth); /////////////// // Main Loop // /////////////// vec3f LightDirection = Normalize( vec3f(2, -12, 2) ); float LightViewSize = 20.f; float LightNear = 1.f; float LightFar = 30.f; float LightDistance = 15.f; TimeManager->Init(WindowManager); while (WindowManager->Run()) { TimeManager->Update(); PostProcessObject->SetVisible(Window->IsKeyDown(EKey::F1)); GUIManager->NewFrame(); ImGui::SetNextWindowPos(ImVec2(10, 10), ImGuiSetCond_Once); ImGui::SetNextWindowSize(ImVec2(400, 300), ImGuiSetCond_Once); if (ImGui::Begin("Settings")) { ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); ImGui::Text("Camera position: %.3f %.3f %.3f", Camera->GetPosition().X, Camera->GetPosition().Y, Camera->GetPosition().Z); ImGui::Text("Camera rotation: %.3f %.3f", Controller->GetTheta(), Controller->GetPhi()); ImGui::Separator(); ImGui::SliderFloat("Light Camera Size", &LightViewSize, 1.f, 200.f); ImGui::SliderFloat("Light Near Plane", &LightNear, 1.f, 300.f); ImGui::SliderFloat("Light Far Plane", &LightFar, 1.f, 600.f); ImGui::SliderFloat("Light Camera Distance", &LightDistance, 1.f, 200.f); ImGui::Text("Light Position: %.3f %.3f %.3f", LightCamera->GetPosition().X, LightCamera->GetPosition().Y, LightCamera->GetPosition().Z); ImGui::Separator(); ImGui::Checkbox("Debug Shadows", &uDebugShadows.Get()); ImGui::SliderFloat("Shadow Bias", &uShadowBias.Get(), 0.0f, 0.5f, "%.6f", 2.f); } ImGui::End(); ImGui::SetNextWindowPos(vec2f(600, 10), ImGuiSetCond_Once); ImGui::SetNextWindowSize(vec2f(300), ImGuiSetCond_Once); if (ImGui::Begin("Shadow Map")) { vec2f const AvailableSpace = ImGui::GetContentRegionAvail(); ImGui::Image(GUIManager->GetTextureID(ShadowDepth), AvailableSpace); } ImGui::End(); Light1->SetDirection(LightDirection); LightSphere->SetPosition(LightDirection * LightDistance); LightCamera->SetLeft(-LightViewSize); LightCamera->SetRight(LightViewSize); LightCamera->SetBottom(-LightViewSize); LightCamera->SetTop(LightViewSize); LightCamera->SetPosition(-LightDirection * LightDistance); LightCamera->SetLookDirection(LightDirection); LightCamera->SetNearPlane(LightNear); LightCamera->SetFarPlane(LightFar); LightCamera->Update(); uLightMatrix = LightCamera->GetProjectionMatrix() * LightCamera->GetViewMatrix(); vec3f const W = - Normalize(LightCamera->GetLookDirecton()); vec3f const U = Normalize(Cross(LightCamera->GetUpVector(), W)); vec3f const V = Cross(W, U); vec3f const P = LightCamera->GetPosition(); vec3f Box[8]; float const BoxSize = LightViewSize; Box[0] = P - U * BoxSize - V * BoxSize - W * LightNear; Box[1] = P + U * BoxSize - V * BoxSize - W * LightNear; Box[2] = P - U * BoxSize + V * BoxSize - W * LightNear; Box[3] = P + U * BoxSize + V * BoxSize - W * LightNear; Box[4] = P - U * BoxSize - V * BoxSize - W * LightFar; Box[5] = P + U * BoxSize - V * BoxSize - W * LightFar; Box[6] = P - U * BoxSize + V * BoxSize - W * LightFar; Box[7] = P + U * BoxSize + V * BoxSize - W * LightFar; Lines->ResetLines(); Lines->AddLine(vec3f(0, 0, 0), P, Color::Basic::Cyan); Lines->AddLine(P, P + U, Color::Basic::Red); Lines->AddLine(P, P + V, Color::Basic::Green); Lines->AddLine(P, P + W, Color::Basic::Blue); Lines->AddLine(Box[0], Box[1], Color::Basic::White); Lines->AddLine(Box[0], Box[2], Color::Basic::White); Lines->AddLine(Box[1], Box[3], Color::Basic::White); Lines->AddLine(Box[2], Box[3], Color::Basic::White); Lines->AddLine(Box[4], Box[5], Color::Basic::White); Lines->AddLine(Box[4], Box[6], Color::Basic::White); Lines->AddLine(Box[5], Box[7], Color::Basic::White); Lines->AddLine(Box[6], Box[7], Color::Basic::White); Lines->AddLine(Box[0], Box[4], Color::Basic::White); Lines->AddLine(Box[1], Box[5], Color::Basic::White); Lines->AddLine(Box[2], Box[6], Color::Basic::White); Lines->AddLine(Box[3], Box[7], Color::Basic::White); //Lines->AddLine(vec3f(0, 0, 0), vec3f(0, 10, 0), Color::Basic::Blue); ShadowBuffer->ClearColorAndDepth(); BackBuffer->ClearColorAndDepth(); SceneManager->DrawAll(); GUIManager->Draw(); Window->SwapBuffers(); } return 0; }
int main() { //////////////////// // ionEngine Init // //////////////////// Log::AddDefaultOutputs(); SingletonPointer<CGraphicsAPI> GraphicsAPI; SingletonPointer<CWindowManager> WindowManager; SingletonPointer<CTimeManager> TimeManager; SingletonPointer<CSceneManager> SceneManager; SingletonPointer<CAssetManager> AssetManager; SingletonPointer<CGUIManager> GUIManager; GraphicsAPI->Init(new Graphics::COpenGLImplementation()); WindowManager->Init(GraphicsAPI); TimeManager->Init(WindowManager); SceneManager->Init(GraphicsAPI); AssetManager->Init(GraphicsAPI); //CWindow * Window = WindowManager->CreateWindow(vec2i(1600, 900), "DemoApplication", EWindowType::Windowed); CWindow * Window = WindowManager->CreateWindowOnMonitor(2, "SSAO"); GUIManager->Init(Window); Window->AddListener(GUIManager); AssetManager->AddAssetPath("Assets/"); AssetManager->SetShaderPath("Shaders/"); AssetManager->SetTexturePath("Images/"); SharedPointer<IGraphicsContext> Context = GraphicsAPI->GetWindowContext(Window); SharedPointer<IRenderTarget> BackBuffer = Context->GetBackBuffer(); BackBuffer->SetClearColor(color3f(0.3f)); SharedPointer<IFrameBuffer> SceneFrameBuffer = Context->CreateFrameBuffer(); SharedPointer<ITexture2D> SceneColor = GraphicsAPI->CreateTexture2D(Window->GetSize(), ITexture::EMipMaps::False, ITexture::EFormatComponents::RGB, ITexture::EInternalFormatType::Fix8); SceneColor->SetMinFilter(ITexture::EFilter::Nearest); SceneColor->SetMagFilter(ITexture::EFilter::Nearest); SceneColor->SetWrapMode(ITexture::EWrapMode::Clamp); SharedPointer<ITexture2D> SceneNormal = GraphicsAPI->CreateTexture2D(Window->GetSize(), ITexture::EMipMaps::False, ITexture::EFormatComponents::RGB, ITexture::EInternalFormatType::Fix8); SceneNormal->SetMinFilter(ITexture::EFilter::Nearest); SceneNormal->SetMagFilter(ITexture::EFilter::Nearest); SceneNormal->SetWrapMode(ITexture::EWrapMode::Clamp); SharedPointer<ITexture2D> SceneDepth = GraphicsAPI->CreateTexture2D(Window->GetSize(), ITexture::EMipMaps::False, ITexture::EFormatComponents::R, ITexture::EInternalFormatType::Depth); SceneFrameBuffer->AttachColorTexture(SceneColor, 0); SceneFrameBuffer->AttachColorTexture(SceneNormal, 1); SceneFrameBuffer->AttachDepthTexture(SceneDepth); if (! SceneFrameBuffer->CheckCorrectness()) { Log::Error("Frame buffer not valid!"); } SharedPointer<IFrameBuffer> PingFrameBuffer = Context->CreateFrameBuffer(); SharedPointer<ITexture2D> PingColor = GraphicsAPI->CreateTexture2D(Window->GetSize(), ITexture::EMipMaps::False, ITexture::EFormatComponents::RGB, ITexture::EInternalFormatType::Fix8); PingColor->SetMinFilter(ITexture::EFilter::Nearest); PingColor->SetMagFilter(ITexture::EFilter::Nearest); PingColor->SetWrapMode(ITexture::EWrapMode::Clamp); PingFrameBuffer->AttachColorTexture(PingColor, 0); if (! PingFrameBuffer->CheckCorrectness()) { Log::Error("Frame buffer not valid!"); } SharedPointer<IFrameBuffer> PongFrameBuffer = Context->CreateFrameBuffer(); SharedPointer<ITexture2D> PongColor = GraphicsAPI->CreateTexture2D(Window->GetSize(), ITexture::EMipMaps::False, ITexture::EFormatComponents::RGB, ITexture::EInternalFormatType::Fix8); PongColor->SetMinFilter(ITexture::EFilter::Nearest); PongColor->SetMagFilter(ITexture::EFilter::Nearest); PongColor->SetWrapMode(ITexture::EWrapMode::Clamp); PongFrameBuffer->AttachColorTexture(PongColor, 0); if (! PongFrameBuffer->CheckCorrectness()) { Log::Error("Frame buffer not valid!"); } ///////////////// // Load Assets // ///////////////// CSimpleMesh * SphereMesh = CGeometryCreator::CreateSphere(); CSimpleMesh * PlaneMesh = CGeometryCreator::CreatePlane(vec2f(100.f)); SharedPointer<IShader> GeometryShader = AssetManager->LoadShader("Geometry"); SharedPointer<IShader> SSAOShader = AssetManager->LoadShader("SSAO"); SharedPointer<IShader> BlurHShader = AssetManager->LoadShader("BlurH"); SharedPointer<IShader> BlurVShader = AssetManager->LoadShader("BlurV"); std::uniform_real_distribution<float> randomFloats(0.0, 1.0); // generates random floats between 0.0 and 1.0 std::default_random_engine generator; // Sample kernel int const numSamples = 64; std::vector<vec3f> ssaoKernel; for (uint i = 0; i < numSamples; ++i) { float const VerticalBias = 0.1f; bool random = true; int const sampleRegionWidth = (int) sqrt((float) numSamples); float const a = random ? randomFloats(generator) : (float) (i / sampleRegionWidth) / (float) (sampleRegionWidth - 1); float const b = random ? randomFloats(generator) : (float) (i % sampleRegionWidth) / (float) (sampleRegionWidth - 1); float const c = random ? randomFloats(generator) : (float) (i % 3) / 2.f; vec3f sample = vec3f(a * 2 - 1, b * 2 - 1, c * (1.f - VerticalBias) + VerticalBias); sample.Normalize(); sample *= randomFloats(generator); float scale = float(i) / numSamples; // Scale samples s.t. they're more aligned to center of kernel scale = lerp(0.1f, 1.0f, scale * scale); sample *= scale; ssaoKernel.push_back(sample); } // Noise texture std::vector<float> NoiseData; uint const NoiseTexSize = 4; for (uint i = 0; i < NoiseTexSize * NoiseTexSize; i++) { NoiseData.push_back(randomFloats(generator) * 2 - 1); NoiseData.push_back(randomFloats(generator) * 2 - 1); NoiseData.push_back(0.0); } SharedPointer<ITexture2D> SSAONoise = GraphicsAPI->CreateTexture2D(vec2i(NoiseTexSize), ITexture::EMipMaps::False, ITexture::EFormatComponents::RGB, ITexture::EInternalFormatType::Float16); SSAONoise->Upload(NoiseData.data(), vec2i(NoiseTexSize), ITexture::EFormatComponents::RGB, EScalarType::Float); SSAONoise->SetMinFilter(ITexture::EFilter::Nearest); SSAONoise->SetMagFilter(ITexture::EFilter::Nearest); //////////////////// // ionScene Setup // //////////////////// CRenderPass * RenderPass = new CRenderPass(Context); RenderPass->SetRenderTarget(SceneFrameBuffer); SceneManager->AddRenderPass(RenderPass); CRenderPass * SSAOPass = new CRenderPass(Context); SSAOPass->SetRenderTarget(PingFrameBuffer); SceneManager->AddRenderPass(SSAOPass); int const BlurPasses = 2; CRenderPass * BlurHPasses[BlurPasses] = { nullptr }; CRenderPass * BlurVPasses[BlurPasses] = { nullptr }; for (int i = 0; i < BlurPasses; ++ i) { BlurHPasses[i] = new CRenderPass(Context); BlurHPasses[i]->SetRenderTarget(PongFrameBuffer); SceneManager->AddRenderPass(BlurHPasses[i]); BlurVPasses[i] = new CRenderPass(Context); BlurVPasses[i]->SetRenderTarget(i + 1 == BlurPasses ? BackBuffer : PingFrameBuffer); SceneManager->AddRenderPass(BlurVPasses[i]); } CPerspectiveCamera * Camera = new CPerspectiveCamera(Window->GetAspectRatio()); Camera->SetPosition(vec3f(-1.7f, 2.8f, 3.4f)); Camera->SetFocalLength(0.4f); Camera->SetNearPlane(0.1f); Camera->SetFarPlane(50.f); RenderPass->SetActiveCamera(Camera); SSAOPass->SetActiveCamera(Camera); CCameraController * Controller = new CCameraController(Camera); Controller->SetTheta(-0.08f); Controller->SetPhi(-0.26f); Window->AddListener(Controller); TimeManager->MakeUpdateTick(0.02)->AddListener(Controller); ///////////////// // Add Objects // ///////////////// CSimpleMeshSceneObject * Sphere1 = new CSimpleMeshSceneObject(); Sphere1->SetMesh(SphereMesh); Sphere1->SetShader(GeometryShader); Sphere1->SetPosition(vec3f(0, 0, 0)); Sphere1->SetScale(2.f); Sphere1->GetMaterial().Diffuse *= color3f(1.0, 0.8f, 0.8f); RenderPass->AddSceneObject(Sphere1); CSimpleMeshSceneObject * Sphere2 = new CSimpleMeshSceneObject(); Sphere2->SetMesh(SphereMesh); Sphere2->SetShader(GeometryShader); Sphere2->SetPosition(vec3f(4, 0, 0)); Sphere2->SetScale(3.f); Sphere2->GetMaterial().Diffuse *= color3f(0.8f, 1, 0.8f); RenderPass->AddSceneObject(Sphere2); CSimpleMeshSceneObject * Sphere3 = new CSimpleMeshSceneObject(); Sphere3->SetMesh(SphereMesh); Sphere3->SetShader(GeometryShader); Sphere3->SetPosition(vec3f(12, 0, 0)); Sphere3->SetScale(4.f); Sphere3->GetMaterial().Diffuse *= color3f(0.8f, 0.9f, 1); RenderPass->AddSceneObject(Sphere3); CSimpleMeshSceneObject * Sphere4 = new CSimpleMeshSceneObject(); Sphere4->SetMesh(SphereMesh); Sphere4->SetShader(GeometryShader); Sphere4->SetPosition(vec3f(3, 0, 6)); Sphere4->GetMaterial().Diffuse *= color3f(0.9f, 1, 1); RenderPass->AddSceneObject(Sphere4); CSimpleMeshSceneObject * PlaneObject = new CSimpleMeshSceneObject(); PlaneObject->SetMesh(PlaneMesh); PlaneObject->SetShader(GeometryShader); RenderPass->AddSceneObject(PlaneObject); CSimpleMesh * DragonMesh = AssetManager->LoadMeshMerged("dragon10k.obj"); CSimpleMeshSceneObject * DragonObject = new CSimpleMeshSceneObject(); DragonObject->SetMesh(DragonMesh); DragonObject->SetShader(GeometryShader); DragonObject->SetPosition(vec3f(6.f, 1.1f, 4.f)); DragonObject->SetScale(4.f); RenderPass->AddSceneObject(DragonObject); CSimpleMesh * StairMesh = AssetManager->LoadMeshMerged("SM_StairCase_02.obj"); CSimpleMeshSceneObject * StairObject = new CSimpleMeshSceneObject(); StairObject->SetMesh(StairMesh); StairObject->SetShader(GeometryShader); StairObject->SetPosition(vec3f(12.f, 0.f, 5.f)); StairObject->SetScale(1.f); StairObject->SetRotation(vec3f(0.f, DegToRad(90.f), 0.f)); RenderPass->AddSceneObject(StairObject); float SSAORadius = 1.0f; CSimpleMeshSceneObject * PostProcessObject = new CSimpleMeshSceneObject(); PostProcessObject->SetMesh(CGeometryCreator::CreateScreenTriangle()); PostProcessObject->SetShader(SSAOShader); PostProcessObject->SetTexture("tSceneNormals", SceneNormal); PostProcessObject->SetTexture("tSceneDepth", SceneDepth); PostProcessObject->SetTexture("texNoise", SSAONoise); PostProcessObject->SetUniform("samples[0]", CUniform<vector<vec3f>>(ssaoKernel)); PostProcessObject->SetUniform("radius", std::make_shared<CUniformReference<float>>(&SSAORadius)); SSAOPass->AddSceneObject(PostProcessObject); CUniform<bool> uDoBlur = true; CUniform<bool> uUnconstrained = false; CUniform<float> uNormalThreshold = 0.5f; for (int i = 0; i < BlurPasses; ++ i) { CSimpleMeshSceneObject * BlurHObject = new CSimpleMeshSceneObject(); BlurHObject->SetMesh(CGeometryCreator::CreateScreenTriangle()); BlurHObject->SetShader(BlurHShader); BlurHObject->SetTexture("uTexture", PingColor); BlurHObject->SetTexture("tSceneNormals", SceneNormal); BlurHObject->SetUniform("uDoBlur", uDoBlur); BlurHObject->SetUniform("uUnconstrained", uUnconstrained); BlurHObject->SetUniform("uNormalThreshold", uNormalThreshold); BlurHPasses[i]->AddSceneObject(BlurHObject); CSimpleMeshSceneObject * BlurVObject = new CSimpleMeshSceneObject(); BlurVObject->SetMesh(CGeometryCreator::CreateScreenTriangle()); BlurVObject->SetShader(BlurVShader); BlurVObject->SetTexture("uTexture", PongColor); BlurVObject->SetTexture("tSceneNormals", SceneNormal); BlurVObject->SetUniform("uDoBlur", uDoBlur); BlurVObject->SetUniform("uUnconstrained", uUnconstrained); BlurVObject->SetUniform("uNormalThreshold", uNormalThreshold); BlurVPasses[i]->AddSceneObject(BlurVObject); } CPointLight * Light1 = new CPointLight(); Light1->SetPosition(vec3f(0, 6, 0)); RenderPass->AddLight(Light1); /////////////// // Main Loop // /////////////// TimeManager->Init(WindowManager); while (WindowManager->Run()) { TimeManager->Update(); GUIManager->NewFrame(); ImGui::SetNextWindowPos(ImVec2(10, 10), ImGuiSetCond_Once); if (ImGui::Begin("Settings")) { ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); ImGui::Text("Camera position: %.3f %.3f %.3f", Camera->GetPosition().X, Camera->GetPosition().Y, Camera->GetPosition().Z); ImGui::Text("Camera rotation: %.3f %.3f", Controller->GetTheta(), Controller->GetPhi()); ImGui::Separator(); ImGui::SliderFloat("SSAO Radius", &SSAORadius, 0.1f, 20.f); ImGui::Checkbox("Do Blur", &uDoBlur.Get()); ImGui::SameLine(); ImGui::Checkbox("Unconstrained", &uUnconstrained.Get()); ImGui::SliderFloat("Normal Threshold", &uNormalThreshold.Get(), -1.f, 1.f); ImGui::End(); } SceneFrameBuffer->ClearColorAndDepth(); BackBuffer->ClearColorAndDepth(); SceneManager->DrawAll(); GUIManager->Draw(); Window->SwapBuffers(); } return 0; }
int main() { //////////////////// // ionEngine Init // //////////////////// Log::AddDefaultOutputs(); SingletonPointer<CGraphicsAPI> GraphicsAPI; SingletonPointer<CWindowManager> WindowManager; SingletonPointer<CSceneManager> SceneManager; GraphicsAPI->Init(new Graphics::COpenGLImplementation()); WindowManager->Init(GraphicsAPI); SceneManager->Init(GraphicsAPI); CWindow * Window = WindowManager->CreateWindow(vec2i(1600, 900), "DemoScene", EWindowType::Windowed); SharedPointer<IGraphicsContext> Context = GraphicsAPI->GetWindowContext(Window); SharedPointer<IRenderTarget> RenderTarget = Context->GetBackBuffer(); RenderTarget->SetClearColor(color3f(0.3f)); /////////////////// // Create Shader // /////////////////// SharedPointer<IVertexShader> VertexShader = GraphicsAPI->CreateVertexShaderFromFile("Diffuse.vert"); SharedPointer<IPixelShader> PixelShader = GraphicsAPI->CreatePixelShaderFromFile("Diffuse.frag"); if (! VertexShader) std::cerr << "Failed to compile vertex shader!" << std::endl; if (! PixelShader) std::cerr << "Failed to compile pixel shader!" << std::endl; SharedPointer<IShaderProgram> ShaderProgram = GraphicsAPI->CreateShaderProgram(); ShaderProgram->SetVertexStage(VertexShader); ShaderProgram->SetPixelStage(PixelShader); //////////////////// // ionScene Setup // //////////////////// CRenderPass * RenderPass = new CRenderPass(Context); RenderPass->SetRenderTarget(RenderTarget); SceneManager->AddRenderPass(RenderPass); CPerspectiveCamera * Camera = new CPerspectiveCamera(Window->GetAspectRatio()); Camera->SetPosition(vec3f(0, 2, -4)); Camera->SetLookAtTarget(vec3f(0, 0, 0)); Camera->SetFocalLength(0.4f); RenderPass->SetActiveCamera(Camera); /////////////////// // Scene Objects // /////////////////// CSimpleMesh * Mesh1 = CGeometryCreator::CreateSphere(); CSimpleMeshSceneObject * SceneObject1 = new CSimpleMeshSceneObject(); SceneObject1->SetMesh(Mesh1); SceneObject1->SetShader(ShaderProgram); SceneObject1->SetPosition(vec3f(2, 0, 0)); RenderPass->AddSceneObject(SceneObject1); CSimpleMesh * Mesh2 = CGeometryCreator::CreateCylinder(0.6f, 0.3f); CSimpleMeshSceneObject * SceneObject2 = new CSimpleMeshSceneObject(); SceneObject2->SetMesh(Mesh2); SceneObject2->SetShader(ShaderProgram); SceneObject2->SetPosition(vec3f(0, -0.5f, 0)); SceneObject2->SetRotation(vec3f(-Constants32::Pi / 2, 0, 0)); RenderPass->AddSceneObject(SceneObject2); CSimpleMesh * Mesh3 = CGeometryCreator::CreateCube(); CSimpleMeshSceneObject * SceneObject3 = new CSimpleMeshSceneObject(); SceneObject3->SetMesh(Mesh3); SceneObject3->SetShader(ShaderProgram); SceneObject3->SetPosition(vec3f(-2, 0, 0)); RenderPass->AddSceneObject(SceneObject3); /////////////// // Main Loop // /////////////// while (WindowManager->Run()) { RenderTarget->ClearColorAndDepth(); SceneManager->DrawAll(); Window->SwapBuffers(); } return 0; }
int main() { //////////////////// // ionEngine Init // //////////////////// Log::AddDefaultOutputs(); SingletonPointer<CGraphicsAPI> GraphicsAPI; SingletonPointer<CWindowManager> WindowManager; SingletonPointer<CTimeManager> TimeManager; SingletonPointer<CSceneManager> SceneManager; SingletonPointer<CAssetManager> AssetManager; GraphicsAPI->Init(new Graphics::COpenGLImplementation()); WindowManager->Init(GraphicsAPI); TimeManager->Init(WindowManager); SceneManager->Init(GraphicsAPI); AssetManager->Init(GraphicsAPI); CWindow * Window = WindowManager->CreateWindow(vec2i(1600, 900), "DemoApplication", EWindowType::Windowed); AssetManager->SetAssetPath("Assets/"); AssetManager->SetShaderPath("Shaders/"); AssetManager->SetTexturePath("Images/"); SharedPointer<IGraphicsContext> Context = GraphicsAPI->GetWindowContext(Window); SharedPointer<IRenderTarget> RenderTarget = Context->GetBackBuffer(); RenderTarget->SetClearColor(color3f(0.3f)); ///////////////// // Load Assets // ///////////////// CSimpleMesh * SphereMesh = CGeometryCreator::CreateSphere(); CSimpleMesh * SkySphereMesh = CGeometryCreator::CreateSkySphere(); CSimpleMesh * PlaneMesh = CGeometryCreator::CreatePlane(vec2f(100.f)); SharedPointer<IShaderProgram> DiffuseShader = AssetManager->LoadShader("Diffuse"); SharedPointer<IShaderProgram> SimpleShader = AssetManager->LoadShader("Simple"); SharedPointer<IShaderProgram> SpecularShader = AssetManager->LoadShader("Specular"); SharedPointer<IShaderProgram> SkySphereShader = AssetManager->LoadShader("SkySphere"); SharedPointer<ITexture2D> SkyMap = AssetManager->LoadTexture("SkyMap.jpg"); SkyMap->SetMagFilter(ITexture::EFilter::Nearest); //////////////////// // ionScene Setup // //////////////////// CRenderPass * RenderPass = new CRenderPass(Context); RenderPass->SetRenderTarget(RenderTarget); SceneManager->AddRenderPass(RenderPass); CPerspectiveCamera * Camera = new CPerspectiveCamera(Window->GetAspectRatio()); Camera->SetPosition(vec3f(0, 3, -5)); Camera->SetFocalLength(0.4f); RenderPass->SetActiveCamera(Camera); CCameraController * Controller = new CCameraController(Camera); Controller->SetTheta(15.f * Constants32::Pi / 48.f); Controller->SetPhi(-Constants32::Pi / 16.f); Window->AddListener(Controller); TimeManager->MakeUpdateTick(0.02)->AddListener(Controller); ///////////////// // Add Objects // ///////////////// CSimpleMeshSceneObject * LightSphere1 = new CSimpleMeshSceneObject(); LightSphere1->SetMesh(SphereMesh); LightSphere1->SetShader(SimpleShader); LightSphere1->SetPosition(vec3f(0, 1, 0)); RenderPass->AddSceneObject(LightSphere1); CSimpleMeshSceneObject * LightSphere2 = new CSimpleMeshSceneObject(); LightSphere2->SetMesh(SphereMesh); LightSphere2->SetShader(SimpleShader); LightSphere2->SetPosition(vec3f(4, 2, 0)); RenderPass->AddSceneObject(LightSphere2); CSimpleMeshSceneObject * LightSphere3 = new CSimpleMeshSceneObject(); LightSphere3->SetMesh(SphereMesh); LightSphere3->SetShader(SimpleShader); LightSphere3->SetPosition(vec3f(12, 3, 0)); RenderPass->AddSceneObject(LightSphere3); CSimpleMeshSceneObject * SpecularSphere = new CSimpleMeshSceneObject(); SpecularSphere->SetMesh(SphereMesh); SpecularSphere->SetShader(SpecularShader); SpecularSphere->SetPosition(vec3f(3, 3, 6)); SpecularSphere->GetMaterial().Ambient = vec3f(0.05f); RenderPass->AddSceneObject(SpecularSphere); CSimpleMeshSceneObject * PlaneObject = new CSimpleMeshSceneObject(); PlaneObject->SetMesh(PlaneMesh); PlaneObject->SetShader(DiffuseShader); PlaneObject->GetMaterial().Ambient = vec3f(0.05f); RenderPass->AddSceneObject(PlaneObject); CSimpleMeshSceneObject * SkySphereObject = new CSimpleMeshSceneObject(); SkySphereObject->SetMesh(SkySphereMesh); SkySphereObject->SetShader(SkySphereShader); SkySphereObject->SetTexture("uTexture", SkyMap); RenderPass->AddSceneObject(SkySphereObject); CPointLight * Light1 = new CPointLight(); Light1->SetPosition(vec3f(0, 1, 0)); Light1->SetColor(Colors::Red); RenderPass->AddLight(Light1); CPointLight * Light2 = new CPointLight(); Light2->SetPosition(vec3f(4, 2, 0)); Light2->SetColor(Colors::Green); RenderPass->AddLight(Light2); CPointLight * Light3 = new CPointLight(); Light3->SetPosition(vec3f(12, 3, 0)); Light3->SetColor(Colors::Blue); RenderPass->AddLight(Light3); /////////////// // Main Loop // /////////////// TimeManager->Init(WindowManager); while (WindowManager->Run()) { TimeManager->Update(); float const MinimumBrightness = 0.2f; float const MaximumBrightness = 1.f - MinimumBrightness; float const Brightness = (Sin<float>((float) TimeManager->GetRunTime()) / 2.f + 0.5f) * MaximumBrightness + MinimumBrightness; float const Radius = Brightness * 10.f; Light1->SetRadius(Radius); Light2->SetRadius(Radius); Light3->SetRadius(Radius); float const Bright = 1; float const Dim = 0.5f; LightSphere1->GetMaterial().Diffuse = color3f(Bright, Dim, Dim) * Brightness; LightSphere2->GetMaterial().Diffuse = color3f(Dim, Bright, Dim) * Brightness; LightSphere3->GetMaterial().Diffuse = color3f(Dim, Dim, Bright) * Brightness; LightSphere1->SetScale(Brightness); LightSphere2->SetScale(Brightness); LightSphere3->SetScale(Brightness); SkySphereObject->SetPosition(Camera->GetPosition()); RenderTarget->ClearColorAndDepth(); SceneManager->DrawAll(); Window->SwapBuffers(); } return 0; }
int main() { //////////////////// // ionEngine Init // //////////////////// Log::AddDefaultOutputs(); SingletonPointer<CGraphicsAPI> GraphicsAPI; SingletonPointer<CWindowManager> WindowManager; SingletonPointer<CTimeManager> TimeManager; SingletonPointer<CSceneManager> SceneManager; SingletonPointer<CAssetManager> AssetManager; SingletonPointer<CGUIManager> GUIManager; GraphicsAPI->Init(new COpenGLImplementation()); WindowManager->Init(GraphicsAPI); TimeManager->Init(WindowManager); SceneManager->Init(GraphicsAPI); AssetManager->Init(GraphicsAPI); CWindow * Window = WindowManager->CreateWindow(vec2i(1600, 900), "Shadow Maps", EWindowType::Windowed); GUIManager->Init(Window); AssetManager->AddAssetPath("Assets/"); AssetManager->SetShaderPath("Shaders/"); AssetManager->SetTexturePath("Images/"); SharedPointer<IGraphicsContext> Context = GraphicsAPI->GetWindowContext(Window); SharedPointer<IRenderTarget> BackBuffer = Context->GetBackBuffer(); BackBuffer->SetClearColor(color3f(0.3f)); SharedPointer<IFrameBuffer> ShadowBuffer = Context->CreateFrameBuffer(); SharedPointer<ITexture2D> ShadowTexture = GraphicsAPI->CreateTexture2D(vec2u(4096), ITexture::EMipMaps::False, ITexture::EFormatComponents::RGBA, ITexture::EInternalFormatType::Fix8); SharedPointer<ITexture2D> ShadowDepth = GraphicsAPI->CreateTexture2D(vec2u(4096), ITexture::EMipMaps::False, ITexture::EFormatComponents::R, ITexture::EInternalFormatType::Depth); ShadowBuffer->AttachColorTexture(ShadowTexture, 0); ShadowBuffer->AttachDepthTexture(ShadowDepth); if (! ShadowBuffer->CheckCorrectness()) { Log::Error("Frame buffer not valid!"); } ///////////////// // Load Assets // ///////////////// CSimpleMesh * SphereMesh = CGeometryCreator::CreateSphere(); CSimpleMesh * PlaneMesh = CGeometryCreator::CreatePlane(vec2f(100.f)); CSimpleMesh * CubeMesh = CGeometryCreator::CreateCube(); SharedPointer<IShaderProgram> DiffuseShader = AssetManager->LoadShader("Diffuse"); SharedPointer<IShaderProgram> QuadCopyShader = AssetManager->LoadShader("QuadCopy"); //////////////////// // ionScene Setup // //////////////////// CRenderPass * ShadowPass = new CRenderPass(Context); ShadowPass->SetRenderTarget(ShadowBuffer); SceneManager->AddRenderPass(ShadowPass); CRenderPass * ColorPass = new CRenderPass(Context); ColorPass->SetRenderTarget(BackBuffer); SceneManager->AddRenderPass(ColorPass); CRenderPass * PostProcess = new CRenderPass(Context); PostProcess->SetRenderTarget(BackBuffer); SceneManager->AddRenderPass(PostProcess); CPerspectiveCamera * Camera = new CPerspectiveCamera(Window->GetAspectRatio()); Camera->SetPosition(vec3f(0, 3, -5)); Camera->SetFocalLength(0.4f); ColorPass->SetActiveCamera(Camera); CCameraController * Controller = new CCameraController(Camera); Controller->SetTheta(15.f * Constants32::Pi / 48.f); Controller->SetPhi(-Constants32::Pi / 16.f); Window->AddListener(Controller); TimeManager->MakeUpdateTick(0.02)->AddListener(Controller); vec3f LightDirection = vec3f(2, -12, 2); float LightViewSize = 20.f; float LightNear = 50.f; float LightFar = 200.f; COrthographicCamera * LightCamera = new COrthographicCamera(-LightViewSize, LightViewSize, -LightViewSize, LightViewSize); LightCamera->SetPosition(-LightDirection * 10.f); LightCamera->SetLookDirection(LightDirection); LightCamera->SetNearPlane(LightNear); LightCamera->SetFarPlane(LightFar); ShadowPass->SetActiveCamera(LightCamera); ///////////////// // Add Objects // ///////////////// CSimpleMeshSceneObject * Sphere1 = new CSimpleMeshSceneObject(); Sphere1->SetMesh(SphereMesh); Sphere1->SetShader(DiffuseShader); Sphere1->SetPosition(vec3f(0, 1, 0)); Sphere1->SetScale(2.f); ColorPass->AddSceneObject(Sphere1); ShadowPass->AddSceneObject(Sphere1); CSimpleMeshSceneObject * Sphere2 = new CSimpleMeshSceneObject(); Sphere2->SetMesh(SphereMesh); Sphere2->SetShader(DiffuseShader); Sphere2->SetPosition(vec3f(4, 4, 0)); Sphere2->SetScale(3.f); ColorPass->AddSceneObject(Sphere2); ShadowPass->AddSceneObject(Sphere2); CSimpleMeshSceneObject * Sphere3 = new CSimpleMeshSceneObject(); Sphere3->SetMesh(SphereMesh); Sphere3->SetShader(DiffuseShader); Sphere3->SetPosition(vec3f(12, 2, 0)); Sphere3->SetScale(4.f); ColorPass->AddSceneObject(Sphere3); ShadowPass->AddSceneObject(Sphere3); CSimpleMeshSceneObject * Sphere4 = new CSimpleMeshSceneObject(); Sphere4->SetMesh(SphereMesh); Sphere4->SetShader(DiffuseShader); Sphere4->SetPosition(vec3f(3, 4, 6)); ColorPass->AddSceneObject(Sphere4); ShadowPass->AddSceneObject(Sphere4); CSimpleMeshSceneObject * Cube1 = new CSimpleMeshSceneObject(); Cube1->SetMesh(CubeMesh); Cube1->SetShader(DiffuseShader); Cube1->SetPosition(vec3f(-4, 4, 0)); Cube1->SetScale(3.f); ColorPass->AddSceneObject(Cube1); ShadowPass->AddSceneObject(Cube1); CSimpleMeshSceneObject * Cube2 = new CSimpleMeshSceneObject(); Cube2->SetMesh(CubeMesh); Cube2->SetShader(DiffuseShader); Cube2->SetPosition(vec3f(-12, 2, 0)); Cube2->SetScale(4.f); ColorPass->AddSceneObject(Cube2); ShadowPass->AddSceneObject(Cube2); CSimpleMeshSceneObject * Plane = new CSimpleMeshSceneObject(); Plane->SetMesh(PlaneMesh); Plane->SetShader(DiffuseShader); Plane->GetMaterial().Ambient *= Colors::Green; Plane->GetMaterial().Diffuse *= Colors::Green; ColorPass->AddSceneObject(Plane); ShadowPass->AddSceneObject(Plane); //vector<CSimpleMesh *> Meshes = CGeometryCreator::LoadOBJFile("terrain.obj"); //for (auto Mesh : Meshes) //{ // CSimpleMeshSceneObject * PlaneObject = new CSimpleMeshSceneObject(); // PlaneObject->SetMesh(Mesh); // PlaneObject->SetShader(DiffuseShader); // ColorPass->AddSceneObject(PlaneObject); // ShadowPass->AddSceneObject(PlaneObject); //} CSimpleMeshSceneObject * PostProcessObject = new CSimpleMeshSceneObject(); PostProcessObject->SetMesh(CGeometryCreator::CreateScreenTriangle()); PostProcessObject->SetShader(QuadCopyShader); PostProcessObject->SetTexture("uTexture", ShadowDepth); PostProcess->AddSceneObject(PostProcessObject); CDirectionalLight * Light1 = new CDirectionalLight(); Light1->SetDirection(LightDirection); ColorPass->AddLight(Light1); ShadowPass->AddLight(Light1); CUniform<glm::mat4> uLightMatrix; ColorPass->SetUniform("uLightMatrix", uLightMatrix); ColorPass->SetTexture("uShadowMap", ShadowDepth); /////////////// // Main Loop // /////////////// TimeManager->Init(WindowManager); while (WindowManager->Run()) { TimeManager->Update(); PostProcessObject->SetVisible(Window->IsKeyDown(EKey::F1)); GUIManager->NewFrame(); ImGui::SetNextWindowPos(ImVec2(10, 10), ImGuiSetCond_Once); if (ImGui::Begin("Settings")) { ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); ImGui::Text("Camera position: %.3f %.3f %.3f", Camera->GetPosition().X, Camera->GetPosition().Y, Camera->GetPosition().Z); ImGui::Text("Camera rotation: %.3f %.3f", Controller->GetTheta(), Controller->GetPhi()); ImGui::Separator(); ImGui::SliderFloat("Light Camera Size", &LightViewSize, 1.f, 200.f); ImGui::SliderFloat("Light Near Plane", &LightNear, 1.f, 300.f); ImGui::SliderFloat("Light Far Plane", &LightFar, 1.f, 600.f); ImGui::SliderFloat3("Light Direction", LightDirection.Values, -30.f, 30.f); ImGui::Text("Light Position: %.3f %.3f %.3f", LightCamera->GetPosition().X, LightCamera->GetPosition().Y, LightCamera->GetPosition().Z); ImGui::End(); } LightCamera->SetLeft(-LightViewSize); LightCamera->SetRight(LightViewSize); LightCamera->SetBottom(-LightViewSize); LightCamera->SetTop(LightViewSize); LightCamera->SetPosition(-LightDirection * 10.f); LightCamera->SetLookDirection(LightDirection); LightCamera->SetNearPlane(LightNear); LightCamera->SetFarPlane(LightFar); uLightMatrix = LightCamera->GetProjectionMatrix() * LightCamera->GetViewMatrix(); ShadowBuffer->ClearColorAndDepth(); BackBuffer->ClearColorAndDepth(); SceneManager->DrawAll(); GUIManager->Draw(); Window->SwapBuffers(); } return 0; }