[ENG] Greetings, is page completely in Russian, for Russian-speaking visitors. In this example it is told as to make of a standard pattern from TV3D 6.5 SDK to make a pattern which will be more convenient and easier for understanding and use (imho). An initial code it is possible download in the end of page.

[RUS] Приветствую=)Искал тут статьи(сам недавно начал изучать TV3D) на русском,не нашел,вот решил написать статью “первые шаги”,заодно упростил для понимания шаблон.Теперь template.cpp более похож прост,и структура создания сцены более напоминает Blitz3D (загрузка-цикл,в одном месте),с которого я к примеру начинал,и так кодить мне проще.возможно не только мне.

Итак начнем. ПРИМЕЧАНИЕ: В самих исходниках комментарии в основном на англиском.

Для начала нужно поставить задачу=)Итак,наша задача-упростить стандартный шаблон.Т.к. большую часть template.cpp сейчас занимает создание,обработка и ‘убивание’ окна,а эти функции нам мешаются,следовательно нужно их убрать с глаз долой=)Оставим в template.cpp только функцию _tWinMain,тогда template.cpp будет выглядеть так:

//#################################
///
///    ГЛАВНЫЙ ИСХОДНЫЙ ФАЙЛ
///
//#################################
 
 
//подключаем нужные нам хидеры
#include "stdafx.h" //винда
#include "Template.h" //движок
#include "window.h" //окно
 
// TV3D - переменные
CTVEngine* pTV; //Девайс(Device),главный объект движка,его нужно создавать самым первым
CTVScene* pScene; //Объект сцены
CTVInputEngine* pInput; //Объект инпута(ввод с клавиатуры,мыш,джостик)
CTVLightEngine* pLight; //Объект источников света
 
 
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
 
	// Создаем девайс TV3D
	// Я уже говорил что его нужно создавать самым первым,это мы щас и сделаем=)
	pTV = new CTVEngine();
 
	// Создаем лог
	// начинаем вести лог перед выбором графического режима и созданием сцены,потомучто уже на этом этапе
        // могут быть сбои,и тогда мы сможем их отследить
	char path[256];
	char srchpath[256];
	
	GetModuleFileName(NULL,path,255); 
 
	AppPath(path,srchpath);	//получаем директорию программы
	
	pTV->SetDebugMode(true, true);
	pTV->SetDebugFile(strcat(srchpath, "\\debugfile.txt")); // наш лог будет иметь имя debugfile.txt и хранится в директории программы
 
 
	// Выбор графического режима.Эта функция новая,моя,ее нет в SDK
        // int pTVCreateWindow(CTVEngine* pTVDevice, char* window_name, int width, int height, int depth, bool fullscreen = false, bool vsync = false)
	pTVCreateWindow(pTV,"hi",640,480,32,false);
 
 
	// Ставим автоизменение размера вьювпорта,чтобы если пользователь изменит размеры окна
	// изменялся и размер изображения,эта функция крайне желательна
	pTV->GetViewport()->SetAutoResize(true);
 
	// будем показывать фпс в левом верхнем углу экрана
	pTV->DisplayFPS(true);
 
	// Выбираем тип системы углов
	pTV->SetAngleSystem(cTV_ANGLE_DEGREE);
 
	// Создаем сцену,через нее и будут создаваться примитивы и грузиться модели	
	pScene = new CTVScene();
	
	// Создаем инпут
	pInput = new CTVInputEngine();
 
	// Наш инпут будет перехватывать события с клавиатуры и мышки
	pInput->Initialize(true, true);
	
 
	// Создаем кубик
	 CTVMesh* Mesh;
	 Mesh = pScene->CreateMeshBuilder("cube");// и даем ему название cube
	 Mesh->CreateBox(2,2,2);
	 
	 // Позиция и вектор проекции камеры
	 pScene->SetCamera(-5,5,-5,0,1,0);
	
 
	bDoLoop = true;
 
 
	// ГЛАВНЫЙ ЦИКЛ
	while (bDoLoop) 
	{
		// Собственно тут будет происходить обработка нажатых клавиш,рендеринг мешей и т д
		if(GetFocus() == formHWND)
		{
                        // Очищаем НЕ только Z-буфер,иначе 2д(текст и 2д графика) будет рисоваться со шлейфом
			pTV->Clear(false);
 
			// Рисуем ВСЕ
			pScene->RenderAll(true);
 
                        // Сам рендер
			pTV->RenderToScreen();
			
			// Если нажали Esc,то выходим из программы
			if(pInput->IsKeyPressed(cTV_KEY_ESCAPE)) { SendMessage(formHWND, WM_DESTROY, 0, 0); }
		
		
		} 
		else 
		{
			// Обрабатываем сообщения не так часто.как отдаем(возрастаем быстродействие проги)
			Sleep(100);
		}
		
                //обновление нашего окошка
		BOOL peek = PeekMessage(&msg, NULL, 0, 0, TRUE);
 
		if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}
 
	return (int) msg.wParam;
}

Всю работу с окнами я убрал в window.h,чтобы не мешалось,заодно написал упрощеную функцию выбора графического режима,вот window.h:

//###################################
//
//  WINDOWS CREATE FUNCTIONS
//
//###################################
 
 
#include "stdafx.h"
 
#include "Template.h"
 
extern CTVEngine* pTV;
 
#define MAX_LOADSTRING 100
 
HWND formHWND;
bool bDoLoop;
 
// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;
 
// Global Variables:
HINSTANCE hInst;								// current instance
TCHAR szWindowClass[MAX_LOADSTRING];			// the main window class name
 
// Forward declarations of functions included in this code module:
ATOM				MyRegisterClass(HINSTANCE hInstance);
BOOL				InitInstance(HINSTANCE hInstance, int nCmdShow,int width,int height,char* winname);
LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
 
 
void AppPath(char* PathOfFile, char* ret_Path)
{							
	char* found = strrchr(PathOfFile, '\\');
	if(!found)
	{
		// check with '/' path format
		found = strrchr(PathOfFile, '/');
		if(!found)
		{
			// no path herre it's just a file.
			// so just blank output
			ret_Path[0] = 0;
		}
		else
		{
			// copy just a part of the string
			int size = (int)found - (int)PathOfFile + 1;
			strncpy(ret_Path, PathOfFile, size);
			ret_Path[size] = 0;
		}
 
	}
	else
	{
		// copy just a part of the string
		int size = (int)found - (int)PathOfFile + 1;
		strncpy(ret_Path, PathOfFile, size);
		ret_Path[size] = 0;
	}		
}
 
 
//
//  FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
//
//  PURPOSE:  Processes messages for the main window.
//
//  WM_PAINT	- Paint the main window
//  WM_DESTROY	- post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message) 
	{
	case WM_DESTROY:
		// Stop the loop.
		bDoLoop = false;
 
		// Free TV:
		delete(pTV);
		pTV = NULL;		
		
 
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}
 
 
//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
//  COMMENTS:
//
//    This function and its usage are only necessary if you want this code
//    to be compatible with Win32 systems prior to the 'RegisterClassEx'
//    function that was added to Windows 95. It is important to call this function
//    so that the application will get 'well formed' small icons associated
//    with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX wcex;
 
	wcex.cbSize = sizeof(WNDCLASSEX); 
 
	wcex.style			= 0;
	wcex.lpfnWndProc	= (WNDPROC)WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= LoadIcon(hInstance, (LPCTSTR)IDI_TEMPLATE);
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= NULL;
	wcex.lpszMenuName	= NULL;
	wcex.lpszClassName	= szWindowClass;
	wcex.hIconSm		= LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
 
	return RegisterClassEx(&wcex);
}
 
//
//   FUNCTION: InitInstance(HANDLE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow,int width,int height,char* winname)
{
   HWND hWnd;
 
   hInst = hInstance; // Store instance handle in our global variable
 
   hWnd = CreateWindow(szWindowClass, winname, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, width, height, NULL, NULL, hInstance, NULL);
 
	
   // Store the Created Window's hWnd in a glboal HWND variable.
   formHWND = hWnd;
 
   if (!hWnd)
   {
      return FALSE;
   }
 
   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);
 
   return TRUE;
}
 
 
int pTVCreateWindow(CTVEngine* pTVDevice, char* window_name, int width, int height, int depth, bool fullscreen = false, bool vsync = false)
{		
	// Initialize global strings
	LoadString(hInst, IDC_TEMPLATE, szWindowClass, MAX_LOADSTRING);
	MyRegisterClass(hInst);
 
	// Perform application initialization:
	if (!InitInstance (hInst, 1,width,height,window_name)) 
	{
			return FALSE;
	}
 
	hAccelTable = LoadAccelerators(hInst, (LPCTSTR)IDC_TEMPLATE);
 
	//если выбран полный экран
	if (fullscreen)
	{
		//грузим в полноэкранном режиме
		pTVDevice->Init3DFullscreen(width,height,depth,true,vsync);
 
		//из-за странного бага,при котором при запуске в полном экране появлялось еще одно окно,которое
		//выходило на передний план,это окно пришлось убивать,чем мы щас и займемся
		//получаем хендл этого окна
		HWND h =  GetFocus();
		//закрываем это окно
		CloseWindow(h);
 
		//делаем активным 'окно' движка,в котором рендерится все
		SetFocus(formHWND);
	}
	else
	{
		//иначе грузим в оконном режиме
		pTVDevice->Init3DWindowed(formHWND, true);
	}
 
	return TRUE;
}

а в Template.h я ‘положил’ заинклудивание всего двига(в данном случае не всего):

//##############################################
/////
/////   ALL INGINE INCLUDES  
/////
//##############################################
 
#pragma once
 
#include "resource.h"
 
#include "cppdll/CTVCamera.h" 
#include "cppdll/CTVEngine.h" 
#include "cppdll/CTVGlobals.h" 
#include "cppdll/CTVInputEngine.h" 
#include "cppdll/CTVLandscape.h" 
#include "cppdll/CTVLightEngine.h" 
#include "cppdll/CTVMaterialFactory.h" 
#include "cppdll/CTVMesh.h" 
#include "cppdll/CTVPath.h" 
#include "cppdll/CTVScene.h" 
#include "cppdll/CTVScreen2DImmediate.h" 
#include "cppdll/CTVScreen2DText.h" 
#include "cppdll/CTVTextureFactory.h" 
#include "cppdll/CTVViewport.h" 
#include "cppdll/HelperFunctions.h" 
#include "cppdll/tv_types.h"

вот и все=)

 
get_started_simple_template_rus.txt · Last modified: 2013/11/22 13:32