Последние записи
- Преобразовать массив байт в вещественное число (single)
- TChromium (CEF3), сохранение изображений
- Как в Delphi XE обнулить таймер?
- Изменить цвет шрифта TextBox на форме
- Ресайз PNG без потери прозрачности
- Вывод на печать графического файла
- Взаимодействие через командную строку
- Перенести программу из Delphi в Lazarus
- Определить текущую ОС
- Автоматическая смена языка (раскладки клавиатуры)
Интенсив по Python: Работа с API и фреймворками 24-26 ИЮНЯ 2022. Знаете Python, но хотите расширить свои навыки?
Slurm подготовили для вас особенный продукт! Оставить заявку по ссылке - https://slurm.club/3MeqNEk
Online-курс Java с оплатой после трудоустройства. Каждый выпускник получает предложение о работе
И зарплату на 30% выше ожидаемой, подробнее на сайте академии, ссылка - ttps://clck.ru/fCrQw
25th
Авг
УРОК 14 ИСПОЛЬЗОВАНИЕ ССЫЛОК В C++
Из урока 10 вы узнали, как изменять параметры внутри функции с помощью указателей. Для использования указателей вы должны предварять имена переменных-указателей звездочкой. Использование указателей досталось в «наследство» от языка С. Чтобы упростить процесс изменения параметров, С++ вводит такое понятие как ссылка. Как вы узнаете из этого урока, ссылка представляет собой псевдоним (или второе имя), который ваши программы могут использовать для обращения к переменной. К концу данного урока вы освоите следующие основные концепции:
• Для объявления и инициализации ссылки внутри программы объявите переменную, размещая амперсанд (&) сразу же после типа переменной, и затем используйте оператор присваивания для назначения псевдонима, например int& alias_name = variable’,.
• Ваши программы могут передавать ссылки в функцию в качестве параметров, а функция, в свою очередь, может изменять соответствующее значение параметра, не используя указателей.
• Внутри функции вам следует объявить параметр как ссылку, размещая амперсанд (&) после типа параметра, затем можно изменять значение параметра внутри функции без помощи указателей.Как вы узнаете, использование указателей очень упрощает изменение значений параметров внутри функции.
ССЫЛКА ЯВЛЯЕТСЯ ПСЕВДОНИМОМ
Ссылка C++ позволяет создать псевдоним (или второе имя) для переменных в вашей программе. Для объявления ссылки внутри программы укажите знак амперсанда (&) непосредственно после типа параметра. Объявляя ссылку, вы должны сразу же присвоить ей переменную, для которой эта ссылка будет псевдонимом, как показано ниже:
int& alias_name = variable; //—> Объявление ссылки
После объявления ссылки ваша программа может использовать или переменную , или ссылку:
alias_name = 1001;
variable = 1001;
Следующая программа SHOW_REF.CPP создает ссылку с именемalias_name и присваивает псевдониму переменную number. Далее программа использует как ссылку, так и переменную:
#include <iostream.h>
void main(void)
{
int number = 501;
int& alias_name = number; // Создать ссылку
cout << «Переменная number содержит » << number << endl;
cout << «Псевдоним для number содержит » << alias_name << endl;
alias_name = alias_name + 500;
cout << «Переменная number содержит » << number << endl;
cout << «Псевдоним для number содержит » << alias_name << endl;
}
Как видите, программа прибавляет 500 к ссылке alias_name. В итоге программа прибавляет 500 также и к соответствующей переменнойnumber, для которой ссылка служит псевдонимом или вторым именем. Когда вы откомпилируете и запустите эту программу, на вашем экране появится следующий вывод:
С:\> SHOW_REF <ENTER>
Переменная number содержит 501
Псевдоним для number содержит 501
Переменная number содержит 1001
Псевдоним для number содержит 1001
В общем случае использование ссылки таким образом, как только что было показано, создает трудности для понимания. Однако вы увидите, что использование ссылок значительно упрощает процесс изменения параметров внутри функции.
Объявление ссылкиСсылка C++ представляет собой псевдоним (второе имя), которое ваши программы могут использовать для обращения к переменной. Для объявления ссылки поставьте амперсанд (&) сразу же после типа переменной, а затем укажите имя ссылки, за которым следует знак равенства и имя переменной, для которой ссылка является псевдонимом:
float& salary_alias = salary;
ИСПОЛЬЗОВАНИЕ ССЫЛОК В КАЧЕСТВЕ ПАРАМЕТРОВ
Основное назначение ссылки заключается в упрощении процесса изменения параметров внутри функции. Следующая программа REFERENC.CPP присваивает ссылку с именем number_alias переменнойnumber. Программа передает ссылку на переменную в функциюchange_value, которая присваивает переменной значение 1001:
#include <iostream.h>
void change_value(int &alias)
{
alias = 1001;
}
void main(void)
{
int number;
int& number_alias = number;
change_value(number_alias);
out << «Переменная number содержит » << number << endl;
}
Как вы видите, программа передает ссылку в функцию change_value. Если вы рассмотрите объявление функции, вы обнаружите, что change_valueобъявляет параметр alias как ссылку на значение типа int.
void change_value(int& alias)
Внутри функции change_value можете изменять значение параметра без помощи указателя. В результате звездочка (*) не используется и операция внутри функции становится легче для понимания.
Использование комментариев для объяснения ссылок внутри ваших программБольшинство программистов C++ знакомы с языком программирования С, и они привыкли использовать указатели внутри функции, если необходимо изменить значение параметра. В результате, если такие программисты не видят указатели внутри функций, которые используют ссылки, они могут предположить, что значения параметров не изменяются. Для предотвращения подобных промахов не забывайте размещать несколько комментариев до и внутри функций, которые изменяют параметры с помощью ссылок. В таком случае программисты С лучше поймут работу ваших функций.
Рассмотрим второй пример
В уроке 10 вы использовали следующую функцию для перестановки двух значений с плавающей точкой:
void swap_values(float *a, float *b)
{
float temp;
temp = *a;
*a = *b;
*b = temp;
}
Как видите, функция комбинирует переменные-указатели с переменными-неуказателями. Следующая программа SWAP_REF.CPP использует ссылки на значения с плавающей точкой для упрощения функции:
#include <iostream.h>
void swap_values(float& a, float& b)
{ float temp;
temp = a;
a = b;
b = temp;
}
void main(void)
{ float big = 10000.0;
float small = 0.00001;
float& big_alias = big;
float& small_alias = small;
swap_values(big_alias, small_alias);
cout << «Big содержит » << big << endl;
cout << «Small содержит » << small << endl;
}
Как видите, функцию swap_values сейчас легче понять, однако ваша программа имеет теперь два дополнительных имени (ссылки big_alias и small_alias), за которыми вы должны следить.
ПРАВИЛА РАБОТЫ СО ССЫЛКАМИ
Ссылка не является переменной. Один раз присвоив значение ссылке, вы уже не можете ее изменить. Кроме того в отличие от указателей вы не можете выполнить следующие операции над ссылками:
• Вы не можете получить адрес ссылки, используя оператор адреса C++.
• Вы не можете присвоить ссылке указатель.
• Вы не можете сравнить значения ссылок, используя операторы сравнения C++.• Вы не можете выполнить арифметические операции над ссылкой, например добавить смещение.•Вы не можете изменить ссылку.По мере использования объектно-ориентированного программирования на C++ вы вернетесь к ссылкам.Использование ссылок для изменения параметров функцииИз урока 10 вы узнали, что ваши программы с помощью указателей могут изменять значение параметров внутри функции. Для изменения параметра вы должны передать его адрес в функцию. Чтобы получить адрес параметра, используйте оператор адреса C++ (&). В свою очередь функция использует переменные-указатели (которые хранят адрес памяти). Для объявления переменной-указателя внутри функции предваряйте имя параметра звездочкой (*). Чтобы изменить или использовать значение параметра внутри функции, предваряйте каждое обращение к имени этого параметра оператором разыменования C++ (*). К сожалению, многие операции внутри функции комбинируют переменные-указатели и переменные-неуказатели.
Ссылки C++ упрощают процесс изменения параметров функции, избавляя от операторов, которые смешивают переменные-указатели и переменные-неуказатели.
ЧТ0 ВАМ НЕОБХОДИМО ЗНАТЬ
Из этого урока вы узнали, как использовать ссылки C++ для создания псевдонима или второго имени переменной. Использование ссылок может упростить функции, изменяющие значения параметров. Из урока 15 вы узнаете, что C++ позволяет вам задавать значения по умолчанию для параметров функции. При вызове функции программа может опускать значения одного или нескольких параметров и функция будет использовать значения по умолчанию. До изучения урока 15 убедитесь, что вы освоили следующие основные концепции:
-
- Ссылка C++ является псевдонимом (или вторым именем) переменной.
- Для объявления ссылки поместите знак амперсанда (&) непосредственно после типа переменной, а затем укажите имя ссылки, за которым следует знак равенства и имя переменной, для которой ссылка является псевдонимом.
- Если вы однажды присвоили ссылке значение, вы не можете его изменить.
- Вам следует помещать несколько комментариев до и внутри функций, которые используют ссылки для изменения значений параметра, чтобы другие программисты, читающие ваш код, сразу обратили, на это внимание.
- Чрезмерное использование ссылок может привести к слишком трудному для понимания программному коду.
Предыдущий урок | Следующий урок
Programming articles
Создание сайтов на шаблонах
Множество вариантов работы с графикой на канве
Шифруем файл с помощью другого файла
Перехват API функций — Основы
Как сделать действительно хороший сайт
Создание почтового клиента в Delphi 7
Применение паскаля для
решения геометрических задач
Управление windows с помощью Delphi
Создание wap сайта
Операционная система unix, термины и понятия
SQL враг или друг
Возникновение и первая редакция ОС UNIX
Оптимизация проекта в Delphi
Ресурсы, зачем нужны ресурсы
Термины программистов 20 века
Советы по созданию собственного сайта с нуля
Шифруем файл с помощью пароля
Фракталы — геометрия природы
Crypt — Delphi программа для шифрования
Рассылка, зачем она нужна и как ее организовать?
Учебник по C++ для начинающих программистов
Уроки для изучения ассемблера
Загадочный тип PCHAR
Средства по созданию сайтов
Операторы преобразования
классов is и as
Borland Developer studio 2006. Всё в одном
Создание базы данных в Delphi, без сторонних БД
Software engineering articles
25th
УРОК 10 ИЗМЕНЕНИЕ ЗНАЧЕНИЙ ПАРАМЕТРОВ
Из урока 9 вы узнали, как разделить ваши программы на небольшие легко управляемые части, называемые функциями. Как вы уже знаете, программы могут передавать информацию (параметры) функциям. Представленные в уроке 9 программы использовали или выводили значения параметров, но не меняли их. Из этого урока вы узнаете, как изменить значение параметра в функции. Вы обнаружите, что для изменения параметров в функции фактически требуется больше шагов, чем можно предположить. Однако этот урок обучит вас всем шагам, которые необходимо знать. К концу данного урока вы освоите следующие основные концепции:
• Если функция не использует указатели или ссылки, она не может изменить значение параметра.
• Для изменения значения параметра функция должна знать адрес параметра в памяти.
• Оператор адреса C++ (&) позволяет вашей программе определить адрес переменной в памяти.
• Когда ваша программа узнает адрес памяти, она сможет использовать операцию разыменования C++ (*) для определения значения, хранимого по данному адресу.
• Если программе нужно изменить значение параметров функции, программа передает в функцию адрес параметра.
Изменение значения параметра функции представляет собой обычную операцию. Экспериментируйте с программами, представленными в этом уроке, чтобы убедиться, что вы полностью освоили этот процесс.
25th
УРОК 33. ДОПОЛНИТЕЛЬНЫЕ ВОЗМОЖНОСТИ CIN И COUT
На всем протяжении этой книги вы использовали выходной поток cout для вывода информации на экран дисплея. Аналогично, многие из ваших программ использовали входной поток cin для чтения информации с клавиатуры. Оказывается, cin и cout представляют собой классовые объекты, определяемые и создаваемые с помощью заголовочного файлаiostream.h. Как объекты cin и cout поддерживают различные операторы и операции. Из данного урока вы узнаете, как расширить возможности ввода и вывода, используя функции, встроенные в классы cin и cout. К концу этого урока вы освоите следующие основные концепции:
- Заголовочный файл iostream.h содержит определения классов, которые вы можете проанализировать, чтобы лучше понять потоковый ввод/вывод.
- Используя метод cout.width, ваши программы могут управлять шириной вывода.
- Используя метод cout.fill, ваши программы могут заменить пустые выходные символы (табуляцию и пробелы) некоторым определенным символом.
- Для управления количеством цифр, выводимых выходным потокомcout для значений с плавающей точкой, ваши программы могут использовать метод cout.setprecision.
- Для вывода и ввода по одному символу за один раз ваши программы могут использовать потоковые методы cout.put и cin.get.
- Используя метод cin.getline, ваши программы могут вводить целую строку за один раз.
Почти любая создаваемая вами на C++ программа будет использовать cout или cin для выполнения операций В/В (ввода/вывода). Выберите время для экспериментов с программами из этого урока.
25th
Делаем динамические тени на OPENGL. Часть 1
Здравствуйте. В этой статье я хочу рассмотреть создание движка динамического освещения с помощью графической библиотеки OpenGL. Писаться движок будет на Delphi, но это не мешает переписать его на любой другой язык, так как главное, рассматриваемое в статье, это алгоритмы…
Вадим Буренков
vadim_burenkov@mail.ru
Чтобы не тратить время на инициализацию OpenGL и избежать других проблем (например, с настройкой таймеров и рендера в текстуру) я буду использовать движок ZenGL [1]. Впрочем, от него нам многого не понадобится. Итак, приступим…
Инициализация OpenGL в ZenGL
Первым делом качаем ZenGL и создаем в нем простейшее приложение (вы можете найти его в папке LightEngine ресурсов статьи, там же вы найдете ZenGL):
код:
uses
zgl_main,
zgl_screen,
zgl_window,
zgl_timers,
zgl_textures,
zgl_textures_jpg,
zgl_sprite_2d,
zgl_mouse,
zgl_keyboard,
zgl_utils;
var
BackTex:zglPTexture; // текстура фона
bTiles:zglTTiles2D; // параметры тайлинга
procedure Init;
var n,j:integer;
begin
// отключаем очищение буфера
zgl_disable(COLOR_BUFFER_CLEAR );
// Тут можно выполнять загрузку основных ресурсов
// загрузка текстуры и настройка тайлинга
BackTex:=tex_LoadFromFile( ‘Back.jpg’,0,TEX_DEFAULT_2D);
// параметры тайлов фона
bTiles.Count.X:=7;
bTiles.Count.Y:=5;
bTiles.Size.W:=128;
bTiles.Size.H:=128;
SetLength(bTiles.Tiles,7,5);
&nfor fto=0 to 4 do
&nbsforbsp;&ntob>for j:=0 to 6 do bTiles.Tiles[j,n]:=1;
end;
procedure Draw;
begin
// Тут «рисуем» что угодно 🙂
tiles2d_Draw(BackTex,0,0,BTiles); // отрисовка фона
end;
procedure Update;
begin
// Тут выполняется обработка данных
if key_Press( K_ESCAPE ) then zgl_Exit;
// обновление клавиш
key_ClearState;
Mouse_ClearState;
end;
procedure Timer;
begin
// Будем в заголовке показывать количество кадров в секунду
wnd_SetCaption( ‘LightEngine [ FPS: ‘ + u_IntToStr( zgl_Get(
SYS_FPS ) ) + ‘ ]’ );
end;
procedure Quit;
begin
// Тут выполняется очищение данных
end;
Begin
// Создаем таймер с интервалом 1000мс.
timer_Add( @Timer, 1000 );
// Создаем таймер с интервалом 10мс.
timer_Add( @Update, 10 );
// Регистрируем процедуру, что выполнится сразу после
// инициализации ZenGL
zgl_Reg( SYS_LOAD, @Init );
// Регистрируем процедуру, где будет происходить рендер
zgl_Reg( SYS_DRAW, @Draw );
// Регистрируем процедуру, которая выполнится после завершения
// работы ZenGL
zgl_Reg( SYS_EXIT, @Quit );
// Устанавливаем заголовок окна
// Разрешаем курсор мыши
wnd_ShowCursor( TRUE );
// Указываем первоначальные настройки
scr_SetOptions( 800, 600, REFRESH_MAXIMUM, FALSE, FALSE );
// Инициализируем ZenGL
zgl_Init;
End.
При инициализации мы указываем процедуры в которых будут производится различные действия (инициализация/обработка/очищение) а также параметры окна.
В инициализации загружается текстура и настраивается тайлинг (количество и размер настроен так, чтобы текстура закрывала весь экран). В обработке обновляются состояния мыши и клавиатуры, а также стоит проверка на нажатие ESC. Процедура очищения пока пуста, так как ресурсы движка очищаются самостоятельно.
Другие непонятные процедуры можно посмотреть в справке, которая находится в папке doc движка. Чтобы при компиляции не возникло проблем необходимо указать расположение модулей движка в Project->Options- >Directories/Conditionals->SearchPath, а именно папки zengl/src и zengl/src/PasZLib (см. рис.1). Можно скомпилировать проект, увидеть вы должны следующее (см. рис.2).
Рис. 1. Пути
Рис. 2. Тайлинг
Немного теории
Теперь перейдем к теории вопроса. В движке мы должны реализовать два типа – источники света и объекты, которые отбрасывают тени (см. рис.3):
Рис. 3. Тень от объекта
Источник света обладает параметрами:
- положение
- радиус
- цвет
- интенсивность
Все объекты являются невыпуклыми многоугольниками. Они имеют:
- локальные координаты вершин
- мировые координаты вершин
- количество вершин
- положение
- угол поворота
Локальные координаты нужны, так как через положение и угол поворота объекта его можно разворачивать.
Для хранения данных об освещенности нам понадобятся два буфера размером в экран. Первый – альфа буфер. В него выводится круглый источник света (см. рис.4):
Рис. 4. Источник света
После этого альфа буфер рисуется во второй буфер – буфер аккумуляции. При этом используется аддитивный режим блендинга, то есть цвета смешиваются. В буфере мы получаем такую картинку (см. рис.5):
Рис. 5. Смешивание источников света
В нем светлые участки – там где свет, а темные – там где тьма. А теперь мы выводим буфер аккамуляции на экран с блендингом MULT. Получается так, что чем светлее цвет, тем он прозрачнее (см. рис.6):
Рис. 6. Рисование с блендингом MULT
Как же делаются тени от объектов? При выводе источника света в альфа буфер на него рисуется форма тени черным цветом. Получается что от круга света «отрезают» кусок (см. рис.7):
Рис. 7. Форма тени на свете
С помощью такого алгоритма получаются тени любой сложности, причем их количество, как и источников света с объектами неограниченно (см.рис.8).
Да будет свет!
Под следующий код сделаем модуль, который и будет отвечать за тени. Назовем его ZGLShadows.
Рис. 8. Сцена с большим количеством теней
Напишем тип света:
код:
PLightSource=^TLightSource;
TLightSource=record
position:leVect; // положение
radius:single; // радиус
color:TColorRGB; // цвет
intensivity:single; // интенсивность cвета
prev,next:PLightSource;
end;
Все данные будут храниться в “prev-next” (двухсвязных) списках (см. рис.9):
Рис. 9. Списки
Каждый элемент является звеном цепи и имеет указатели на предыдущее и следующее звено. Нам же нужно иметь первый элемент и длину цепи для управления списком:
код:
// Источники света
le_Lights:PLightSource; // список
le_NumLights:integer; // количество
Более подробно о такой системе хранения данных можно почитать в Интернете. Как мы видим, у нас появились новые типы данных:
код:
TColorRGB=record
r,g,b:single;
end;
Данный тип нужен для хранения цвета в формате rgb, так как его использует OpenGL. ZenGL использует integer для хранения цветов (например $FFFFFF соответствует 1,1,1 в RGB), поэтому нам может понадобится процедура для перевода цвета в RGB:
код:
begin
Result.r := ((Color and $FF0000) shr 16) / 255;
Result.g := ((Color and $FF00) shr 8) / 255;
Result.b := (Color and $FF) / 255;
end;
Все координаты будут храниться в типе:
код:
leVect=record
x,y:single;
end;
Подробнее о нем будет написано позже, пока нам понадобится только формирование вектора по x и y:
код:
begin
result.x:=x;
result.y:=y;
end;
Перейдем к процедурам управления источниками света:
код:
color:TColorRGB):PLightSource;
var t: PLightSource;
begin
new(t);
t.Next:= nil;
t.Prev:= nil;
t.position:=p;
t.radius:=radius;
t.intensivity:=intensivity;
t.color:=color;
t.Next:= le_Lights;
if le_Lights <> nil then le_Lights.Prev:= t;
le_Lights:= t;
Result:= le_Lights;
inc(le_NumLights);
end;
Функция создает источник света в памяти и возвращает указатель на него. Большую часть кода занимает работа со списками.
В следующей процедуре происходит рисование круга света как на рисунке 4. Он рисуется через GL_TRIANGLE_FAN. Первая точка в центре имеет цвет и интенсивность света, далее идут точки по радиусу окружности с нулевым цветом, благодаря чему мы имеем плавный переход цвета:
код:
var angle:single;
begin
angle:=0;
glBegin(GL_TRIANGLE_FAN);
glColor4f(t.color.r, t.color.g, t.color.b, t.intensivity);
glVertex2f(t.position.x,t.position.y);
glColor4f(0, 0, 0, 0 );
while angle<=Pi*2 do begin
glVertex2f( t.radius*cos(angle) + t.position.x,
t.radius*sin(angle) + t.position.y);
angle:=angle+((PI*2)/le_numSubdivisions);
end;
glVertex2f(t.position.x+t.radius, t.position.y);
glEnd();
end;
Количество треугольников, из которого рисуется круг, задается константой:
код:
le_numSubdivisions = 32;
Следующая процедура рассчитывает и рисует тень для объектов, но о ней я напишу позже:
код:
Далее напишем процедуру, которая освобождает память, занятую источником света:
код:
var DelT: PLightSource;
begin
DelT:= t;
if t.Prev <> nil then t.Prev.Next := t.Next
else le_Lights:= t.Next;
if t.Next <> nil then t.Next.Prev := t.Prev;
Dispose(DelT);
dec(le_NumLights);
t:=nil
end;
Следующая процедура вспомогательная, она обрабатывает каждый источник света передаваемой в нее процедурой:
код:
var t, tNext: PLightSource;
begin
t:= le_Lights;
while t <> nil do
begin
tNext:= t.Next;
p(t);
t:= tNext;
end;
end;
le_proc – тип процедуры:
код:
le_proc=procedure(d:Pointer);
Например, данная строчка нарисует все источники света:
код:
Хочу заметить, что при попытке передать в le_EachLightSource процедуру очищения возникнет ошибка, связанная с памятью, поэтому для очищения всех источников света напишем отдельную процедуру:
код:
var t, tNext: PLightSource;
begin
t:= le_Lights;
while t <> nil do begin
tNext:= t.Next;
le_FreeLightSource(t);
t:= tNext;
end;
end;
Заставим это работать
С типом света мы управились, теперь надо заставить его работать. Объявим следующие переменные:
код:
le_AlphaBuffer: zglPRenderTarget; // буфер для света
le_AccBuffer: zglPRenderTarget; // буфер для сложения
// изображений света
le_DarkColor: integer; // цвет тени
В этой процедуре инициализируются буферы для рендеринга. К проекту нужно также подключить модули:
- zgl_textures – создание текстуры-буфера
- zgl_render_target – управление рендерингом
- zgl_primitives_2d – очищение рендер target. Хотя можно было бы просто рисовать QUAD на OpenGL.
- zgl_fx – процедуры управления блендингом
- zgl_sprite_2d – рисование текстур
Напишем процедуру инициализации буферов:
код:
begin
le_DarkColor:=DarkColor;
// инициализация буферов
le_AlphaBuffer:=rtarget_Add( RT_TYPE_FBO, tex_CreateZero(
800,600, 0, TEX_DEFAULT_2D ) , RT_FULL_SCREEN );
le_AccBuffer :=rtarget_Add( RT_TYPE_FBO, tex_CreateZero(
800,600, 0, TEX_DEFAULT_2D ) , RT_FULL_SCREEN );
end;
le_DarkColor – переменная, которая отвечает за освещенность. К ее смыслу и принципу работы я еще вернусь. Обобщающая процедура полной обработки света:
код:
begin
rtarget_Set( le_AlphaBuffer ); // начинаем рендер в буфер
pr2d_Rect(0,0,800,600, 0,255,PR2D_FILL); // очищаем черным
// цветом
le_DrawLightSource(t); // отрисовка источника света
rtarget_Set( nil );
rtarget_Set( le_AccBuffer ); // отрисовка полученного
// изобр-я в буфер аккамуляции
fx_SetBlendMode(FX_BLEND_ADD); // при отрисовке используем
// блендинг для сложения
// интенсивностей источ-в света
ssprite2d_Draw( le_AlphaBuffer.Surface, 0,0,800,600,0);
fx_SetBlendMode(FX_BLEND_NORMAL);
rtarget_Set( nil );
end;
И завершающая процедура – вывод буфера с использованием MULT блендинга:
код:
begin
// выводим полученные тени и свет на экран с использованием
// блендинга mult (чем светлее изображение тем прозрачней)
fx_SetBlendMode(FX_BLEND_MULT);
ssprite2d_Draw( le_AccBuffer.Surface, 0,0,800,600,0);
fx_SetBlendMode(FX_BLEND_NORMAL);
// очищаем буфер для следующего кадра (цветом le_DarkColor!)
rtarget_Set( le_AccBuffer );
pr2d_Rect(0,0,800,600, le_DarkColor,255,PR2D_FILL);
rtarget_Set( nil );
end;
Хочу заметить, что очищение le_AccBuffer проводится цветом le_DarkColor. Следовательно, чем светлее этот цвет тем прозрачнее тени (см. рис.10). На изображении видно, что справа фон просвечивается даже там, где света нет, так как le_DarkColor не черный, а серый ($1f1f1f).
Рис. 10. Различный DarkColor
Все, система света написана. Правда, пока без теней от объектов. Теперь проверим ее в действии.
Добавим переменную под управляемый свет:
код:
UserLight:PLightSource; // указатель на управляемый свет
Создадим его, и еще 4 света в Init:
код:
// загружаем источники света
le_CreateLightSource
(le_v(520,550),400,0.3,IntToRGB($FF00FF));
le_CreateLightSource
(le_v(470,50),250,0.5,IntToRGB($FF0000));
le_CreateLightSource
(le_v(200,300),270,1,IntToRGB($00FF00));
le_CreateLightSource
(le_v(640,270),300,0.8,IntToRGB($FFFFFF));
UserLight:=le_CreateLightSource(le_v(0 ,
0),100,0.8,IntToRGB($FFFFFF));
Теперь в Draw напишем рисование теней:
код:
le_EachLightSource(@le_RenderLight);
// отрисовка теней
le_FinishRender;
В Update привяжем UserLight к мышке, сделаем изменение размера при нажатии на кнопки мыши и цвета при нажатии на колесико:
код:
UserLight.radius:=UserLight.radius+3;
if mouse_Down( M_BRIGHT ) then
if UserLight.radius>0 then
UserLight.radius:=UserLight.radius-3;
if mouse_Click( M_BMIDLE ) then begin
UserLight.color.r:=random(100)/100;
UserLight.color.g:=random(100)/100;
UserLight.color.b:=random(100)/100;
end;
И наконец, в Quit очищаем источники света:
код:
Запускаем, любуемся результатом (см. рис.11).
Рис. 11. Результат
Заключение
В следующей части статьи я рассмотрю создание теней от объектов, а также оптимизирую код, чтобы добиться большей производительности. Весь исходный код проекта приложен к журналу «ПРОграммист. Пятый выпуск».
Продолжение следует…
Ресурсы
- Страница разработчика ZenGL http://andrukun.inf.ua/zengl.html
- Михалкович С.С. Основы программирования.
Второй семестр 08-09, 2 часть
Обсудить на форуме – Делаем динамические тени на OPENGL. Часть 1
25th
Применение паскаля в геометрии
Часть 0. Intro.
Еще в самом
детстве, когда я начал изучать Паскаль, я запомнил цитату из детской книжки
примерно такого содержания: «Паскаль — универсальный язык программирования
подходящий для решения самых различных задач». Когда человек впервые
сталкивается с программированием на Паскале, одна из первых его мыслей после
прочтения таких строк будет «А в чем же заключается его универсальность?». На
самом деле я когда более углубленно изучил паскаль решил, что это определение
абсолютно правдивое. И действительно Паскаль можно применить для решения
абсолютно любых задач. В этой статье я расскажу о там как можно использовать
Паскаль для решения геометрических задач. Для примера возьмем задание которое
звучит так: «По координатам точки и вершин треугольника определить, принадлежит
ли точка этому треугольнику».
(читать всё…)
24th
Как в WebBrowser выбрать из списка и нажать на кнопку?
Posted by Chas under Пост-обзор
Нажатие на кнопку:
код:
var HtmlDocument : IHtmlDocument2;
i : integer;
HtmlCollection : IHtmlElementCollection;
HtmlElement : IHtmlElement;
spisok : string;
begin
HtmlDocument := BrowserMain.Document as IHtmlDocument2;
HtmlCollection := HtmlDocument.All;
for i := 0 to HtmlCollection.length – 1 do
begin
if stop = 1 then Exit;
HtmlElement := HtmlCollection.Item(i, 1) as IHtmlElement;
spisok := HtmlElement.InnerText;
Trim(spisok);
if spisok = ‘список’ then
begin
HtmlElement.click;
Exit;
end;
end;
end;
выбор из открывающегося списка:
код:
const fieldName, newValue: string; const instance: integer);
var
field: IHTMLElement;
inputField: IHTMLInputElement;
selectField: IHTMLSelectElement;
textField: IHTMLTextAreaElement;
begin
field := theForm.Item(fieldName,instance) as IHTMLElement;
if Assigned(field) then
begin
if field.tagName = ‘INPUT’ then
begin
inputField := field as IHTMLInputElement;
if (inputField.type_ ‘radio’) and (inputField.type_ ‘checkbox’)
then inputField.value := newValue
else inputField.checked := (newValue = ‘checked’);
end
else if field.tagName = ‘SELECT’ then
begin
selectField := field as IHTMLSelectElement;
selectField.value := newValue;
end
else if field.tagName = ‘TEXTAREA’ then
begin
textField := field as IHTMLTextAreaElement;
textField.value := newValue;
end;
end;
end;
вызов процедуры:
код:
SetFieldValue(theForm,’type’,переменная);
23rd
Авг
Получить идентификатор процесса и узнать полуный путь до файла этого процесса. c/c++
Пишу небольшую программу, мне нужно чтобы она искала заданный мною выполняемый процесс. Подскажите какая это функция может сделать, быть может это win api функция?
Sazary:
код:
#include <stdio.h>
#include <TlHelp32.h>
#include <conio.h>
#include <string.h>
#include <psapi.h>
using namespace std;
int main()
{
HANDLE h,hp;
PROCESSENTRY32 pe;
int id;
bool bl,flag=false;
char name[256],str[256];
char path[MAX_PATH];
DWORD dw;
HMODULE hmod;
scanf(”%s”,name);
h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS|TH32CS_SNAPMODULE,0);
for(bl = Process32First(h, &pe); bl; bl = Process32Next(h, &pe))
{
strcpy(str,pe.szExeFile);
if(strcmp(str,name)==0)
{
printf(”Process found: %s\n”,str);
hp = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,false,pe.th32ProcessID);
EnumProcessModules(hp, &hmod,sizeof(hmod),&dw); // получаем первый модуль, связанный с процессом, то есть сам exe-файл
GetModuleFileNameEx(hp, hmod, path, MAX_PATH); // получаем путь к модулю
printf(”path: %s\n”,path);
CloseHandle(hp);
CloseHandle(h);
flag = true;
break;
}
}
CloseHandle(h);
if(!flag) printf(”Process not found”);
getch();
return 0;
}
Нужно прилинковать модуль psapi.
23rd
Как узнать количество строк в memo?
У новичков может возникнуть такой вопрос.
код:
Нумерация строк начинается с нуля.
23rd
Определить нажата правая клавиша мыши?
Событие OnMouseDown у формы, проверяя таким макаром:
код:
Облако меток
css реестр ассемблер timer SaveToFile ShellExecute программы массив советы word MySQL SQL ListView pos random компоненты дата LoadFromFile form база данных сеть html php RichEdit indy строки Win Api tstringlist Image мысли макросы Edit ListBox office C/C++ memo графика StringGrid canvas поиск файл Pascal форма Файлы интернет Microsoft Office Excel excel winapi журнал ПРОграммист DelphiКупить рекламу на сайте за 1000 руб
пишите сюда - alarforum@yandex.ru
Да и по любым другим вопросам пишите на почту
пеллетные котлы
Пеллетный котел Emtas
Наши форумы по программированию:
- Форум Web программирование (веб)
- Delphi форумы
- Форумы C (Си)
- Форум .NET Frameworks (точка нет фреймворки)
- Форум Java (джава)
- Форум низкоуровневое программирование
- Форум VBA (вба)
- Форум OpenGL
- Форум DirectX
- Форум CAD проектирование
- Форум по операционным системам
- Форум Software (Софт)
- Форум Hardware (Компьютерное железо)