Функция CreateScene() приложения Spotlight отвечает за создание сеток и прожектора, а также устанавливает функцию обратного вызова, использующуюся для анимации прожектора. Код функции SpotlightWin::CreateScene() представлен в листинге6.5.
Листинг 6.5. Функция SpotlightWin::CreateScene() |
BOOL SpotlightWin::CreateScene() { //----- СЕТКИ -------- D3DRMLOADRESOURCE resinfo; resinfo.hModule = NULL; resinfo.lpName = MAKEINTRESOURCE(IDR_SPHEREMESH); resinfo.lpType = "MESH"; LPDIRECT3DRMMESHBUILDER builder; d3drm->CreateMeshBuilder(&builder); builder->Load(&resinfo, NULL, D3DRMLOAD_FROMRESOURCE, NULL, NULL); builder->SetColorRGB(D3DVALUE(1.0), D3DVALUE(0.0), D3DVALUE(0.0)); builder->CreateMesh(&mesh1); builder->SetColorRGB(D3DVALUE(0.0), D3DVALUE(1.0), D3DVALUE(0.0)); builder->CreateMesh(&mesh2); builder->SetColorRGB(D3DVALUE(0.0), D3DVALUE(0.0), D3DVALUE(1.0)); builder->CreateMesh(&mesh3); builder->Release(); builder = 0; //----- ФРЕЙМЫ ДЛЯ СЕТОК -------- LPDIRECT3DRMFRAME frame1; d3drm->CreateFrame(scene, &frame1); frame1->SetPosition(scene, D3DVALUE(-2), D3DVALUE(0), D3DVALUE(0)); frame1->AddVisual(mesh1); frame1->Release(); frame1 = 0; LPDIRECT3DRMFRAME frame2; d3drm->CreateFrame(scene, &frame2); frame2->SetPosition(scene, D3DVALUE(2), D3DVALUE(0), D3DVALUE(0)); frame2->AddVisual(mesh2); frame2->Release(); frame2 = 0; LPDIRECT3DRMFRAME frame3; d3drm->CreateFrame(scene, &frame3); frame3->SetPosition(scene, D3DVALUE(0), D3DVALUE(0), D3DVALUE(2)); frame3->AddVisual(mesh3); frame3->Release(); frame3 = 0; //------- ПРОЖЕКТОР ------ d3drm->CreateLightRGB(D3DRMLIGHT_SPOT, D3DVALUE(0.8), D3DVALUE(0.8), D3DVALUE(0.8), &spotlight); OnBeamNormal(); //------ ФРЕЙМ ПРОЖЕКТОРА -------- LPDIRECT3DRMFRAME lightframe; d3drm->CreateFrame(scene, &lightframe); lightframe->SetPosition(scene, D3DVALUE(0), D3DVALUE(10), D3DVALUE(-10)); lightframe->SetOrientation(scene, D3DVALUE(0), D3DVALUE(-1), D3DVALUE(1), D3DVALUE(0), D3DVALUE(1), D3DVALUE(0)); lightframe->AddLight(spotlight); lightframe->AddMoveCallback(MoveLight, NULL); lightframe->Release(); lightframe = 0; //------ КАМЕРА ------ d3drm->CreateFrame(scene, &camera); camera->SetPosition(scene, D3DVALUE(0), D3DVALUE(6), D3DVALUE(-6)); camera->SetOrientation(scene, D3DVALUE(0), D3DVALUE(-1), D3DVALUE(1.1), D3DVALUE(0), D3DVALUE(1), D3DVALUE(0)); d3drm->CreateViewport(device, camera, 0, 0, device->GetWidth(), device->GetHeight(), &viewport); return TRUE; } |
Функция CreateScene() выполняет следующие действия:
Давайте взглянем на код, реализующий первый этап:
D3DRMLOADRESOURCE resinfo; resinfo.hModule = NULL; resinfo.lpName = MAKEINTRESOURCE(IDR_SPHEREMESH); resinfo.lpType = "MESH"; LPDIRECT3DRMMESHBUILDER builder; d3drm->CreateMeshBuilder(&builder); builder->Load(&resinfo, NULL, D3DRMLOAD_FROMRESOURCE, NULL, NULL); builder->SetColorRGB(D3DVALUE(1.0), D3DVALUE(0.0), D3DVALUE(0.0)); builder->CreateMesh(&mesh1); builder->SetColorRGB(D3DVALUE(0.0), D3DVALUE(1.0), D3DVALUE(0.0)); builder->CreateMesh(&mesh2); builder->SetColorRGB(D3DVALUE(0.0), D3DVALUE(0.0), D3DVALUE(1.0)); builder->CreateMesh(&mesh3); builder->Release(); builder = 0;В самом начале выполняется объявление и инициализация экземпляра структуры D3DRMLOADRESOURCE. Структура resinfo идентифицирует сферическую сетку, которую мы будем использовать.
Далее объявляется указатель на интерфейс Direct3DRMMeshBuilder с именем builder. Для инициализации этого указателя вызывается функция CreateMeshBuilder() интерфейса Direct3DRM. Функция Load() применяется для загрузки сетки. Адрес подготовленной ранее структуры resinfo передается функции Load() в ее первом аргументе.
Затем инициализируются три указателя на интерфейс Direct3DRMMesh. Каждый из них инициализируется с помощью функции CreateMesh() интерфейса Direct3DRMMeshBuilder. После каждого вызова функции CreateMesh() конструктору сеток назначается новый цвет. В результате будут созданы три сетки различных цветов, каждая из которых представлена интерфейсом Direct3DRMMesh. Сразу после создания этих трех сеток указатель builder освобождается.
На втором этапе работы функции CreateScene() выполняется создание и размещение трех фреймов, по одному для каждой из сеток:
LPDIRECT3DRMFRAME frame1; d3drm->CreateFrame(scene, &frame1); frame1->SetPosition(scene, D3DVALUE(-2), D3DVALUE(0), D3DVALUE(0)); frame1->AddVisual(mesh1); frame1->Release(); frame1 = 0; LPDIRECT3DRMFRAME frame2; d3drm->CreateFrame(scene, &frame2); frame2->SetPosition(scene, D3DVALUE(2), D3DVALUE(0), D3DVALUE(0)); frame2->AddVisual(mesh2); frame2->Release(); frame2 = 0; LPDIRECT3DRMFRAME frame3; d3drm->CreateFrame(scene, &frame3); frame3->SetPosition(scene, D3DVALUE(0), D3DVALUE(0), D3DVALUE(2)); frame3->AddVisual(mesh3); frame3->Release(); frame3 = 0;Каждый фрейм создается функцией CreateFrame() интерфейса Direct3DRM, после чего помещается на предназначенное ему место сцены. Третий фрейм помещается за первыми двумя. Каждая из созданных ранее сеток присоединяется к одному из фреймов с помощью функции AddVisual(). После того, как сетка присоединена к фрейму, указатель на фрейм освобождается.
На третьем этапе, код которого показан ниже, создается прожектор:
d3drm->CreateLightRGB(D3DRMLIGHT_SPOT, D3DVALUE(0.8), D3DVALUE(0.8), D3DVALUE(0.8), &spotlight); OnBeamNormal();Вначале для инициализации указателя spotlight вызывается функция CreateLightRGB() интерфейса Direct3DRM. Константа D3DRMLIGHT_SPOT указывает, что мы создаем прожектор. Для красной, зеленой и синей составляющих цвета мы указываем значение 0.8, чтобы цвет нашего источника света был светло-серым.
Затем вызывается функция OnBeamNormal(), являющаяся обработчиком сообщения для пункта Normal меню Beam. Здесь мы вызываем ее для инициализации значений угла светового пятна и угла области освещенности. Чуть позже код функции OnBeamNormal() будет рассмотрен более подробно.
На четвертом этапе создается фрейм к которому будет присоединен прожектор:
LPDIRECT3DRMFRAME lightframe; d3drm->CreateFrame(scene, &lightframe); lightframe->SetPosition(scene, D3DVALUE(0), D3DVALUE(10), D3DVALUE(-10)); lightframe->SetOrientation(scene, D3DVALUE(0), D3DVALUE(-1), D3DVALUE(1), D3DVALUE(0), D3DVALUE(1), D3DVALUE(0)); lightframe->AddLight(spotlight); lightframe->AddMoveCallback(MoveLight, NULL); lightframe->Release(); lightframe = 0;Указатель lightframe инициализируется функцией CreateFrame() интерфейса Direct3DRM. Функция SetPosition() применяется, чтобы поместить фрейм в точку, расположенную на 10 единиц выше и на 10 единиц дальше начала координат. Затем вызывается функция SetOrientation(), чтобы направить фрейм на начало координат.
После этого созданный ранее прожектор присоединяется к новому фрейму с помощью функции AddLight(). Кроме того, с помощью функции AddMoveCallback() устанавливается функция обратного вызова MoveLight(). После выполнения всех описанных действий указатель lightframe освобождается.
На заключительном, пятом, этапе работы функции CreateScene() осуществляется создание порта просмотра:
d3drm->CreateFrame(scene, &camera); camera->SetPosition(scene, D3DVALUE(0), D3DVALUE(6), D3DVALUE(-6)); camera->SetOrientation(scene, D3DVALUE(0), D3DVALUE(-1), D3DVALUE(1.1), D3DVALUE(0), D3DVALUE(1), D3DVALUE(0)); d3drm->CreateViewport(device, camera, 0, 0, device->GetWidth(), device->GetHeight(), &viewport);Сначала инициализируется фрейм camera. Затем этот фрейм перемещается от начала координат на шесть единиц вверх и на шесть единиц ближе к зрителю. Функция SetOrientation() применяется, чтобы направить лицевую грань фрейма на начало координат. И, в самом конце, вызывается функция CreateViewport() интерфейса Direct3DRM для инициализации указателя viewport.