OpenGL和 Delphi -绘制png图像(D2纹理)

7nbnzgx9  于 2023-03-12  发布在  其他
关注(0)|答案(1)|浏览(252)

我不能将PNG图像加载到2D纹理中并在窗体上绘制。
我需要非常快地绘制大量透明的png图像,这些图像是从一个较大的png图像中剪切出来的,在准备好的背景上,然后显示在屏幕上。
我不想使用任何控件,如果可能的话,尽量避免使用外部库。只是使用来自 Delphi 和OpenGL单元的Pngimage。
我能够在窗体上绘制位图图像,下面是我的代码:

procedure TForm1.InitOpenGL;
var
  PixelFormat: GLuint;
  pfd: TPixelFormatDescriptor;
begin
  ZeroMemory(@pfd, SizeOf(pfd));
  pfd.nSize := SizeOf(pfd);
  pfd.nVersion := 1;
  pfd.dwFlags := PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER;
  pfd.iPixelType := PFD_TYPE_RGBA;
  pfd.cColorBits := 32;
  pfd.cDepthBits := 24;
  pfd.iLayerType := PFD_MAIN_PLANE;

  hdc := GetDC(Handle);
  PixelFormat := ChoosePixelFormat(hdc, @pfd);
  SetPixelFormat(hdc, PixelFormat, @pfd);

  hrc := wglCreateContext(hdc);
  wglMakeCurrent(hdc, hrc);

  glEnable(GL_TEXTURE_2D);

  glGenTextures(1, @renderImage);
  glBindTexture(GL_TEXTURE_2D, renderImage);

  bmp := TBitmap.Create;
  try
    bmp.LoadFromFile(imageFilename);
    gluBuild2DMipmaps(GL_TEXTURE_2D, 3, bmp.Width, bmp.Height, GL_BGR, GL_UNSIGNED_BYTE, bmp.ScanLine[bmp.Height - 1]);
  finally
    //bmp.Free;
  end;

  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

  glClearColor(0.0, 0.0, 0.0, 0.0);
end;

procedure TForm1.DrawScene;
var
  imageWidth, imageHeight: Integer;
begin
  glClear(GL_COLOR_BUFFER_BIT);

  // Get the width and height of the image
  glBindTexture(GL_TEXTURE_2D, renderImage);
  glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, @imageWidth);
  glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, @imageHeight);

  // Translate the quad to the center of the form
  glTranslatef(0, 0, 0);

  // Draw the quad with the adjusted vertices
  glBegin(GL_QUADS);
    glTexCoord2f(0, 0); glVertex2f(-bmp.Width/Form1.Width, -bmp.Height/Form1.Height);
    glTexCoord2f(1, 0); glVertex2f(bmp.Width/Form1.Width, -bmp.Height/Form1.Height);
    glTexCoord2f(1, 1); glVertex2f(bmp.Width/Form1.Width, bmp.Height/Form1.Height);
    glTexCoord2f(0, 1); glVertex2f(-bmp.Width/Form1.Width, bmp.Height/Form1.Height);
  glEnd;

  SwapBuffers(hdc);
end;

但是ping的代码不起作用。在一些尝试中,我能够在屏幕上得到一些东西(随机像素几行),但我卡住了。PNG图像是在Gimp中创建的。
下面是代码。

procedure TForm1.InitOpenGL;
var
  PixelFormat: GLuint;
  pfd: TPixelFormatDescriptor;
begin
  ZeroMemory(@pfd, SizeOf(pfd));
  pfd.nSize := SizeOf(pfd);
  pfd.nVersion := 1;
  pfd.dwFlags := PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER;
  pfd.iPixelType := PFD_TYPE_RGBA;
  pfd.cColorBits := 32;
  pfd.cDepthBits := 24;
  pfd.iLayerType := PFD_MAIN_PLANE;

  hdc := GetDC(Handle);
  PixelFormat := ChoosePixelFormat(hdc, @pfd);
  SetPixelFormat(hdc, PixelFormat, @pfd);

  hrc := wglCreateContext(hdc);
  wglMakeCurrent(hdc, hrc);

  glEnable(GL_TEXTURE_2D);

  glGenTextures(1, @renderImage);
  glBindTexture(GL_TEXTURE_2D, renderImage);

  png := TPngImage.Create;
  try
    png.LoadFromFile('image.png');
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, png.Width, png.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, png.AlphaScanline[png.Height - 1]);
  finally
    png.Free;
  end;
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

  glClearColor(0.0, 0.0, 0.0, 0.0);
end;

procedure TForm1.DrawScene;
var
  imageWidth, imageHeight: Integer;
begin
  glClear(GL_COLOR_BUFFER_BIT);

  // Get the width and height of the image
  glBindTexture(GL_TEXTURE_2D, renderImage);
  glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, @imageWidth);
  glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, @imageHeight);

  // Translate the quad to the center of the form
  glTranslatef(0, 0, 0);

  // Draw the quad with the adjusted vertices
  glBegin(GL_QUADS);
    glTexCoord2f(0, 0); glVertex2f(-png.Width/Form1.Width, -png.Height/Form1.Height);
    glTexCoord2f(1, 0); glVertex2f(png.Width/Form1.Width, -png.Height/Form1.Height);
    glTexCoord2f(1, 1); glVertex2f(png.Width/Form1.Width, png.Height/Form1.Height);
    glTexCoord2f(0, 1); glVertex2f(-png.Width/Form1.Width, png.Height/Form1.Height);
  glEnd;

  SwapBuffers(hdc);
end;

现在我没有得到任何错误,但没有绘制任何内容。

kokeuurv

kokeuurv1#

好的,这是从所需的点(左上角)绘制png图像或部分图像的代码。它只使用 Delphi 和OpenGL。现在它使用固定的管道,我将尝试切换到着色器,但这对我来说是一个很大的进步。

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Winapi.OpenGL, PngImage;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormPaint(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
    FGLContext: HGLRC;
    FTexture: GLuint;
    FPngImage: TPngImage;
    procedure InitOpenGL;
    procedure LoadTexture;
    procedure DrawTexture(width, height, texWidth, texHeight, texOffsetX, texOffsetY, offsetX, offsetY: single);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

type
  TRGBA = packed record
    R, G, B, A: Byte;
  end;

  PRGBA = ^TRGBA;

procedure TForm1.FormCreate(Sender: TObject);
begin
  InitOpenGL;
  FPngImage := TPngImage.Create;
  FPngImage.LoadFromFile('image.png');
  LoadTexture;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  if FTexture <> 0 then
    glDeleteTextures(1, @FTexture);
  FPngImage.Free;
  wglDeleteContext(FGLContext);
end;

procedure TForm1.FormPaint(Sender: TObject);
begin
  DrawTexture(100, 49, 250, 180, 70, 50, 10, 15);
end;

procedure TForm1.InitOpenGL;
var
  pfd: TPixelFormatDescriptor;
  pf: Integer;
  glc: HGLRC;
begin
  ZeroMemory(@pfd, SizeOf(TPixelFormatDescriptor));
  pfd.nSize := SizeOf(TPixelFormatDescriptor);
  pfd.nVersion := 1;
  pfd.dwFlags := PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER;
  pfd.iPixelType := PFD_TYPE_RGBA;
  pfd.cColorBits := 24;
  pfd.cDepthBits := 32;
  pf := ChoosePixelFormat(Canvas.Handle, @pfd);
  SetPixelFormat(Canvas.Handle, pf, @pfd);
  glc := wglCreateContext(Canvas.Handle);
  wglMakeCurrent(Canvas.Handle, glc);
  FGLContext := glc;

  // Enable blending
  glEnable(GL_BLEND);

  // Set the blend function to take alpha into account
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glClearColor(0.0, 0.5, 0.0, 0.0);
end;

procedure TForm1.LoadTexture;
var
  PixelData: PByte;
  Pixel: PRGBA;
  x, y: Integer;
  Color: TColor;
begin
  // Allocate memory for the texture data
  GetMem(PixelData, FPngImage.Width * FPngImage.Height * SizeOf(TRGBA));
  try
    // Copy the PNG image data into the texture data
    Pixel := PRGBA(PixelData);
    for y := 0 to FPngImage.Height - 1 do
    begin
      for x := 0 to FPngImage.Width - 1 do
      begin
        Color := FPngImage.Canvas.Pixels[x, y];
        Pixel^.R := GetRValue(Color);
        Pixel^.G := GetGValue(Color);
        Pixel^.B := GetBValue(Color);
        Pixel^.A := FPngImage.AlphaScanline[y]^[x];
        Inc(Pixel);
      end;
    end;

    // Create and bind the texture object
    glGenTextures(1, @FTexture);
    glBindTexture(GL_TEXTURE_2D, FTexture);

    // Set the texture parameters
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    // Load the texture data into the texture object
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, FPngImage.Width, FPngImage.Height, 0,
      GL_RGBA, GL_UNSIGNED_BYTE, PixelData);

    // Enable texturing
    glEnable(GL_TEXTURE_2D);
  finally
    FreeMem(PixelData);
  end;
end;

procedure TForm1.DrawTexture(width, height, texWidth, texHeight, texOffsetX, texOffsetY, offsetX, offsetY: single);
begin
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  glBindTexture(GL_TEXTURE_2D, FTexture);

  glPushMatrix();
  glTranslatef(-1 + (offsetX / Form1.Width * 2.0) + (width / Form1.Width), 1 - (offsetY / Form1.Height * 2.0) - (height / Form1.Height), 0.0);

  glBegin(GL_QUADS);
    glTexCoord2f(texOffsetX / texWidth, (texOffsetY + height) / texHeight); glVertex2f(- width / Form1.Width, - height / Form1.Height);
    glTexCoord2f((texOffsetX + width) / texWidth, (texOffsetY + height) / texHeight); glVertex2f(width / Form1.Width, - height / Form1.Height);
    glTexCoord2f((texOffsetX + width) / texWidth, texOffsetY / texHeight); glVertex2f(width / Form1.Width, height / Form1.Height);
    gltexCoord2f(texOffsetX / texWidth, texOffsetY / texHeight); glVertex2f(- width / Form1.Width, height / Form1.Height);
  glEnd;

  glFlush;
  SwapBuffers(Canvas.Handle);
end;

end.

所需的纹理参数和绘制起点作为调用DrawTexture过程的参数传递。
我希望这能成为刚开始使用OpenGL的人的一个起点。

相关问题