Click here to Skip to main content
15,881,139 members
Articles / Multimedia / GDI

3D Software Rendering Engine - Part I

Rate me:
Please Sign up or sign in to vote.
4.93/5 (120 votes)
18 Mar 2011CPOL8 min read 254.9K   10.8K   264  
This article is about the 3D software rendering engine.
#include "main.h"


HINSTANCE g_hInstance = NULL;
HWND g_hMainWindow = NULL;
C3DEngine g_3DEngine;
BOOL g_bPaused = FALSE;
_LPRENDERLIST g_lpRenderList = NULL;
_LPOBJECT3D g_lpObject3D = NULL;
_LPCAMERA3D g_lpCamera3D = NULL;
_LPTEXTUREINFO g_lpTexture = NULL;
_LPMATERIALINFO g_lpMaterial = NULL;
_LPLIGHTINFO g_lpLights[NUMBER_LIGHTS];
_POINT3D world_positions[NUMBER_TEST_OBJECTS];


int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	int iReturnValue = 0;

	// Format main window class
	WNDCLASSEX wce;
	memset(&wce, 0, sizeof(WNDCLASSEX));
	wce.cbSize = sizeof(WNDCLASSEX);
	wce.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
	wce.lpfnWndProc = (WNDPROC)MainWindowProc;
	wce.hInstance = hInstance;
	wce.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
	wce.hCursor = LoadCursor(NULL, IDC_ARROW);
	wce.lpszClassName = MAIN_WINDOW_CLASS_NAME;

	// Calculate main window position
	int iScreenWidth = GetSystemMetrics(SM_CXSCREEN);
	int iScreenHeight = GetSystemMetrics(SM_CYSCREEN);
	int x = (iScreenWidth - MAIN_WINDOW_WIDTH) / 2;
	int y = (iScreenHeight - MAIN_WINDOW_HEIGHT) / 2;

	srand((unsigned)time(NULL));
	
	// Register main window class
	if (RegisterClassEx(&wce) != 0)
	{
		// Save application instance
		g_hInstance = hInstance;

		// Create main window
		g_hMainWindow = CreateWindowEx(0, MAIN_WINDOW_CLASS_NAME, NULL, WS_POPUP | WS_VISIBLE, x, y, 
			MAIN_WINDOW_WIDTH, MAIN_WINDOW_HEIGHT, NULL, NULL, g_hInstance, NULL);
		if (g_hMainWindow != NULL)
		{
			// Init
			Init();

			// Main
			Main();

			// Shutdown
			Shutdown();
		}
		else
		{
			// Error creating main window
			MessageBox(NULL, _T("The main window can not be created!"), _T("Error..."), MB_OK | MB_ICONERROR);
			iReturnValue = -1;
		}

		// Unregister main window class
		UnregisterClass(MAIN_WINDOW_CLASS_NAME, hInstance);
	}
	else
	{
		// Error registering main window class
		MessageBox(NULL, _T("The main window class can not be registered!"), _T("Error..."), MB_OK | MB_ICONERROR);
		iReturnValue = -1;
	}

	return iReturnValue;
}

LRESULT CALLBACK MainWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	int lResult = 0;

	// Process main window messages
	switch (uMsg)
	{
		case WM_DESTROY:
			{
				// Exit application
				PostQuitMessage(0);
			}
			break;

		case WM_KEYDOWN:
			{
				if (wParam == VK_ESCAPE)
				{
					// Destroy main window
					DestroyWindow(hWnd);
				}
				else if ((_TCHAR)wParam == '0')
				{
					g_3DEngine.Set_ShadingMode(_SHADING_MODE_NONE);
				}
				else if ((_TCHAR)wParam == '1')
				{
					g_3DEngine.Set_ShadingMode(_SHADING_MODE_CONSTANT);
				}
				else if ((_TCHAR)wParam == '2')
				{
					g_3DEngine.Set_ShadingMode(_SHADING_MODE_FLAT);
				}
				else if ((_TCHAR)wParam == '3')
				{
					g_3DEngine.Set_ShadingMode(_SHADING_MODE_GOURAUD);
				}
				else if ((_TCHAR)wParam == '4')
				{
					g_3DEngine.Set_ShadingMode(_SHADING_MODE_TEXTURE | _SHADING_MODE_CONSTANT);
				}
				else if ((_TCHAR)wParam == '5')
				{
					g_3DEngine.Set_ShadingMode(_SHADING_MODE_TEXTURE | _SHADING_MODE_FLAT);
				}
				else if ((_TCHAR)wParam == '6')
				{
					g_3DEngine.Set_ShadingMode(_SHADING_MODE_TEXTURE | _SHADING_MODE_GOURAUD);
				}
				else if ((_TCHAR)wParam == 'B')
				{
					if (g_3DEngine.Get_TextureFiltering() == _TEXTURE_FILTERING_NONE)
						g_3DEngine.Set_TextureFiltering(_TEXTURE_FILTERING_BILINEAR);
					else
						g_3DEngine.Set_TextureFiltering(_TEXTURE_FILTERING_NONE);
				}
				else if ((_TCHAR)wParam == 'P')
				{
					g_bPaused = !g_bPaused;
				}
				else if ((_TCHAR)wParam == VK_LEFT)
				{
					g_lpCamera3D->pos.x -= 1.0f;
				}
				else if ((_TCHAR)wParam == VK_RIGHT)
				{
					g_lpCamera3D->pos.x += 1.0f;
				}
				else if ((_TCHAR)wParam == VK_UP)
				{
					g_3DEngine.Add_Vector3D(g_lpCamera3D->pos, g_lpCamera3D->pos, g_lpCamera3D->target);
				}
				else if ((_TCHAR)wParam == VK_DOWN)
				{
					g_3DEngine.Sub_Vector3D(g_lpCamera3D->pos, g_lpCamera3D->pos, g_lpCamera3D->target);
				}
				else if ((_TCHAR)wParam == 'R')
				{
					g_lpCamera3D->dir.x = 0.0f;
					g_lpCamera3D->dir.y = 0.0f;
					g_lpCamera3D->dir.z = 0.0f;
					g_lpCamera3D->target.x = 0.0f;
					g_lpCamera3D->target.y = 0.0f;
					g_lpCamera3D->target.z = 1.0f;
				}
			}
			break;

		case WM_MOUSEMOVE:
			{
				g_3DEngine.Update_Mouse(LOWORD(lParam), HIWORD(lParam), g_lpCamera3D);
			}
			break;

		default:
			{
				// Call main window default procedure
				lResult = DefWindowProc(hWnd, uMsg, wParam, lParam);
			}
	}

	return lResult;
}

void Init()
{
	// Init engine
	g_3DEngine.Init(g_hMainWindow, MAIN_WINDOW_WIDTH, MAIN_WINDOW_HEIGHT, FRAMES_PER_SECOND);

	_POINT3D obj_pos;
	g_3DEngine.Init_Vector3D(obj_pos, 0, 15, 50);
	g_lpObject3D = g_3DEngine.Load_Object_PLG(_T("Cube.plg"), obj_pos);
//	g_lpObject3D = g_3DEngine.Load_Object_MD2(_T("hansolo.md2"), _T("solo_anh.bmp"), obj_pos);
	_POINT3D cam_pos, cam_dir, cam_target;
	g_3DEngine.Init_Vector3D(cam_pos, 0, 0, 0);
	g_3DEngine.Init_Vector3D(cam_dir, 0, 0, 0);
	g_3DEngine.Init_Vector3D(cam_target, 0, 0, 1);
	g_lpCamera3D = g_3DEngine.Init_Camera(cam_pos, cam_dir, cam_target, 5.0f, 5000.0f, 90.0f, MAIN_WINDOW_WIDTH, MAIN_WINDOW_HEIGHT);
	g_lpRenderList = g_3DEngine.Init_RenderList(MAX_OBJECTS);
	g_lpTexture = g_3DEngine.Load_Texture(_T("texture1.bmp"));
	g_lpMaterial = g_3DEngine.Init_Material(_RGB(0,0,255), 1.0f, 1.0f, 1.0f, 0.0f, g_lpTexture);
	g_3DEngine.Set_Material(g_lpObject3D, g_lpMaterial);
	g_lpObject3D->list_texel[0].x = 0;
	g_lpObject3D->list_texel[0].y = 0;
	g_lpObject3D->list_texel[1].x = (float)g_lpTexture->dwSize - 1;
	g_lpObject3D->list_texel[1].y = 0;
	g_lpObject3D->list_texel[2].x = (float)g_lpTexture->dwSize - 1;
	g_lpObject3D->list_texel[2].y = (float)g_lpTexture->dwSize - 1;
	g_lpObject3D->list_texel[3].x = 0;
	g_lpObject3D->list_texel[3].y = (float)g_lpTexture->dwSize - 1;
	g_lpObject3D->list_texel[4].x = (float)g_lpTexture->dwSize - 1;
	g_lpObject3D->list_texel[4].y = (float)g_lpTexture->dwSize - 1;
	g_lpObject3D->list_texel[5].x = 0;
	g_lpObject3D->list_texel[5].y = (float)g_lpTexture->dwSize - 1;
	g_lpObject3D->list_texel[6].x = 0;
	g_lpObject3D->list_texel[6].y = 0;
	g_lpObject3D->list_texel[7].x = (float)g_lpTexture->dwSize - 1;
	g_lpObject3D->list_texel[7].y = 0;
	g_lpObject3D->plist[0].texel[0] = 2;
	g_lpObject3D->plist[0].texel[1] = 1;
	g_lpObject3D->plist[0].texel[2] = 0;
	g_lpObject3D->plist[1].texel[0] = 3;
	g_lpObject3D->plist[1].texel[1] = 2;
	g_lpObject3D->plist[1].texel[2] = 0;
	g_lpObject3D->plist[2].texel[0] = 3;
	g_lpObject3D->plist[2].texel[1] = 2;
	g_lpObject3D->plist[2].texel[2] = 0;
	g_lpObject3D->plist[3].texel[0] = 0;
	g_lpObject3D->plist[3].texel[1] = 1;
	g_lpObject3D->plist[3].texel[2] = 2;
	g_lpObject3D->plist[4].texel[0] = 2;
	g_lpObject3D->plist[4].texel[1] = 1;
	g_lpObject3D->plist[4].texel[2] = 0;
	g_lpObject3D->plist[5].texel[0] = 3;
	g_lpObject3D->plist[5].texel[1] = 2;
	g_lpObject3D->plist[5].texel[2] = 0;
	g_lpObject3D->plist[6].texel[0] = 1;
	g_lpObject3D->plist[6].texel[1] = 2;
	g_lpObject3D->plist[6].texel[2] = 0;
	g_lpObject3D->plist[7].texel[0] = 2;
	g_lpObject3D->plist[7].texel[1] = 3;
	g_lpObject3D->plist[7].texel[2] = 0;
	g_lpObject3D->plist[8].texel[0] = 3;
	g_lpObject3D->plist[8].texel[1] = 2;
	g_lpObject3D->plist[8].texel[2] = 0;
	g_lpObject3D->plist[9].texel[0] = 2;
	g_lpObject3D->plist[9].texel[1] = 1;
	g_lpObject3D->plist[9].texel[2] = 0;
	g_lpObject3D->plist[10].texel[0] = 2;
	g_lpObject3D->plist[10].texel[1] = 3;
	g_lpObject3D->plist[10].texel[2] = 0;
	g_lpObject3D->plist[11].texel[0] = 1;
	g_lpObject3D->plist[11].texel[1] = 2;
	g_lpObject3D->plist[11].texel[2] = 0;
//	g_3DEngine.Extract_Frame_MD2(g_lpObject3D);
	_POINT3D light_pos, light_dir, spot_pos, spot_dir;
	float umbra = 30.0f;
	float penumbra = 60.0f;
	float falloff = 1.0f;
	g_3DEngine.Init_Vector3D(light_pos, 0, 1000, 0);
	g_3DEngine.Init_Vector3D(light_dir, 0, -1, 0);
	g_3DEngine.Init_Vector3D(spot_pos, 1000, 1000, -1000);
	g_3DEngine.Init_Vector3D(spot_dir, -1, -1, 1);
	g_lpLights[0] = g_3DEngine.Init_Light(_LIGHT_TYPE_AMBIENT, _RGB(64,64,64), 0, 0, light_pos, light_dir, 0, 0, 0, 0, 0, 0);
	g_lpLights[1] = g_3DEngine.Init_Light(_LIGHT_TYPE_INFINITE, 0, _RGB(255,255,255), 0, light_pos, light_dir, 0, 0, 0, 0, 0, 0);
	g_lpLights[2] = g_3DEngine.Init_Light(_LIGHT_TYPE_POINT, 0, _RGB(255,255,255), 0, light_pos, light_dir, 0, 0.001f, 0, 0, 0, 0);
	g_lpLights[0]->bActive = TRUE;
	g_lpLights[1]->bActive = TRUE;
	g_lpLights[2]->bActive = TRUE;

	for (int i=0; i<NUMBER_TEST_OBJECTS; i++)
	{
		world_positions[i].x = (float)(rand() % 200);
		world_positions[i].y = (float)(rand() % 200);
		world_positions[i].z = (float)(rand() % 200);
		world_positions[i].w = 1.0f;
	}
}

void Main()
{
	MSG msg;

	// Run main window message loop
	while (true)
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			// Test for quit message
			if (msg.message == WM_QUIT)
				break;

			// Translate any accelerator keys
			TranslateMessage(&msg);

			// Send message to window procedure
			DispatchMessage(&msg);
		}

		// Start frame
		g_3DEngine.Begin_Frame(g_lpRenderList, g_lpCamera3D);

		// Update
		Update();

		// End frame
		g_3DEngine.End_Frame(g_lpRenderList, g_lpCamera3D);

		// Draw text
		char szText[1024];
		sprintf(szText, "FPS: %d\nTR: %d\nFR: %d\nSR: %d", g_3DEngine.Get_FPS(), g_3DEngine.Get_TriangleRate(), g_3DEngine.Get_FillRate(), g_3DEngine.Get_SkipRate());
		g_3DEngine.Draw_Text(10, 10, szText, _RGB(255,255,255), 100, _T("Arial"), 8, TRUE, FALSE);

		// Draw frame
		g_3DEngine.Draw_Frame(g_lpRenderList);
	}
}

void Update()
{
	static float angle_y = 0.0f;
//	angle_y += 1.0f;
	if (angle_y >= 360.0f)
	{
		angle_y = 0.0f;
	}
	g_lpObject3D->ux = angle_y;
	g_lpObject3D->uy = angle_y;
	g_lpObject3D->uz = angle_y;

//	g_lpObject3D->uy = 270.0f;

	g_3DEngine.Insert_RenderList(g_lpRenderList, g_lpObject3D, g_lpCamera3D, g_lpLights, NUMBER_LIGHTS);
/*	float oldZ = g_lpObject3D->world_pos.z;
	for (int i=0; i<NUMBER_TEST_OBJECTS; i++)
	{
		g_lpObject3D->world_pos = world_positions[i];
		g_3DEngine.Insert_RenderList(g_lpRenderList, g_lpObject3D, g_lpCamera3D, g_lpLights, NUMBER_LIGHTS);
	}
	g_lpObject3D->world_pos.z = oldZ;*/
}

void Shutdown()
{
	for (int i=0; i<NUMBER_LIGHTS; i++)
	{
		g_3DEngine.Destroy_Light(g_lpLights[i]);
	}
	g_3DEngine.Destroy_Material(g_lpMaterial);
	g_3DEngine.Destroy_Texture(g_lpTexture);
	g_3DEngine.Destroy_Object(g_lpObject3D);
	g_3DEngine.Destroy_Camera(g_lpCamera3D);
	g_3DEngine.Destroy_RenderList(g_lpRenderList);

	// Shutdown engine
	g_3DEngine.Shutdown();
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Elektromehanika d.o.o. Nis
Serbia Serbia
He has a master degree in Computer Science at Faculty of Electronics in Nis (Serbia), and works as a C++/C# application developer for Windows platforms since 2001. He likes traveling, reading and meeting new people and cultures.

Comments and Discussions