понедельник, 13 октября 2025 г.

Минимальное OpenGL + SDL 2 приложение на языке Lisp (SBCL) под Windows 10

Я уже пытался освоить Lisp в этой статье (https://notidealrunner.blogspot.com/2013/01/common-lisp-fedora-17-kde.html). В конце статьи я сказал, что мы попробуем написать OpenGL программу на Lisp. Каким-то чудом это у меня получилось. Читаем ниже.

 

1. Установка диалекта Lisp (SBCL) на Windows 10

Для начала скачайте SBCL (Steel Bank Common Lisp) с официального сайта проекта по ссылке (https://www.sbcl.org/platform-table.html). На момент написания статьи на сайте доступна версия 2.5.9 Установка SBCL проста: следуйте инструкциям мастера установки. После установки путь до SBCL установится в переменную окружения PATH. Запустите командную строку и выполните команду sbcl --version. 

 

2. Установка менеджера пакетов Quicklisp

Скачайте quicklisp с официального сайта по ссылке (https://beta.quicklisp.org/quicklisp.lisp). Сохраните quicklisp.lisp, например, в папку c:\users\[ваш пользователь]\Downloads\. В командной строке выполните команду sbcl, после этого вы попадёте в командную строку sbcl. Для установки Quicklisp в C:\users\[ваш пользователь]\quicklisp и добавления его загрузку в инициализацию SBCL необходима выполнить следующие команды:

 

1) (load "c:/users/user/Downloads/quicklisp.lisp") — загрузит файл quicklisp.lisp

2) (quicklisp-quickstart:install) — установит менеджер пакетов

3) (ql:add-to-init-file) - добавит строку загрузки менеджера пакетов quicklisp в c:\users\[ваш пользователь]\.sbclrc 

 

3. Загрузка пакетов OpenGL и SDL 2

В SBCL для работы с OpenGL используют пакет cl-opengl для рисовки графики и для работы с SDL 2 используют пакет sdl2 для создания окна.

 

1) (ql:quickload "cl-opengl") – для OpenGL

2) (ql:quickload "sdl2") – для SDL 2

 

4. Пример кода на lisp с использованием OpenGL и SDL

 

(defpackage #:sdl2-opengl-triangle
  (:use :cl)
  (:export :run))

(in-package :sdl2-opengl-triangle)

(eval-when (:compile-toplevel :load-toplevel :execute)
  (ql:quickload '("sdl2" "cl-opengl")))

(defparameter *window-width* 640)
(defparameter *window-height* 480)

(defun run()
  (sdl2:with-init (:video)
    (sdl2:with-window (window :title "OpenGL Triangle"
                              :w *window-width*
                              :h *window-height*
                              :flags '(:opengl :shown))
	(let ((context (sdl2:gl-create-context window)))
        (unwind-protect
             (progn
               (sdl2:gl-make-current window context)
               (gl:viewport 0 0 *window-width* *window-height*)
               
               ;; Основной цикл рендеринга
               (sdl2:with-event-loop (:method :poll)
                 (:quit () t)
                 (:keydown (:keysym keysym)
                           (when (sdl2:scancode= (sdl2:scancode-value keysym) :scancode-escape)
                             (sdl2:push-event :quit)))
                 (:idle ()
                        ;; Очистка буфера
                        (gl:clear-color 0.1 0.1 0.1 1.0)
                        (gl:clear :color-buffer-bit)
                        
                        ;; Рисуем треугольник
                        (gl:begin :triangles)
                        (gl:color 1.0 0.0 0.0)  ; красный
                        (gl:vertex -0.5 -0.5 0.0)
                        (gl:color 0.0 1.0 0.0)  ; зелёный
                        (gl:vertex  0.5 -0.5 0.0)
                        (gl:color 0.0 0.0 1.0)  ; синий
                        (gl:vertex  0.0  0.5 0.0)
                        (gl:end)
                        
                        ;; Показываем кадр
                        (sdl2:gl-swap-window window)
                        
                        ;; Ограничиваем FPS (~60)
                        (sdl2:delay 16)
				  )
				)
             ;; Освобождение контекста
             (sdl2:gl-delete-context context)
			 )
		)
	)
	)
  )
)

5. Скачать SDL2.dll  

Прежде чем загружать и запускать пример на Lisp c OpenGL и SDL, вам необходимо скачать последние драйвера для вашей видеокарты, это позволит вам запускать OpenGL приложения и динамическую библиотеку SDL 2 для запуска приложений SDL 2. Скачать SDL 2 можно с официального сайта (https://github.com/libsdl-org/SDL/releases/tag/release-2.30.11). Последняя версия SDL 2 это 2.30.11. Скопируйте SDL2.dll в папку, где у вас установлен SBCL, рядом с файлом sbcl.exe. У меня это папка C:\Program Files\Steel Bank Common Lisp\.

 

6. Команда загрузки примера кода на Lisp и его запуск 


(load "h:/Programming/Projects/lisp/lisp_opengl_p1/sdl-opengl.lisp")

(sdl2-opengl-triangle:run)

 

Рисунок 1. Пример работы программы на Lisp с использованием OpenGL и SDL 2
 

понедельник, 6 октября 2025 г.

Пример кода на Delphi и OpenGL. Переключение камеры, привязка камеры к объекту

Программа реализует пример переключения камеры между объектами, привязка камеры к объекту.

Рисунок 1. Пример работы программы
 

Код проекта:

unit ogl_p17_u1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, dglOpenGL, ExtCtrls, Math, DGlut;

type
  TForm1 = class(TForm)
    tmr1: TTimer;
    procedure FormDestroy(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormResize(Sender: TObject);
    procedure tmr1Timer(Sender: TObject);
  private
    { Private declarations }
  public
    h_RC: HGLRC; // Контекст рендеринга
    h_DC: HDC;   // Контекст устройства

    procedure AttachCameraToCube;
    procedure AttachCameraToCube2;
    procedure ReturnCameraToOrigPos;
    procedure InitGL;
    procedure DrawGLScene;
    procedure UpdateCamera;
    procedure HandleKeys;
    procedure DrawCube;
    procedure DrawCube2;
    procedure DrawTrack;
    procedure BuildFont;
    procedure glPrint(text: string);
    { Public declarations }
  end;

var
  Form1: TForm1;
   
  CubePos: array [0..2] of GLfloat = (0, 0, 0); // Позиция куба
  Cube2Pos: array [0..2] of GLfloat = (0, 0, 0); // Позиция куба 2
  Cube2PosCount: GLfloat = 1.0;
  Cube2Rot: GLfloat = 0.0;
  Cube2Speed: GLfloat = 1.0;
  CubeRot: GLfloat = 0.0; // Угол вращения куба
  CamPos: array [0..2] of GLfloat = (0, 5, 10); // Позиция камеры
  CamPitch: GLfloat; // Углы поворота камеры
  MoveSpeed: GLfloat = 0.1; // Скорость перемещения
  CamPosFlag: GLbyte;
  
const
  CAM_FREE = 0;
  CAM_CUBE1 = 1;
  CAM_CUBE2 = 2;
  FONT_BASE = 1000;

implementation

{$R *.dfm}

procedure TForm1.BuildFont;
var
  h_Font: HFONT;
begin
  h_Font := CreateFont(
    -16,
    0,
    0,
    0,
    FW_NORMAL,
    0,
    0,
    0,
    RUSSIAN_CHARSET,
    OUT_TT_PRECIS,
    CLIP_DEFAULT_PRECIS,
    ANTIALIASED_QUALITY,
    FF_DONTCARE or DEFAULT_PITCH,
    'Arial'                      
  );
  SelectObject(h_DC, h_Font);
  wglUseFontBitmaps(h_DC, 0, 256, FONT_BASE);
  DeleteObject(h_Font);
end;

procedure TForm1.glPrint(text: string);
begin
  glListBase(FONT_BASE);
  glCallLists(Length(text), GL_UNSIGNED_BYTE, PAnsiChar(AnsiString(text)));
end;

procedure TForm1.AttachCameraToCube;
begin
  CamPos[0] := CubePos[0] + 3;
  CamPos[1] := CubePos[1] + 4;
  CamPos[2] := CubePos[2] + 5;
end;

procedure TForm1.AttachCameraToCube2;
begin
  CamPos[0] := Cube2Pos[0] + 3;
  CamPos[1] := Cube2Pos[1] + 4;
  CamPos[2] := Cube2Pos[2] + 5;
end;

procedure TForm1.ReturnCameraToOrigPos;
begin
  CamPos[0] := 0;
  CamPos[1] := 5;
  CamPos[2] := 10;
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);

  if Assigned(wglSwapIntervalEXT) then
    wglSwapIntervalEXT(1);

  glClearColor(0.0, 0.0, 0.0, 1.0); // Чёрный фон
  glEnable(GL_DEPTH_TEST); // Включение теста глубины
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity;
  gluPerspective(45.0, 640/480, 0.1, 100.0); // Настройка перспективы
  glMatrixMode(GL_MODELVIEW);

  BuildFont;
end;

procedure TForm1.UpdateCamera;
begin
  glLoadIdentity;
  case CamPosFlag of
    CAM_FREE: // Исходная позиция
      gluLookAt(CamPos[0], CamPos[1], CamPos[2], 0, 0, 0, 0, 1, 0);
    CAM_CUBE1: // Следим за первым кубом
      gluLookAt(CamPos[0], CamPos[1], CamPos[2], CubePos[0], CubePos[1], CubePos[2], 0, 1, 0);
    CAM_CUBE2: // Следим за вторым кубом
      gluLookAt(CamPos[0], CamPos[1], CamPos[2], Cube2Pos[0], Cube2Pos[1], Cube2Pos[2], 0, 1, 0);
  end;
end;

procedure TForm1.HandleKeys;
var
  Angle: GLfloat;
begin
  if GetAsyncKeyState(VK_F1) < 0 then
  begin
    CamPosFlag := CAM_CUBE1;
    AttachCameraToCube;
  end;

  if GetAsyncKeyState(VK_F2) < 0 then
  begin
    CamPosFlag := CAM_CUBE2;
    AttachCameraToCube2;
  end;

  if GetAsyncKeyState(VK_F3) < 0 then
  begin
    CamPosFlag := CAM_FREE;
    ReturnCameraToOrigPos;
  end;

  if GetAsyncKeyState(VK_UP) < 0 then
  begin
    CubePos[2] := CubePos[2] - MoveSpeed;
    if CamPosFlag = CAM_CUBE1 then
      AttachCameraToCube;
  end;

  if GetAsyncKeyState(VK_DOWN) < 0 then
  begin
    CubePos[2] := CubePos[2] + MoveSpeed;
    if CamPosFlag = CAM_CUBE1 then
      AttachCameraToCube;
  end;

  if GetAsyncKeyState(VK_LEFT) < 0 then
  begin
    CubePos[0] := CubePos[0] - MoveSpeed;
    if CamPosFlag = CAM_CUBE1 then
      AttachCameraToCube;
  end;

  if GetAsyncKeyState(VK_RIGHT) < 0 then
  begin
    CubePos[0] := CubePos[0] + MoveSpeed;
    if CamPosFlag = CAM_CUBE1 then
      AttachCameraToCube;
  end;

  CubeRot := CubeRot + 2.0; // Вращение
  if CubeRot >= 360 then CubeRot := 0;

  // Движение и вращение второго куба
  Cube2PosCount := Cube2PosCount + Cube2Speed;
  if Cube2PosCount >= 360 then Cube2PosCount := 0;

  // Всегда обновляем позицию второго куба
  Angle := DegToRad(Cube2PosCount);
  Cube2Pos[0] := 5*Cos(Angle);
  Cube2Pos[1] := 0.5;
  Cube2Pos[2] := 5*Sin(Angle);

  
  Cube2Rot := Cube2Rot + 3.0; // Независимое вращение
  if Cube2Rot >= 360 then Cube2Rot := 0;
end;

procedure TForm1.DrawCube;
begin
  glColor3f(0, 0, 1); // Синий цвет
  glPushMatrix;
    glTranslatef(CubePos[0], CubePos[1], CubePos[2]);
    glRotatef(CubeRot, 0, 1, 0); // Вращение вокруг Y
    glutSolidCube(1.0); // Используем GLUT для простоты
  glPopMatrix;
end;

procedure TForm1.DrawCube2;
begin
  glColor3f(1, 0, 1); // Фиолетовый цвет
  glPushMatrix;
    glTranslatef(Cube2Pos[0], Cube2Pos[1], Cube2Pos[2]);
    glRotatef(Cube2Rot, 0, 1, 0);
    glutSolidCube(1.0);
  glPopMatrix;
end;

procedure TForm1.DrawTrack;
var
  i: Integer;
begin
  glColor3f(1, 1, 0); // Жёлтый цвет
  glBegin(GL_LINE_STRIP);
    for i := 0 to 360 do
      glVertex3f(5*Cos(DegToRad(i)), 0, 5*Sin(DegToRad(i)));
  glEnd;
end;

procedure TForm1.DrawGLScene;
begin
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  glLoadIdentity;

  UpdateCamera;
  HandleKeys;
  DrawTrack;
  DrawCube;
  DrawCube2;

// Сохраняем текущую матрицу
  glPushMatrix;
  
  // Переключаемся в 2D режим для текста
  glMatrixMode(GL_PROJECTION);
  glPushMatrix;
  glLoadIdentity;
  gluOrtho2D(0, ClientWidth, ClientHeight, 0); // 2D проекция
  
  glMatrixMode(GL_MODELVIEW);
  glPushMatrix;
  glLoadIdentity;
  
  // Отключаем тест глубины для текста
  glDisable(GL_DEPTH_TEST);
  
  // Устанавливаем цвет текста
  glColor3f(1.0, 1.0, 1.0); // Белый цвет
  
  // Рисуем текст
  glRasterPos2f(10, 20);
  glPrint('F1 - Синий куб');
  
  glRasterPos2f(10, 40);
  glPrint('F2 - Розовый куб');
  
  glRasterPos2f(10, 60);
  glPrint('F3 - Вся сцена');
  
  // Восстанавливаем настройки
  glEnable(GL_DEPTH_TEST);
  
  glPopMatrix; // MODELVIEW
  glMatrixMode(GL_PROJECTION);
  glPopMatrix; // PROJECTION
  glMatrixMode(GL_MODELVIEW);
  glPopMatrix; // исходная матрица

  SwapBuffers(h_DC);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  wglMakeCurrent(0, 0);
  wglDeleteContext(h_RC);
  ReleaseDC(Handle, h_DC);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  DoubleBuffered := False; 
  InitGL;
  KeyPreview := True;
  Visible := True;
  tmr1.Interval := 16;
  CamPosFlag := 0;
  Cube2PosCount := 0;
end;

procedure TForm1.FormResize(Sender: TObject);
begin
  glViewport(0, 0, ClientWidth, ClientHeight);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity;
  gluPerspective(45.0, ClientWidth/ClientHeight, 0.1, 100.0);
  glMatrixMode(GL_MODELVIEW);
end;

procedure TForm1.tmr1Timer(Sender: TObject);
begin
  DrawGLScene;
end;

end.

Пример кода на Delphi и OpenGL. Три разных варианта пламени

Выкладываю три варианта пламени, визуальные эффекты получились прикольные.

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.

Пример кода на Delphi и OpenGL. Вращение камеры, управление камерой.

Нашёл на форуме по программированию (Ссылка) частично не рабочий код, довёл его до работоспособности. Пример показывает вращение камеры и управление камерой с клавиатуры.

Рисунок 1. Пример работы проекта

unit p1_u1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, OpenGL, ExtCtrls;

type
  TForm1 = class(TForm)
    tmr1: TTimer;
    tmr2: TTimer;
    procedure FormCreate(Sender: TObject);
    procedure FormKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormPaint(Sender: TObject);
    procedure FormResize(Sender: TObject);
    procedure tmr1Timer(Sender: TObject);
    procedure tmr2Timer(Sender: TObject);
  private
    { Private declarations }
    newCount, frameCount, lastCount : LongInt;
    fpsRate : GLfloat;

    procedure MyInitOpenGL(dc:HDC);
    procedure PaintGL(dc:HDC);
    procedure SetDCPixelFormat(DC:HDC);
    procedure SetLight;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  hgc:HGLRC;
  tx,ty,tz:GLfloat;
  gox,goy,goz:GLfloat;
  buf:TBitmap;
  LightPos:array [0..3] of GLfloat=(-1.5,0.0,-3.0,1.0);
  LightAmb:array [0..3] of GLfloat=(0.5,0.5,0.5,1.0);
  LightDif:array [0..3] of GLfloat=(1.0,1.0,1.0,1.0);
  glFog_Color:array [0..3] of GLfloat=(0.5,0.5,0.5,1.0);
  
implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin

  // Инициализация переменных
  goz := -8;
  tx := 0; // Инициализация tx
  ty := 0; // Инициализация ty
  tz := 0; // Инициализация tz
  gox := 0; // Инициализация goX
  goy := 0; // Инициализация goY

  // Установка заголовка формы
  Form1.Caption := 'x=' + FloatToStr(tx) + '  y=' + FloatToStr(ty);

  // Инициализация OpenGL
  MyInitOpenGL(Canvas.Handle);
  PaintGL(Canvas.Handle);

  // Установка параметров OpenGL
  glViewport(0, 0, ClientWidth, ClientHeight);
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);
  glEnable(GL_COLOR_MATERIAL);
  glEnable(GL_POLYGON_SMOOTH);
  
  // Установка матрицы проекции
  glMatrixMode(GL_PROJECTION);
  glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
  glDepthFunc(GL_LEQUAL);
  
  // Возврат к матрице модели
  glMatrixMode(GL_MODELVIEW);

  // Запоминаем текущее время
  lastCount := GetTickCount;

end;

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin

  if Key=VK_ESCAPE then Form1.Close;

  // Проверка нажатия клавиш без Shift
  if not (ssShift in Shift) then
  begin
    if Key = VK_UP then
      tx := tx + 1;
    if Key = VK_DOWN then
      tx := tx - 1;
    if Key = VK_LEFT then
      ty := ty - 1;
    if Key = VK_RIGHT then
      ty := ty + 1;
    if Key = VK_INSERT then
      tz := tz + 0.3;
    if Key = VK_DELETE then
      tz := tz - 0.3;
  end;

  // Проверка нажатия клавиш с Shift
  if ssShift in Shift then
  begin
    if Key = VK_UP then
      goz := goz + 0.3;
    if Key = VK_DOWN then
      goz := goz - 0.3;
    if Key = VK_LEFT then
      gox := gox - 0.3;
    if Key = VK_RIGHT then
      gox := gox + 0.3;
    if Key = VK_INSERT then
      goy := goy + 0.3;
    if Key = VK_DELETE then
      goy := goy - 0.3;
  end;

  // Проверка границ для tX и tY
  if tx = 361 then
    tx := 0;
  if tx = -1 then
    tx := 360;
  if ty = 361 then
    ty := 0;
  if ty = -1 then
    ty := 360;

  // Обновление окна
  InvalidateRect(Handle, nil, False);

end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  // Проверяем, установлен ли контекст
  if hgc <> 0 then
  begin
    // Устанавливаем текущий контекст в 0 перед удалением
    wglMakeCurrent(0, 0);
    // Удаляем контекст
    wglDeleteContext(hgc);
    hgc := 0; // Обнуляем hgc после удаления
  end;
end;

procedure TForm1.FormPaint(Sender: TObject);
begin
  PaintGL(Canvas.Handle);
  newCount:=GetTickCount;
  Inc(frameCount);
  if newCount-lastCount>1000 then
  begin
    fpsRate:=frameCount;
    lastCount:=newCount;
    frameCount:=0;
  end;
end;

procedure TForm1.FormResize(Sender: TObject);
begin
  // Убедитесь, что контекст OpenGL активен перед вызовом функций OpenGL
  glMatrixMode(GL_MODELVIEW);

  // Установите размер области просмотра
  glViewport(0, 0, ClientWidth, ClientHeight);

  // Сброс матрицы модели
  glLoadIdentity;

  // Если нужно, можно задать перспективу
  // glFrustum (-1, 1, -1, 1, 3, 10); // задаем перспективу

  // Перерисовка окна
  InvalidateRect(Handle, nil, False);
end;

procedure TForm1.myInitOpenGL(dc:HDC);
begin
  SetDCPixelFormat(dc);
  hgc:=wglCreateContext(dc);
  wglMakeCurrent(dc,hgc);
end;

procedure TForm1.PaintGL(dc: HDC);
begin

  glMatrixMode(GL_PROJECTION);
  glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
  glClearColor(0,0,0.7,1);

  glClear(GL_COLOR_BUFFER_BIT+GL_DEPTH_BUFFER_BIT);
  glColor3f(0,1,0);
  glLoadIdentity();

  SetLight;
  glBegin(GL_QUADS);
    glVertex3f(-1,-1,-1);
    glVertex3f(-1,1,-1);
    glVertex3f(1,1,-1);
    glVertex3f(1,-1,-1);
  glEnd();

  glBegin(GL_QUADS);
    glVertex3f(-1,-1,1);
    glVertex3f(-1,1,1);
    glVertex3f(1,1,1);
    glVertex3f(1,-1,1);
  glEnd();

  glBegin(GL_QUADS);
    glVertex3f(-1,1,-1);
    glVertex3f(-1,1,1);
    glVertex3f(-1,-1,1);
    glVertex3f(-1,-1,-1);
  glEnd();

  glColor4d(0.7,0,0,0.8);

  glBegin(GL_QUADS);
    glVertex3f(1,1,-1);
    glVertex3f(1,1,1);
    glVertex3f(1,-1,1);
    glVertex3f(1,-1,-1);
  glEnd();

  glColor4f(0,1,0,1.0);

  glBegin(GL_QUADS) ;
    glVertex3f(1,1,1);
    glVertex3f(1,1,-1);
    glVertex3f(-1,1,-1);
    glVertex3f(-1,1,1);
  glEnd();

  glBegin(GL_QUADS) ;
    glVertex3f(1,-1,1);
    glVertex3f(1,-1,-1);
    glVertex3f(-1,-1,-1);
    glVertex3f(-1,-1,1);
  glEnd();

  glColor3f(0,1,1);

  glBegin(GL_QUADS);
    glVertex3f(10,-1.1,10);
    glVertex3f(10,-1.1,-10);
    glVertex3f(-10,-1.1,-10);
    glVertex3f(-10,-1.1,10);
  glend;

  glColor3f(0,1,1);

  glMatrixMode(GL_MODELVIEW);

  glLoadIdentity();
  glTranslated(0,2,0);

  glLoadIdentity();
  gluPerspective(45, ClientWidth/ClientHeight, 0.1, 100);


  //glFrustum (-2, 2, -2, 2, 3, 100);    // задаем перспективу
  //glOrtho(-2,2,-2,2,3,10);

  glTranslatef(gox, goy, goz);       // перенос объекта по оси Z
  glRotatef(tx,1,0,0);
  glRotatef(ty,0,1,0);
  glRotatef(tz,0,0,1);

  glEnable(GL_FOG);
  glFogi(GL_FOG_MODE, GL_LINEAR);
  glFogiv(GL_FOG_COLOR, @glFog_COLOR);
  glFog(GL_FOG_DENSITY, 0.35);
  glFog(GL_FOG_HINT, GL_DONT_CARE);
  glFog(GL_FOG_START, 5.0);
  glFog(GL_FOG_END, -5.0);

  SwapBuffers(dc);

end;

procedure TForm1.SetDCPixelFormat(DC: HDC);
var
  nPixelFormat: Integer;
  pfd: PIXELFORMATDESCRIPTOR;
begin
  FillChar(pfd, SizeOf(pfd), 0);
  pfd.nSize := SizeOf(PIXELFORMATDESCRIPTOR); // Установка размера структуры
  pfd.dwFlags := PFD_DRAW_TO_WINDOW or PFD_SUPPORT_GDI or PFD_GENERIC_ACCELERATED or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER;
  pfd.cDepthBits := 32;

  nPixelFormat := ChoosePixelFormat(DC, @pfd);
  if nPixelFormat = 0 then
  begin
    // Обработка ошибки: не удалось выбрать формат пикселей
    Exit;
  end;

  if SetPixelFormat(DC, nPixelFormat, @pfd) = False then
  begin
    // Обработка ошибки: не удалось установить формат пикселей
    Exit;
  end;
end;

procedure TForm1.SetLight;
begin
  glDisable(GL_LIGHTING);
  glDisable(GL_LIGHT0);
  glLightfv(GL_LIGHT0, GL_AMBIENT, @LightAmb);
  glLightfv(GL_LIGHT0, GL_POSITION, @lightPos);
  glLightfv(GL_LIGHT0, GL_DIFFUSE, @lightDif);
  glEnable(GL_LIGHT0);
  glEnable(GL_LIGHTING);
end;

procedure TForm1.tmr1Timer(Sender: TObject);
begin
  Refresh;
  tmr1.Free;
end;

procedure TForm1.tmr2Timer(Sender: TObject);
begin
  Form1.Caption:='x='+FloatToStr(tx)+'  y='+FloatToStr(ty)+' z='+FloatToStr(tz)+' goX='+FloatToStr(gox)+' goY='+FloatToStr(goy)+'  goZ='+FloatToStr(goz)+' FPS='+FloatToStr(fpsRate);
  InvalidateRect(Handle, nil, False);
end;

end.

 

Пример кода на Delphi и OpenGL, показывающий интересный визуальный эффект

 

В Интернет нашёл код на Delphi + GDI (Ссылка), перевёл этот код на Delphi + OpenGL. Вышел интересный визуальный эффект. 

 

Рисунок 1. Результат работы программы

Код проекта:

unit ogl_p1_u1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, OpenGL, ExtCtrls;

type
  TForm1 = class(TForm)
    tmr1: TTimer;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure tmr1Timer(Sender: TObject);
    procedure FormResize(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

type
  TRGB = record
    B, G, R: Byte;
  end;

  ARGB = array[0..0] of TRGB;
  PARGB = ^ARGB;

var
  Form1: TForm1;
  MyBmp: TBitmap;
  i: Byte = 0;
  hrc: HGLRC; // Контекст OpenGL
  FHDC: HDC;  // Контекст устройства

implementation

{$R *.dfm}

const
  pfd: TPixelFormatDescriptor = (
    nSize: SizeOf(TPixelFormatDescriptor);
    nVersion: 1;
    dwFlags: PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER;
    iPixelType: PFD_TYPE_RGBA;
    cColorBits: 24;
    cDepthBits: 16;
    iLayerType: PFD_MAIN_PLANE;
  );

procedure SetupOrthoProjection;
begin
  glViewport(0, 0, Form1.ClientWidth, Form1.ClientHeight);

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity;
  glOrtho(0, Form1.ClientWidth, 0, Form1.ClientHeight, -1, 1);

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity;

  glDisable(GL_DEPTH_TEST);
end;

procedure InitOpenGL;
begin
  // Настройка OpenGL
  glClearColor(0.0, 0.0, 0.0, 0.0);
  SetupOrthoProjection;
end;

procedure CreateOpenGLContext;
begin
  FHDC := GetDC(Form1.Handle); // Получаем контекст устройства
  if FHDC = 0 then
    raise Exception.Create('Не удалось получить контекст устройства.');

  // Устанавливаем формат пикселей
  if not SetPixelFormat(FHDC, ChoosePixelFormat(FHDC, @pfd), @pfd) then
    raise Exception.Create('Не удалось установить формат пикселей.');

  // Создаем контекст OpenGL
  hrc := wglCreateContext(FHDC);
  if hrc = 0 then
    raise Exception.Create('Не удалось создать контекст OpenGL.');

  // Активируем контекст OpenGL
  if not wglMakeCurrent(FHDC, hrc) then
    raise Exception.Create('Не удалось активировать контекст OpenGL.');
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  // Задаем фиксированные размеры для Bitmap
  MyBmp := TBitmap.Create;
  MyBmp.PixelFormat := pf24bit;
  MyBmp.Width := Form1.ClientWidth; // Фиксированная ширина
  MyBmp.Height := Form1.ClientHeight; // Фиксированная высота

  // Настраиваем таймер
  tmr1.Interval := 50;
  tmr1.Enabled := True;

  CreateOpenGLContext;
  // Инициализация OpenGL
  InitOpenGL;
end;

procedure Draw;
var
  LinePointer: PARGB;
  a, b: Real;
  x, y: Integer;
  xPos, yPos: GLfloat;
begin
  // Заполняем Bitmap данными
  for y := 0 to (MyBmp.Height - 1) do
  begin
    LinePointer := MyBmp.ScanLine[y];
    for x := 0 to (MyBmp.Width - 1) do
    begin
      a := x * x + i;
      b := y * y + i;
      LinePointer[x].R := Trunc(Abs(b));
      LinePointer[x].G := Trunc(Abs(a + b));
      LinePointer[x].B := Trunc(Abs(a));
    end;
  end;

  // Очищаем буфер и отрисовываем Bitmap
  glClear(GL_COLOR_BUFFER_BIT);

  // Вычисляем позицию для центрирования
  xPos := Abs(Form1.ClientWidth - MyBmp.Width) div 2;
  yPos := Abs(Form1.ClientHeight - MyBmp.Height) div 2;

  //glRasterPos2f(-1, -1);
  glRasterPos2f(xPos, yPos);
  glDrawPixels(MyBmp.Width, MyBmp.Height, GL_RGB, GL_UNSIGNED_BYTE, LinePointer);
  SwapBuffers(FHDC); // Обмениваем буферы
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  // Освобождаем ресурсы
  if Assigned(MyBmp) then
    MyBmp.Free;

  if hrc <> 0 then
  begin
    wglMakeCurrent(0, 0);
    wglDeleteContext(hrc);
  end;

  if FHDC <> 0 then
    ReleaseDC(Form1.Handle, FHDC);
end;

procedure TForm1.tmr1Timer(Sender: TObject);
begin
  Draw;
  Inc(i);
end;

procedure TForm1.FormResize(Sender: TObject);
begin
  if (Form1.ClientWidth < 640) or (Form1.ClientHeight < 480) then
  begin
      MyBmp.Width := Form1.ClientWidth; // Фиксированная ширина
      MyBmp.Height := Form1.ClientHeight; // Фиксированная высота
  end
  else
  begin
      MyBmp.Width := 640; // Фиксированная ширина
      MyBmp.Height := 480; // Фиксированная высота
  end;

  SetupOrthoProjection;
end;

end.

 

воскресенье, 31 августа 2025 г.

Ошибка 0x0000011b: Как исправить сбой подключения к общему принтеру в Windows 10

При попытке подключить общий принтер \\pc01\printer01 выдаётся сообщение «Windows не удалось подключиться к принтеру» с ошибкой 0x0000011b. Решение этой проблемы я нашёл на странице сайта https://remontka.pro/0x0000011b-error-printer/. Здесь я опишу способ, который помог именно мне. Если он не сработает для вас, то в упомянутой статье есть и другие методы решения этой ошибки, возможно, они вам помогут.

Для исправления ошибки 0x0000011b с сообщением «Windows не удалось подключиться к принтеру» необходимо на компьютере, к которому физически подключён принтер (в моём случае это pc01), сделать следующее:

  1. Откройте Редактор реестра.

  2. Перейдите в ветку:
    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print

  3. Создайте параметр DWORD (32 бита).

  4. Дайте ему имя RpcAuthnLevelPrivacyEnabled.

  5. Присвойте ему значение 0.

  6. Перезагрузите компьютер pc01.

После перезагрузки попробуйте с pc02 перейти на компьютер pc01 и заново подключить общий принтер printer01. Ошибка должна исчезнуть, и принтер будет успешно подключён.

Борьба с тормозами в Excel 2016: удаляем скрытые объекты

Проблема: Одной из частых причиной сильного замедления работы больших файлов Excel 2016 (например, размером от 30 МБ) являются скрытые графические объекты (Смотрите рисунок 1).

Рисунок 1. Пример скрытых объектов в Excel 

Решение: Если файл начал подтормаживать, проверьте его на наличие ненужных скрытых изображений. Вот как это сделать:

  1. Откройте панель выбора:

    • Перейдите на вкладку «Главная» в ленте меню.

    • В разделе «Редактирование» нажмите кнопку «Найти и выделить».

    • В выпадающем меню выберите пункт «Область выделения». Смотрите рисунок 2.

       Рисунок 2. Открытие панели со списком объектов
       

  2. Проверьте объекты:

    • Справа откроется панель со списком всех объектов на листе. Просмотрите его и убедитесь, что эти объекты вам не нужны.

  3. Вариант А: Удаление конкретных объектов

    • На панели выделения зажмите клавишу Ctrl и щелкните левой кнопкой мыши по всем объектам, которые хотите удалить.

    • Нажмите клавишу Delete.

  4. Вариант Б: Массовое удаление всех объектов

    • На вкладке «Главная» в разделе «Редактирование» нажмите «Найти и выделить» -> «Перейти». Смотрите рисунок 3.

    • В диалоговом окне «Переход» нажмите кнопку «Выделить». Смотрите рисунок 4.

    • В новом окне «Выделить группу ячеек» выберите опцию «объекты» и нажмите «OK». Все объекты на листе будут выделены. Смотрите рисунок 5.

    • Нажмите Ctrl + Delete для удаления.

Рисунок 3.  Вызов диалога "Переход"
 
Рисунок 4. Диалог "Переход"

 
Рисунок 5. Диалог "Выделить группу ячеек"
 
Рисунок 6. Пример выделенных скрытых объектов Excel

Важно! Процесс удаления большого количества объектов может занять значительное время (иногда несколько часов). Дождитесь его полного завершения, не закрывая программу.

Результат: После очистки файл может значительно уменьшиться в размере (например, с 30 МБ до 300 КБ, как в моем случае) и начать работать гораздо быстрее.

Установка .NET Framework 3.5 без подключения к интернету

Если вы пытались установить .NET Framework 3.5 через официальный установщик Microsoft или функцию «Включение или отключение компонентов Windows» без подключения к интернету и получили ошибку (Смотрите рисунок 1) о том, что для установки требуется подключение к сети, у меня для вас есть решение.

Рисунок 1. Ошибка установки .NET Framework 3.5 

Существует способ установить .NET Framework 3.5 без интернета, но при одном условии: у вас должен быть в наличии архив с необходимыми файлами. Этот архив можно получить из официального ISO-образа Windows 10 (скачанного с сайта Microsoft) той же версии, что установлена на вашем компьютере. Например, если у вас стоит Windows 10 22H2, то и образ вам понадобится именно Windows 10 22H2.

  1. Откройте ISO-образ с помощью архиватора (например, 7Zip).

  2. Найдите внутри папку sources.

  3. Перейдите в папку sxs — в ней и находится нужный файл.

  4. Его имя будет примерно таким: microsoft-windows-netfx3-ondemand-package~31bf3856ad364e35~amd64~~.cab. Скопируйте этот файл на компьютер, на котором нужно произвести установку.

Допустим, вы скопировали файл в папку C:\Temp. Далее:

  1. Запустите командную строку от имени администратора (в заголовке окна должно быть указано «Администратор»).
  2. Перейдите в папку с файлом с помощью команды: cd /d C:\Temp
  3. Выполните команду: dism.exe /Online /Enable-Feature /FeatureName:NetFx3 /All /Source:C:\Temp /LimitAccess

После выполнения этой команды .NET Framework 3.5 будет установлен на ваш компьютер без необходимости подключения к интернету (Смотрите рисунок 2).

Рисунок 2. Установка .NET Framework 3.5  

понедельник, 25 августа 2025 г.

Начальный пример подключения библиютеки Three.js в веб-проекте

Three.js – это JavaScript-библиотека для создания 3D-графики. Для создания начального примера я отправился на официальный сайт разработчиков (https://threejs.org/).

Первым делом я скачал библиотеку с GitHub (https://github.com/mrdoob/three.js/archive/master.zip). На компьютере я создал папку проекта с именем web_p1. После распаковки архива я скопировал папку build в мой проект web_p1. В этой папке находится файл three.module.js – это и есть библиотека Three.js.

Затем в папке проекта web_p1 я создал стартовый файл index.html, в который планировал подключить библиотеку.

Как подключить библиотеку Three.js в HTML-файле?

  1. В документации на официальном сайте предлагается установить среду выполнения Node.js и библиотеку three.js через менеджер пакетов npm. Этот вариант мне не подошел, так как я уже скачал библиотеку вручную.

  2. Также в документации указано, что можно подключить библиотеку с помощью HTML-тега <script> с атрибутом типа importmap. Этот вариант нам и подойдет.

Однако прежде чем привести код файла index.html с примером вращающегося зеленого куба на черном фоне (смотрите рисунок 1) , важно понять, как правильно его запустить.

Может показаться, что достаточно просто открыть index.html через проводник Windows, и он запустится в браузере. Но это не так. Пример с подключенной библиотекой Three.js не заработает, потому что современные браузеры из соображений безопасности блокируют выполнение JavaScript-модулей, загруженных напрямую с локального диска (схема file://).

Чтобы файл index.html с библиотекой Three.js работал корректно, необходимо запустить его через локальный веб-сервер. Для этого нужно установить одну из сборок, например, XAMPP, Denwer, Open Server или любой другой сервер на ваш вкус.

Порядок действий:

  1. Установите и запустите выбранный веб-сервер.

  2. Переместите папку вашего проекта web_p1 в корневую директорию веб-сервера (часто это папки htdocs или www).

  3. В адресной строке браузера перейдите по адресу локального хоста, указав путь к вашему проекту (например, http://localhost:8080/web_p1/ или http://localhost/web_p1/). Точный адрес зависит от конфигурации вашего сервера.

 Код проекта:

<!DOCTYPE html>
<html lang="en">
<head>
<title>My first three.js app</title>
</head>
<body>
<script type="importmap">
{
"imports": {
"three": "./build/three.module.js"
}
}</script>

<script type="module">
import * as THREE from "three";
console.log(THREE);

// Создаем сцену
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();

renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// Создаем куб
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

camera.position.z = 5;

// Анимация
function animate() {
requestAnimationFrame(animate);

cube.rotation.x += 0.01;
cube.rotation.y += 0.01;

renderer.render(scene, camera);
}

animate();
</script>
</body>
</html>

 

Рисунок 1. Пример работы библиотеки Three.js в браузере Firefox

понедельник, 18 августа 2025 г.

Проблемы с проводником Windows 10 при работе с сетевыми папками

В данной статье я рассмотрю две проблемы проводника Windows 10, с которыми столкнулся при работе с сетевыми папками и файлами на общем файловом сервере в локальной сети. Возможно, эти проблемы возникают из-за низкой скорости работы локальной сети.

1. Проводник зависает при работе с файлами на сервере

Если проводник Windows 10 зависает при попытке работы с файлами и папками на файловом сервере (так, что помогает только принудительное завершение процесса explorer.exe через Диспетчер задач), проблема может быть связана с включённой областью предварительного просмотра.

Эта функция позволяет просматривать содержимое документов прямо в проводнике, но при медленном сетевом соединении она может вызывать зависания.

Решение:
Отключите область просмотра в проводнике:

  1. Откройте проводник.

  2. Перейдите на вкладку «Вид» в ленте меню.

  3. В разделе «Области» нажмите кнопку «Область просмотра», чтобы она стала неактивной (подсветка пропадёт).

После этого проводник должен перестать зависать. Смотрите рисунок 1.


Рисунок 1. Отключение предварительного просмотра в проводнике Windows 10 
 

2. Некорректный поиск файлов на сервере

Если при поиске файлов по имени в проводнике Windows 10 (на файловом сервере в локальной сети) вместо нужных результатов вы получаете нерелевантные файлы, проблема связана с настройками поиска.

По умолчанию проводник ищет совпадения не только в именах файлов, но и в их содержимом. В медленной сети это может приводить к бесконечному поиску или некорректным результатам.

Решение:
Отключите поиск в содержимом файлов, оставив только поиск по именам:

  1. Откройте проводник.

  2. Перейдите на вкладку «Поиск»«Параметры поиска».

  3. Выберите «Дополнительные параметры».

  4. Снимите опцию с параметра «Содержимое файлов» чтобы она не была активна.

После этого поиск будет работать корректно. Смотрите рисунок 2.

 

 
Рисунок 2. Отключение поиска содержимого фалов в проводнике Windows 10

Как скрыть и отобразить документ в окне Excel 2016

Если при открытии любого документа формата XLS или XLSX Вы видите пустое окно, то, возможно, окно открываемого документа скрыто, и его необходимо отобразить. Эта возможность в Excel 2016 называется "Скрыть/Отобразить текущее окно". Данная функция находится на ленте меню "Вид" в разделе "Окно". Должна быть активна кнопка "Отобразить" (Смотрите рисунок 1 и рисунок 2). Если Вы нажмете на кнопку "Отобразить", то, скорее всего, Вы увидите окно Вашего скрытого документа.

Рисунок 1. Кнопка Скрыть/Отобразить документ 
 
 Рисунок 2. Выбор скрытого окна книги


Внимание! Если Вы скрываете документ с помощью этой функции Excel 2016, то при закрытии окна Excel документа в этом состоянии и последующем открытии документ будет находиться в скрытом состоянии, пока Вы не нажмете кнопку "Отобразить" на ленте меню "Вид" в разделе "Окно". Многие пользователи нажимали на кнопку "Скрыть", видели, что документ исчезал в окне Excel 2016, после этого закрывали Excel 2016 и пытались открыть документ заново, и, соответственно, окно Excel 2016 было пустым, так как документ в нем был скрыт.

Возможность скрывать документ в Excel, скорее всего, разработчики Microsoft создали на тот случай, если Excel 2016 будет работать в многодокументном режиме, т.е. режиме, позволяющем в одном окне Excel 2016 открывать множество документов Excel. Тогда в этом случае кнопки "Скрыть" и "Отобразить" для множества дочерних окон Excel 2016 имеют смысл. Однако многодокументное отображение Excel 2016 у многих отключено или не работает, так как пользователям неудобно работать с более чем одним документом Excel в одном открытом окне Excel 2016.

Не открываются ссылки e1c на документ 1С:8.3 в HCL Notes 12.0.2

Если в HCL Notes 12.0.2 вам пришло письмо со ссылкой на документ 1С:8.3 вида e1c://<ссылка_на_документ_1С>, но при нажатии на неё не открывается, а вместо этого запускается браузер Windows 10 (установленный по умолчанию), то для решения проблемы необходимо установить HCL Notes 12.0.2 Fix Pack 6 (или более новую версию).

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

воскресенье, 2 февраля 2025 г.

Пример приложения печатающий текст в стиле терминала из фильма Matrix "Матрица"

Спустя 12 лет довел до ума пример приложения, который печатает текст в стиле терминала из фильма Матрица с DelphiX на OpenGL. Оригинальный пример, на основе которого сделан мой пример, взят с сайта Delphi-Graphics. Мой код базируется на Delphi, OpenGL, WinAPI. Код моего примера оставляю без комментарий, т. к. написание проводилось без детального разбора работы алгоритма оригинального приложения и осуществлялся банальный подбор функций OpenGL и их параметров. На рисунке 1 представлена работа моего примера в Windows 10. 

Рисунок 1. Пример приложения вывода текста в стиле терминала из фильма "Матрица"

program matrix;

uses
  Windows,
  Messages,
  OpenGL;

var
  h_Rc: HGLRC;
  h_Dc: HDC;
  h_Wnd: HWND;
  base: GLuint;

  keys: array [0..255] of BOOL;

  text: array[0..4] of String = ('Wake up, Neo.',
                                 'The Matrix has you.',
                                 'Follow the White Rabbit.',
                                 'Disconnecting...',
                                 '');

  Active: bool = true;
  FullScreen:bool = true;
  f,z: boolean;
  a,b: byte;
  sx: integer;
  cur: byte;
  all: string;

procedure ReSizeGLScene(Width: GLsizei; Height: GLsizei);
begin
  if (Height=0) then
     Height:=1;
  glViewport(0, 0, Width, Height);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(0, Width, Height, 0, 1, -1);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity;
end;

procedure BuildFont;
var
  font: HFONT;
  oldfont: HFONT;
begin

  base := glGenLists(96);

  font := CreateFont( -30,
                        0,
                        0,
                        0,
                        FW_BOLD,
                        0,
                        0,
                        0,
                        ANSI_CHARSET,
                        OUT_TT_PRECIS,
                        CLIP_DEFAULT_PRECIS,
                        ANTIALIASED_QUALITY,
                        FF_DONTCARE or DEFAULT_PITCH,
                        'Courier New');

  oldfont := SelectObject(h_DC, font);                       
  wglUseFontBitmaps(h_DC, 32, 96, base);
  SelectObject(h_DC, oldfont);
  DeleteObject(font);
end;

procedure KillFont;
begin
  glDeleteLists(base, 96);
end;

procedure glPrint(const Fmt: String);
begin

if Fmt = '' then
  Exit;

glPushAttrib(GL_LIST_BIT);
glListBase(base - 32);
glCallLists(Length(Fmt), GL_UNSIGNED_BYTE, Pointer(Fmt));
glPopAttrib();

end;

function IntToStr(Num: Integer) : String;
begin
  Str(Num, Result);  
end;

function InitGL:bool;
begin

  glClearColor(0.0, 0.0, 0.0, 0.0);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(0, 640, 480, 0, 0, 1);
  glDisable(GL_DEPTH_TEST);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();

  BuildFont();

  a:=0;
  b:=0;
  sx:=0;
  cur:=0;

  Result:=true;
end;

procedure addchar;
begin
  if length(all)=length(text[cur]) then
  begin
    inc(cur);
    sx:=0;
    z:=false;
    all:='';
    Exit;
  end;
  if cur<=5 then
  begin
    all := all + text[cur][length(all)+1];
  end
  else
  begin
    exit;
  end;
end;

function DrawGLScene():bool;
var
  i: integer;
  kk2:integer;
  kk: integer;
begin
  glClear(GL_COLOR_BUFFER_BIT);

  glEnable(GL_ALPHA_TEST);
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  glLoadIdentity();

  if not z then
    inc(sx);
  if sx=200 then
    z:=true;

  if z then
  begin
    inc(B);
    if b=20 then addchar;
    if b>20 then b:=0;
  end;

  if not f then
    inc(a,5)
  else dec(a,5);

  if (a>=255)or(a=0) then f:=not f;

  glColor3f(0.196078, 0.8, 0.196078);
  for i := 0 to cur - 1 do
  begin
    glRasterPos2f(0.0, 20.0 + i*30);
    glPrint(text[i]);
  end;

  if i=5 then
  begin
    i:=0;
    cur:=0;
    a:=0;
    b:=0;
    sx:=0;
    z:=false;
    f:=False;
    all:='';
    glClearColor(0, 0, 0, 0);
    glClear(GL_COLOR_BUFFER_BIT);
  end;

  kk := 18*length(all);
  kk2 := cur*30;

  glRasterPos2f(0.0, 20.0 + cur*30);
  glPrint(all);

  glColor4f(0.196078, 0.8, 0.196078, a / 255); // Colour LimeGreen
  glRectf(0.0+kk, 0.0+kk2, 23.0+kk, 23.0+kk2);

  glDisable(GL_BLEND);
  glDisable(GL_ALPHA_TEST);

  Result := true;
end;


function WndProc(hWnd: HWND;
                 message: UINT;
                 wParam: WPARAM;
                 lParam: LPARAM):
                                  LRESULT; stdcall;
begin
  if message=WM_SYSCOMMAND then
  begin
      case wParam of
        SC_SCREENSAVE,SC_MONITORPOWER:
          begin
            result:=0;
            exit;
          end;
      end;
  end;
  
  case message of
    WM_ACTIVATE:
      begin
        if (Hiword(wParam)=0) then
          active:=true
        else
          active:=false;
        Result:=0;
      end;
    WM_CLOSE:
      Begin
        PostQuitMessage(0);
        result:=0
      end;
    WM_KEYDOWN:
      begin
        keys[wParam] := TRUE;
        result:=0;
      end;
    WM_KEYUP:
      begin
    	  keys[wParam] := FALSE;
        result:=0;
      end;
    WM_SIZe:
      begin
    	  ReSizeGLScene(LOWORD(lParam),HIWORD(lParam));
        result:=0;
      end
    else

      begin
      	Result := DefWindowProc(hWnd, message, wParam, lParam);
      end;
    end;
end;


procedure KillGLWindow;
begin
  if FullScreen then
    begin
      ChangeDisplaySettings(devmode(nil^),0);
      showcursor(true);
    end;
  if h_rc<> 0 then
    begin
      if (not wglMakeCurrent(h_Dc,0)) then
        MessageBox(0,'Release of DC and RC failed.',' Shutdown Error',MB_OK or MB_ICONERROR);
      if (not wglDeleteContext(h_Rc)) then
        begin
          MessageBox(0,'Release of Rendering Context failed.',' Shutdown Error',MB_OK or MB_ICONERROR);
          h_Rc:=0;
        end;
    end;
  if (h_Dc=1) and (releaseDC(h_Wnd,h_Dc)<>0) then
    begin
      MessageBox(0,'Release of Device Context failed.',' Shutdown Error',MB_OK or MB_ICONERROR);
      h_Dc:=0;
    end;
  if (h_Wnd<>0) and (not destroywindow(h_Wnd))then
    begin
      MessageBox(0,'Could not release hWnd.',' Shutdown Error',MB_OK or MB_ICONERROR);
      h_Wnd:=0;
    end;
  if (not UnregisterClass('OpenGL',hInstance)) then
    begin
      MessageBox(0,'Could Not Unregister Class.','SHUTDOWN ERROR',MB_OK or MB_ICONINFORMATION);
    end;
end;


function CreateGlWindow(title:Pchar; width,height,bits:integer;FullScreenflag:bool):boolean stdcall;
var
  Pixelformat: GLuint;
  wc:TWndclass;
  dwExStyle:dword;
  dwStyle:dword;
  pfd: pixelformatdescriptor;
  dmScreenSettings: Devmode;
  h_Instance:hinst;
  WindowRect: TRect;
begin
  WindowRect.Left := 0;
  WindowRect.Top := 0;
  WindowRect.Right := width;
  WindowRect.Bottom := height;
  h_instance:=GetModuleHandle(nil);
  FullScreen:=FullScreenflag;
  with wc do
    begin
      style:=CS_HREDRAW or CS_VREDRAW or CS_OWNDC;
      lpfnWndProc:=@WndProc;
      cbClsExtra:=0;
      cbWndExtra:=0;
      hInstance:=h_Instance;
      hIcon:=LoadIcon(0,IDI_WINLOGO);
      hCursor:=LoadCursor(0,IDC_ARROW);
      hbrBackground:=0;
      lpszMenuName:=nil;
      lpszClassName:='OpenGl';
    end;
  if  RegisterClass(wc)=0 then
    begin
      MessageBox(0,'Failed To Register The Window Class.','Error',MB_OK or MB_ICONERROR);
      Result:=false;
      exit;
    end;
  if FullScreen then
    begin
      ZeroMemory( @dmScreenSettings, sizeof(dmScreenSettings) );
      with dmScreensettings do
        begin
          dmSize := sizeof(dmScreenSettings);
          dmPelsWidth  := width;
	        dmPelsHeight := height;
          dmBitsPerPel := bits;
          dmFields     := DM_BITSPERPEL or DM_PELSWIDTH or DM_PELSHEIGHT;
        end;

      if (ChangeDisplaySettings(dmScreenSettings, CDS_FULLSCREEN))<>DISP_CHANGE_SUCCESSFUL THEN
        Begin

          if MessageBox(0,'This FullScreen Mode Is Not Supported. Use Windowed Mode Instead?'
                                             ,'Matrix',MB_YESNO or MB_ICONEXCLAMATION)= IDYES then
                FullScreen:=false
          else
            begin

              MessageBox(0,'Program Will Now Close.','Error',MB_OK or MB_ICONERROR);
              Result:=false;
              exit;
            end;
          end;
    end;
  if FullScreen then
    begin
      dwExStyle:=WS_EX_APPWINDOW;
      dwStyle:=WS_POPUP or WS_CLIPSIBLINGS or WS_CLIPCHILDREN;
      Showcursor(false);
    end
  else
    begin
      dwExStyle:=WS_EX_APPWINDOW or WS_EX_WINDOWEDGE;
      dwStyle:=WS_OVERLAPPEDWINDOW or WS_CLIPSIBLINGS or WS_CLIPCHILDREN;
    end;
  AdjustWindowRectEx(WindowRect,dwStyle,false,dwExStyle);

  H_wnd:=CreateWindowEx(dwExStyle,
                               'OpenGl',
                               Title,
                               dwStyle,
                               0,0,
                               WindowRect.Right-WindowRect.Left,
                               WindowRect.Bottom-WindowRect.Top,
                               0,
                               0,
                               hinstance,
                               nil);
  if h_Wnd=0 then
    begin
      KillGlWindow();
      MessageBox(0,'Window creation error.','Error',MB_OK or MB_ICONEXCLAMATION);
      Result:=false;
      exit;
    end;
  with pfd do
    begin
      nSize:= SizeOf( PIXELFORMATDESCRIPTOR );
      nVersion:= 1;
      dwFlags:= PFD_DRAW_TO_WINDOW
        or PFD_SUPPORT_OPENGL
        or PFD_DOUBLEBUFFER;
      iPixelType:= PFD_TYPE_RGBA;
      cColorBits:= bits;
      cRedBits:= 0;
      cRedShift:= 0;
      cGreenBits:= 0;
      cBlueBits:= 0;
      cBlueShift:= 0;
      cAlphaBits:= 0;
      cAlphaShift:= 0;
      cAccumBits:= 0;
      cAccumRedBits:= 0;
      cAccumGreenBits:= 0;
      cAccumBlueBits:= 0;
      cAccumAlphaBits:= 0;
      cDepthBits:= 16;
      cStencilBits:= 0;
      cAuxBuffers:= 0;
      iLayerType:= PFD_MAIN_PLANE;
      bReserved:= 0;
      dwLayerMask:= 0;
      dwVisibleMask:= 0;
      dwDamageMask:= 0;
    end;
  h_Dc := GetDC(h_Wnd);
  if h_Dc=0 then
    begin
      KillGLWindow();
      MessageBox(0,'Cant''t create a GL device context.','Error',MB_OK or MB_ICONEXCLAMATION);
      Result:=false;
      exit;
    end;
  PixelFormat := ChoosePixelFormat(h_Dc, @pfd);
  if (PixelFormat=0) then
    begin
      KillGLWindow();
      MessageBox(0,'Cant''t Find A Suitable PixelFormat.','Error',MB_OK or MB_ICONEXCLAMATION);
      Result:=false;
      exit;
    end;
  if (not SetPixelFormat(h_Dc,PixelFormat,@pfd)) then
    begin
      KillGLWindow();
      MessageBox(0,'Cant''t set PixelFormat.','Error',MB_OK or MB_ICONEXCLAMATION);
      Result:=false;
      exit;
    end;
  h_Rc := wglCreateContext(h_Dc);
  if (h_Rc=0) then
    begin
      KillGLWindow();
      MessageBox(0,'Cant''t create a GL rendering context.','Error',MB_OK or MB_ICONEXCLAMATION);
      Result:=false;
      exit;
    end;
  if (not wglMakeCurrent(h_Dc, h_Rc)) then
    begin
      KillGLWindow();
      MessageBox(0,'Cant''t activate the GL rendering context.','Error',MB_OK or MB_ICONEXCLAMATION);
      Result:=false;
      exit;
    end;
  ShowWindow(h_Wnd,SW_SHOW);
  SetForegroundWindow(h_Wnd);
  SetFOcus(h_Wnd);
  ReSizeGLScene(width,height);
  if (not InitGl()) then
    begin
      KillGLWindow();
      MessageBox(0,'initialization failed.','Error',MB_OK or MB_ICONEXCLAMATION);
      Result:=false;
      exit;
    end;
  Result:=true;
end;


function WinMain(hInstance: HINST;
		 hPrevInstance: HINST;
		 lpCmdLine: PChar;
		 nCmdShow: integer):
                        integer; stdcall;
var
  msg: TMsg;
  done: Bool;

begin
  done:=false;

  if MessageBox(0,'Would You Like To Run In FullScreen Mode?','Start FullScreen', MB_YESNO or MB_ICONQUESTION)=IDNO then
    FullScreen:=false
  else
    FullScreen:=true;

  if not CreateGLWindow('Matrix',640,480,16,FullScreen) then
  begin
    Result := 0;
    exit;
  end;

  while not done do
  begin
    if (PeekMessage(msg, 0, 0, 0, PM_REMOVE)) then
    begin
      if msg.message=WM_QUIT then
        done:=true
      else
      begin
        TranslateMessage(msg);
        DispatchMessage(msg);
      end;
    end
    else
    begin

      if (Active and (not DrawGLScene()) or keys[VK_ESCAPE]) then
      begin
        done:=true;
      end;

      if (keys[VK_F1]) then
      begin
        Keys[VK_F1] := false;
        KillGLWindow();
        FullScreen := not FullScreen;

        if not CreateGLWindow('Matrix',640,480,16,fullscreen) then Result := 0;
      end;

      SwapBuffers(h_Dc);
    end;
  end;

  KillFont();
  killGLwindow();

  result:=msg.wParam;
end;

begin
  WinMain( hInstance, hPrevInst, CmdLine, CmdShow );
end.

пятница, 24 января 2025 г.

Несколько проблемных МФУ

Кому интересно, перечислю проблемные, относительно новые модели МФУ, которые я не рекомендую покупать.


Xerox VersaLink B405dn

1) Безобразно захватывает бумагу из обоих лотков. Направляющие бумаги у данного принтера реализованы плохо, из-за этого бумага идет не ровно и часто застревает. Замена роликов подачи бумаги или ролика лотка не решает проблему.

2) Печка портится очень быстро, покупка новой выходит дорого. Из-за этого МФУ придётся утилизировать.

3) Сенсорный экран может не нажиматься (Пересекался с двумя такими МФУ с такой проблемой). Может брак.

4) Оба лотка представляют из себя хлипкое изделие, которое болтается в руках как погремушка. При малейшем движение направляющие бумаги лотка разъезжаются.

Xerox WorkCentre 3345

1) Через 3-4 года сенсорный экран перестает реагировать на нажатия или сам по себе начнёт нажиматься без участия пользователя. Покупка сенсорной панели выходит очень дорого. Из-за этого МФУ придётся утилизировать.

HP Laser Jet Pro M428dnf

1) По сети документы Word или PDF печатаются с задержкой в 1 минуту на одну страницу документа. Переустановка драйверов не решает проблему.

2) Драйвера МФУ не корректно работают с масштабированием документа. Иногда в таких программах как Word, ты видишь на предварительном просмотре печати, что документ выглядит как надо, таблица заполняет всю страницу. Отправляешь на принтер, а он выдает таблицу на пол страницы, таким образом сжав таблицу по горизонтали. В свойствах драйвера это можно исправить, но каждый раз при такой проблеме необходимо заходить в свойства драйвера, чтобы распечатать документ.

HP Laser Jet Pro 4103dw

1) Такая же проблема с масштабированием как и в случае с HP Laser Jet Pro M428dnf

 

По мере накопления проблем с разными МФУ и принтерами, буду пополнять список.