Выкладываю три варианта пламени, визуальные эффекты получились прикольные.
1) Пламя зелёное
Рисунок 1. Пример работы программы зелёного пламени
Код проекта:
unit ogl_p9_u1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, dglOpenGL, Math; type TForm1 = class(TForm) tmr1: TTimer; procedure tmr1Timer(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormResize(Sender: TObject); private { Private declarations } FireTexture: GLuint; buffer: array[0..199, 0..319] of Word; h_DC: HDC; // Хранение контекста устройства h_RC: HGLRC; // Хранение контекста рендеринга procedure InitGL; procedure SetupViewport; public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.FormCreate(Sender: TObject); begin InitGL; // Исправлено имя процедуры инициализации Randomize; FillChar(buffer, SizeOf(buffer), 0); tmr1.Interval := 50; end; procedure TForm1.InitGL; begin // Инициализация OpenGL InitOpenGL; // Инициализация библиотеки h_DC := GetDC(Handle); // Создание контекста с правильными атрибутами h_RC := CreateRenderingContext(h_DC, [opDoubleBuffered], 32, 24, 8, 0, 0, 0); ActivateRenderingContext(h_DC, h_RC); // Настройка параметров OpenGL glClearColor(0.0, 0.0, 0.0, 1.0); // Черный фон SetupViewport; // Создание текстуры с правильным форматом glGenTextures(1, @FireTexture); glBindTexture(GL_TEXTURE_2D, FireTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 320, 200, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, nil); // Исправлен формат end; procedure TForm1.SetupViewport; begin glViewport(0, 0, ClientWidth, ClientHeight); glMatrixMode(GL_PROJECTION); glLoadIdentity; gluOrtho2D(0, 320, 200, 0); glMatrixMode(GL_MODELVIEW); glLoadIdentity; end; procedure TForm1.tmr1Timer(Sender: TObject); var x, y, xPrev, xNext: Integer; sum: Cardinal; begin // Активация контекста перед использованием ActivateRenderingContext(h_DC, h_RC); // Генерация новых пикселей for x := 0 to 319 do buffer[199, x] := IfThen(Random(2) = 1, $F800, $0000); // Распространение пламени for y := 198 downto 0 do for x := 0 to 319 do begin xPrev := (x - 1 + 320) mod 320; xNext := (x + 1) mod 320; sum := buffer[y+1, xPrev] + buffer[y+1, x] + buffer[y+1, xNext]; //buffer[y, x] := sum div 3; buffer[y, x] := (sum div 3) and $FFE0; // Уменьшаем интенсивность end; // Обновление текстуры glBindTexture(GL_TEXTURE_2D, FireTexture); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 320, 200, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, @buffer[0][0]); // Отрисовка glClear(GL_COLOR_BUFFER_BIT); glEnable(GL_TEXTURE_2D); glBegin(GL_QUADS); glTexCoord2f(0, 0); glVertex2f(0, 0); glTexCoord2f(1, 0); glVertex2f(320, 0); glTexCoord2f(1, 1); glVertex2f(320, 200); glTexCoord2f(0, 1); glVertex2f(0, 200); glEnd; SwapBuffers(h_DC); // Используем сохраненный контекст end; procedure TForm1.FormDestroy(Sender: TObject); begin // Корректное удаление ресурсов glDeleteTextures(1, @FireTexture); wglMakeCurrent(0, 0); wglDeleteContext(h_RC); ReleaseDC(Handle, h_DC); end; procedure TForm1.FormResize(Sender: TObject); begin ActivateRenderingContext(h_DC, h_RC); // Активируем контекст SetupViewport; Invalidate; end; end.
2) Пламя синие
Рисунок 2. Пример работы программы синего пламени
Код проекта:
unit ogl_p10_u1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, dglOpenGL, Math; type TForm1 = class(TForm) tmr1: TTimer; procedure FormCreate(Sender: TObject); procedure tmr1Timer(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormResize(Sender: TObject); private { Private declarations } FireTexture: GLuint; FirePalette: array[0..255] of TRGBQuad; buffer: array[0..199, 0..319] of Byte; h_DC: HDC; h_RC: HGLRC; procedure InitGL; procedure SetupViewport; procedure GeneratePalette; public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.FormCreate(Sender: TObject); begin InitGL; Randomize; FillChar(buffer, SizeOf(buffer), 0); GeneratePalette; tmr1.Interval := 50; end; procedure TForm1.GeneratePalette; var i: Integer; begin // Правильная огненная палитра (красный -> оранжевый -> желтый) for i := 0 to 255 do begin // Черное ядро пламени if i < 32 then begin FirePalette[i].rgbRed := i * 2; FirePalette[i].rgbGreen := 0; FirePalette[i].rgbBlue := 0; end // Красная зона else if i < 96 then begin FirePalette[i].rgbRed := 255; FirePalette[i].rgbGreen := (i - 32) * 4; FirePalette[i].rgbBlue := 0; end // Оранжевая зона else if i < 160 then begin FirePalette[i].rgbRed := 255; FirePalette[i].rgbGreen := 128 + (i - 96) * 2; FirePalette[i].rgbBlue := (i - 96) * 4; end // Желтое ядро else begin FirePalette[i].rgbRed := 255; FirePalette[i].rgbGreen := 255; FirePalette[i].rgbBlue := (i - 160) * 16; end; end; end; procedure TForm1.InitGL; begin InitOpenGL; h_DC := GetDC(Handle); h_RC := CreateRenderingContext(h_DC, [opDoubleBuffered], 32, 24, 8, 0, 0, 0); ActivateRenderingContext(h_DC, h_RC); glClearColor(0.0, 0.0, 0.0, 1.0); SetupViewport; glGenTextures(1, @FireTexture); glBindTexture(GL_TEXTURE_2D, FireTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 320, 200, 0, GL_RGBA, GL_UNSIGNED_BYTE, nil); end; procedure TForm1.SetupViewport; begin glViewport(0, 0, ClientWidth, ClientHeight); glMatrixMode(GL_PROJECTION); glLoadIdentity; gluOrtho2D(0, 320, 200, 0); glMatrixMode(GL_MODELVIEW); glLoadIdentity; end; procedure TForm1.tmr1Timer(Sender: TObject); var x, y, xPrev, xNext: Integer; sum: Integer; rgbBuffer: array[0..199, 0..319] of TRGBQuad; begin // Генерация огня с большей интенсивностью for x := 0 to 319 do buffer[199, x] := 160 + Random(96); // Старт с горячих цветов // Улучшенный алгоритм распространения for y := 198 downto 0 do for x := 0 to 319 do begin xPrev := (x - 1 + 320) mod 320; xNext := (x + 1) mod 320; sum := buffer[y+1, xPrev] + buffer[y+1, x] * 2 + buffer[y+1, xNext] + buffer[y+2, x] + Random(4); // Добавляем шум //buffer[y, x] := Max(0, (sum div 5) - 1); buffer[y, x] := Max(0, (sum div 5) - (y div 70)); // Усиливаем затухание с высотой end; // Конвертация в RGB с коррекцией цвета for y := 0 to 199 do for x := 0 to 319 do begin // Применяем гамма-коррекцию rgbBuffer[y, x] := FirePalette[Min(255, buffer[y, x] * 2)]; rgbBuffer[y, x].rgbBlue := rgbBuffer[y, x].rgbBlue div 4; // Уменьшаем синий end; // Обновление текстуры glBindTexture(GL_TEXTURE_2D, FireTexture); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 320, 200, GL_RGBA, GL_UNSIGNED_BYTE, @rgbBuffer); // Рендеринг glClear(GL_COLOR_BUFFER_BIT); glEnable(GL_TEXTURE_2D); glBegin(GL_QUADS); glTexCoord2f(0, 0); glVertex2f(0, 0); glTexCoord2f(1, 0); glVertex2f(320, 0); glTexCoord2f(1, 1); glVertex2f(320, 200); glTexCoord2f(0, 1); glVertex2f(0, 200); glEnd; SwapBuffers(h_DC); end; procedure TForm1.FormDestroy(Sender: TObject); begin glDeleteTextures(1, @FireTexture); wglMakeCurrent(0, 0); wglDeleteContext(h_RC); ReleaseDC(Handle, h_DC); end; procedure TForm1.FormResize(Sender: TObject); begin ActivateRenderingContext(h_DC, h_RC); SetupViewport; Invalidate; end; end.
3) Пламя красное
Рисунок 3. Пример работы программы красного пламени
Код проекта:
unit ogl_p11_u1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, dglOpenGL, Math; type TForm1 = class(TForm) tmr1: TTimer; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormResize(Sender: TObject); procedure tmr1Timer(Sender: TObject); private { Private declarations } FireTexture: GLuint; FirePalette: array[0..255] of TRGBQuad; buffer: array[0..199, 0..319] of Byte; h_DC: HDC; h_RC: HGLRC; procedure InitGL; procedure SetupViewport; procedure GeneratePalette; public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.FormCreate(Sender: TObject); begin InitGL; Randomize; FillChar(buffer, SizeOf(buffer), 0); GeneratePalette; tmr1.Interval := 50; end; procedure TForm1.GeneratePalette; var i: Integer; begin // Правильная огненная палитра (без синих оттенков) for i := 0 to 255 do begin case i of 0..63: // Черный -> Темно-красный begin FirePalette[i].rgbRed := i; FirePalette[i].rgbGreen := 0; FirePalette[i].rgbBlue := 0; end; 64..127: // Красный -> Оранжевый begin FirePalette[i].rgbRed := 255; FirePalette[i].rgbGreen := (i - 64) * 2; FirePalette[i].rgbBlue := 0; end; 128..191: // Оранжевый -> Желтый begin FirePalette[i].rgbRed := 255; FirePalette[i].rgbGreen := 128 + (i - 128); FirePalette[i].rgbBlue := 0; end; 192..255: // Желтый -> Белый begin FirePalette[i].rgbRed := 255; FirePalette[i].rgbGreen := 255; FirePalette[i].rgbBlue := (i - 192) * 4; end; end; end; end; procedure TForm1.InitGL; begin InitOpenGL; h_DC := GetDC(Handle); h_RC := CreateRenderingContext(h_DC, [opDoubleBuffered], 32, 24, 8, 0, 0, 0); ActivateRenderingContext(h_DC, h_RC); glClearColor(0.0, 0.0, 0.0, 1.0); SetupViewport; glGenTextures(1, @FireTexture); glBindTexture(GL_TEXTURE_2D, FireTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 320, 200, 0, GL_BGRA, GL_UNSIGNED_BYTE, nil); end; procedure TForm1.SetupViewport; begin glViewport(0, 0, ClientWidth, ClientHeight); glMatrixMode(GL_PROJECTION); glLoadIdentity; gluOrtho2D(0, 320, 200, 0); glMatrixMode(GL_MODELVIEW); glLoadIdentity; end; procedure TForm1.FormDestroy(Sender: TObject); begin glDeleteTextures(1, @FireTexture); wglMakeCurrent(0, 0); wglDeleteContext(h_RC); ReleaseDC(Handle, h_DC); end; procedure TForm1.FormResize(Sender: TObject); begin ActivateRenderingContext(h_DC, h_RC); SetupViewport; Invalidate; end; procedure TForm1.tmr1Timer(Sender: TObject); var x, y, xPrev, xNext: Integer; sum: Integer; rgbBuffer: array[0..199, 0..319] of TRGBQuad; begin // Генерация основания пламени с большей интенсивностью for x := 0 to 319 do buffer[199, x] := Min(255, 192 + Random(64)); // Улучшенный алгоритм распространения пламени for y := 198 downto 0 do for x := 0 to 319 do begin xPrev := (x - 1 + 320) mod 320; xNext := (x + 1) mod 320; // Новое ядро пламени с турбулентностью sum := (buffer[y+1, xPrev] + buffer[y+1, x] * 2 + buffer[y+1, xNext] + buffer[y+2, x] * 2) div 6; // Добавляем случайные колебания buffer[y, x] := Max(0, sum - 1 + Random(3) - 1); end; // Конвертация в RGB for y := 0 to 199 do for x := 0 to 319 do rgbBuffer[y, x] := FirePalette[Min(255, buffer[y, x] + Random(8))]; // Обновление текстуры glBindTexture(GL_TEXTURE_2D, FireTexture); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 320, 200, GL_BGRA, GL_UNSIGNED_BYTE, @rgbBuffer); // Рендеринг glClear(GL_COLOR_BUFFER_BIT); glEnable(GL_TEXTURE_2D); glBegin(GL_QUADS); glTexCoord2f(0, 0); glVertex2f(0, 0); glTexCoord2f(1, 0); glVertex2f(320, 0); glTexCoord2f(1, 1); glVertex2f(320, 200); glTexCoord2f(0, 1); glVertex2f(0, 200); glEnd; SwapBuffers(h_DC); end; end.
Комментариев нет:
Отправить комментарий