Saturday, July 16, 2022

Lesson06: Lighting a Textured Cube interactively

Overview 
In the previous posts drawing a textured cube were explained. Also, the implementation of the LightingUtil and LightedTexCube were covered. 
In this post we will try to draw a textured cube with lighting interactively. The cube looks as shown above. The cube looks elongated because aspect ratio is not applied.

Details
The purpose of  Lesson06 is to create a lighted textured cube and work with it interactively with different types of light to understand nuances of lighting.

System  class diagram
The scene class overrides camera with an instance of ThreeDCamera. It has an instance of LightedTexCube called cube derived from TexturedCube class.

Implementation

Scene
The functionality is implemented in the Scene class derived from BaseScene class.

The three methods InitDrawScene and Cleanup are overridden as below:
The Init method calls 
  1. BaseScene::Init to create hosting window and OpenGL Context. 
  2. It also attaches camera to a ThreeDCamera class object. This camera  processes keyboard and mouse inputs as explained earlier.
  3. It creates an input dialog to work with lighting settings interactively.
  4. It calls init function on the LightedTexCube object to populate VBO/EBO buffers and bind them. 
  5. Load textures from the image file
  6. It also compiles and links shader programs.
The DrawScene method draws the cube with texture wrapped and rotates as per keyboard or mouse inputs. The lighting settings are taken from the light instance of LightingUtil of the cube object.

The Cleanup method releases the resources related to VBO/EBO, Texture related resources and shader programs.

The message handler for IDOK is called when Apply button is pressed after updates are made in the input dialog. It refreshes the display.

The message handler for IDCANCEL is called when in Cancel button is pressed the input dialog. It calls 
OnCloseWindow to destroy window.

Finally the WM_CLOSE  event is  handled in OnCloseWindow function and the window is destroyed and  application is shutdown when the window is closed or Escape key is pressed. 

#include "Scene\BaseScene.h"
#include "Scene\Camera\ThreeDCamera.h"
#include "Geometry\LightingUtil.h"
#include "Geometry\Cube\LightedTexCube.h"
#include "InputDlg.h"

DWORD WINAPI ThreadFunction(LPVOID lpParam);

class Scene:public BaseScene
{
public:
	//message handler
	BEGIN_MSG_MAP(Scene0)
		MESSAGE_HANDLER(WM_CLOSE, OnCloseWindow)
		COMMAND_ID_HANDLER(IDOK, OnDoRefresh)
		COMMAND_ID_HANDLER(IDCANCEL, OnClose)
		CHAIN_MSG_MAP(BaseScene)
	END_MSG_MAP()


	//override
	int Init(RECT rect, WCHAR *windowname)
	{
		//create host window and context
		BaseScene::Init(rect, windowname);

		CreateThread(NULL, 0, ThreadFunction, this, 0, NULL);

		//attach mouse keyboard input handler
		camera = new ThreeDCamera(m_hWnd);
		::Sleep(500);
		updatecube();

		return 0;
	}

	void updatecube()
	{
		if (pcube != nullptr)
		{
			auto src = pcube->light.lightsrc.src;
			pdlg->update(&pcube->light);
			if (src != pcube->light.lightsrc.src)
			{
				pcube->Cleanup();
				delete pcube;
				pcube = nullptr;
			}
		}

		if (pcube == nullptr)
		{
			pcube = new LightedTexCube();
			pdlg->update(&pcube->light);
			pcube->Init(0, R"(..\resources\textures\rocks2.bmp)");
		}
	}

	//release resources
	void Cleanup()
	{
		pcube->Cleanup();
		delete camera;
	}


	LRESULT OnDoRefresh(WORD wParam, WORD wParam2, HWND lParam, BOOL& bHandled)
	{
		bHandled = TRUE;
		updatecube();
		Invalidate();
		return 0;
	}

	LRESULT OnClose(WORD wParam, WORD wParam2, HWND lParam, BOOL& bHandled)
	{
		return OnCloseWindow(0, 0, (LPARAM)nullptr, bHandled);
	}


	//draw the scene
	void DrawScene()
	{
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		SceneCamera()->augumentModelMatrix(*pcube);
		wstring wcap = L"Lighting Settings - " + pcube->getangless();
		SetWindowTextW(wcap.c_str());
		pcube->Draw();
		SceneCamera()->MM.Reset();
	}

	//Close the window
	LRESULT OnCloseWindow(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		bHandled = TRUE;
		DestroyWindow();
		PostQuitMessage(0);
		return 0;
	}

	inline ThreeDCamera*  SceneCamera()
	{
		static auto ret = dynamic_cast<ThreeDCamera*>(camera);
		return ret;
	}

	void CreateInputDlg()
	{
		pdlg = new InputDlg();
		pdlg->Create(m_hWnd);
		pdlg->ShowWindow(SW_SHOW);
		Invalidate();
	}

private:
	LightedTexCube *pcube = nullptr;
	int IDM_INPUTDLG = 1001;
	InputDlg* pdlg;

};

DWORD WINAPI ThreadFunction(LPVOID lpParam)
{
	Scene* pscene = (Scene*)lpParam;
	pscene->CreateInputDlg();

	MSG msg;
	while (GetMessage(&msg, 0, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessageA(&msg);
	}

	return 0;
}

Application
Scene class is hosted main.cpp. which creates the scene object and displays it. Message pump is added to process windows messages.

#include "Scene.h"

Scene scene;

int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmd_line, int show)
{
	scene.Init(RECT{ 100, 100, 780, 500 }, L"Lesson06: Lighting");
	scene.ShowWindow(show);

	MSG msg;
	while (GetMessage(&msg, 0, 0, 0)) 
	{
		TranslateMessage(&msg);
		DispatchMessageA(&msg);
	}

	return 0;
}

Input dialog
The input dialog as shown below can be used to change settings and understand lighting.

Output
The output looks as shown in the top. 


No comments:

Post a Comment