Войти
ПрограммированиеСтатьиГрафика

Делаем простой редактор бликов. (3 стр)

Функциональность интерфейса

Здесь мы рассмотрим базовые понятия чистого Win32 программирования, поэтому если вы ждете от VC++ такой же простоты как от Delphi или VB, то вы ошибаетесь. Я не спорю, что есть уже много самопальных облегчителей создания проектов под VC++, но мы попробуем это сделать сами, без использования чего-то стороннего, также мы не будем использовать MFC.

Частый вопрос начинающих о Win32 программировании - "как мне сделать visible=false"(ну или типа того). Ведь в VC++ нет таких классов как в Delphi, даже хваленый MFC этого не умеет. Хотя бы потому, что язык C не располагает, так сказать, Read&Write переменными класса. Ну и черт с ними, это можно легко переделать под Visible ( false ); То есть вызывать не переменные, а сразу функции. Но и мы такого не будем использовать, потому, как это, нужно хотя бы сделать, а для такого небольшого проекта это не нужно.

Все операции с визуальными компонентами (кнопки, текст, списки, и прочее) оперируют с главным параметром - это переменная типа HWND. Зная этот параметр - можно проделать с объектом все, на что способен Win32 API. Напрямую получить этот параметр нельзя, так как VC++ не располагает никакими классами объектов, а уж тем более так называемым Code Generator'ом (это когда VC может часть работы ( 1% ) сделать за вас). Это есть в MFC (и то не слишком развито, воды очень много). Но для таких дел был специально заготовлен макрос GetDlgItem ( HWND, ID ). Где первый параметр это HWND вашего окна (вы его должны знать по любому), а второй параметр это идентификатор того объекта HWND которого вы хотите получить. В окне Properties можно назначить идентификаторы ( ID ) любым компонентам которые есть у вас на форме и самой форме тоже.

Теперь, зная HWND объекта, вы можете делать все что хотите, к примеру, можно поставить текст на том компонент, который вы хотите, вызвав

SetWindowText ( GetDlgItem(hWnd, IDC_LABEL1),   text );
IDC_LABEL1 - идентификатор объекта.
text - переменная, где хранится сам текст.

Как можно заметить это и есть аналог Delphi'вского Caption := text;

В основном все операции идут со списками. Более подробно как с ними работать вы можете посмотреть в MSDN или же в исходнике нашего супер редактора.

Сохранение и загрузка.

Сохранение мы будем делать через стандартные WIn32 DialogBox, такие как открытие файла, сохранение файла. Попутно расскажу про диалог выбора цветов.

Сохраняем. Функция по вызову диалогового окна сохранения файлов выглядит так:

void SaveProject ( void )
{
  OPENFILENAME ofn;
  char szFile[260];
  char szDir[320];

  GetCurrentDirectory ( 320, szDir );
  GetWindowText ( GetDlgItem(Opt.hWnd,IDC_PNAME), szFile, 260 );
  strcat ( szFile, ".lns" );
  strcat ( szDir, "/Projects" );

  ZeroMemory(&ofn, sizeof(OPENFILENAME));
  ofn.lStructSize = sizeof(OPENFILENAME);
  ofn.hwndOwner = Opt.hWnd;
  ofn.lpstrFile = szFile;
  ofn.nMaxFile = sizeof(szFile);
  ofn.lpstrFilter = "Lens file\0*.LNS\0";
  ofn.nFilterIndex = 1;
  ofn.lpstrFileTitle = NULL;
  ofn.nMaxFileTitle = 0;
  ofn.lpstrInitialDir = szDir;
  ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

  if ( GetSaveFileName ( &ofn ))
  {
    SaveLens ( ofn.lpstrFile );
  }
}

Все просто, мы заполняем поля структуры типа OPENFILENAME необходимыми значениями, затем открываем диалоговое окно сохранения файлов вызовом функции GetSaveFileName с аргументом типа OPENFILENAME. При корректной работе функции она должна вернуть путь к файлу, сам путь лежит в переменной lpstrFile структуры типа OPENFILENAME.

Этот путь мы направляем в функцию сохранения наших данных на диск.

void SaveLens ( char *filename )
{
  FILE *f = NULL;
  f = fopen ( filename, "wb" );
  if ( f == NULL )
  {
    MessageBox ( 0, "Cant save file", "Error", MB_ICONERROR|MB_OK );
    return;
  }

  const char SIGNATURE[] = "LNS";
  fwrite ( SIGNATURE, sizeof(const char), sizeof(SIGNATURE), f );
  fwrite ( &proj,     sizeof(proj), 1, f);
  fclose ( f );
}

Стандартная запись бинарных файлов на диск. Есть даже сигнатура, ее нужно использовать для быстрой проверки типа файла, ну, к примеру, если у вас файл с расширением *.map, то убедиться, что вам не подсунули другой map (таких форматов полно, и еще больше редакторов, у которых такие же форматы) можно через сигнатуру, она должна быть уникальна. Но в нашем случае это не нужно, так как мы ничего не продаем, ничего не покупаем, поэтому, защита такого рода у нас не уместна. А вообще эта защита заключается в вызове функции strcmp и одного if.

Точно также мы поступаем и с чтением данных. Функция GetOpenFileName запишет в поле lpstrFile структуры OPENFILENAME путь к файлу, а вам всего лишь нужно передать его в вашу функцию чтения данных.

Теперь пару слов о диалоге выбора цвета. Функция, которая это делает.

vector4 GetNewColor ( void )
{
  CHOOSECOLOR cc;
  static COLORREF acrCustClr[16];
  static DWORD rgbCurrent;
  vector4 color;
  VECTOR4_SET ( color, 0.0f );

  ZeroMemory(&cc, sizeof(CHOOSECOLOR));
  cc.lStructSize = sizeof(CHOOSECOLOR);
  cc.hwndOwner = Opt.hWnd;
  cc.lpCustColors = (LPDWORD) acrCustClr;
  cc.rgbResult = rgbCurrent;
  cc.Flags = CC_FULLOPEN | CC_RGBINIT;

  if ( ChooseColor ( &cc ))
  {
    rgbCurrent = cc.rgbResult;
    color.v[0] = ((float)GetRValue ( rgbCurrent )) / 255.0f;
    color.v[1] = ((float)GetGValue ( rgbCurrent )) / 255.0f;
    color.v[2] = ((float)GetBValue ( rgbCurrent )) / 255.0f;
    color.v[3] = 1.0f;
  }

  return color;
}

Почти, как и с сохранением, открытием файлов. Мы заполняем поля структуры CHOOSECOLOR и передаем все это дело в функцию ChooseColor. После выбора цвета в появившемся диалоге, функция запишет цвет в переменную rgbResult структуры CHOOSECOLOR. Чтобы его прочитать воспользуемся макросами GetRValue, GetGValue, GetBValue. Названия говорят сами за себя, эти макросы вытаскивают значения цветов из rgbResult. Мы немного улучшим эту часть программы, добавив деление на 255, тем самым преведя байтовое число к интервалу 0..1. Результат запишем в переменную color типа vector4 (у вас, скорее всего свой тип). Альфа составляющую цвета поставим на 1, чтобы блики были видны. От этого вытекает небольшой трюк - программа не умеет НЕ рисовать некоторые блики, но этого можно добиться, поставив блику полностью черный цвет.

Вот и все, не забудем удалить все текстуры и контексты после работы программы.

Заключение.

Этот маленький редактор - настоящая дорога в светлое будущее, и когда-нибудь он станет убийцей таких редакторов как UnrealEditor. Шутка конечно.

На самом деле этот редактор мог бы послужить некоторой довеской к действительно мощному компоновщику уровней. Ведь блики не будешь делать в 3DSMax, а в таком редакторе вполне можно. Данная программа всего лишь пример того, что можно сделать без использования Delphi или VB.

За Русский GAMEDEV,  УРА!!!

[gurl=http://www.gamedev.ru/articles/opengl/20030326.zip]Пример[/url]. Исходный код проекта написан на VisualC++.NET, но не содержит никаких "проектных наворотов", даже lib'ы подключаются программно (исключение - #pragma once). Поэтому может быть откомпилен и в других редакторах. В папке Projects есть уже готовые проекты.

Страницы: 1 2 3

#эффекты, #OpenGL, #tools

26 марта 2003

Комментарии [3]