我的代码在 Delphi 中。
我有 1920x1080 的背景图片和 305x3132 的第二张图片。第二张图片由 12 个高度为 261px 的标志创建。两个图像都是 32 位位图并且具有透明度。背景图像没有透明部分。大多数事情都可以正常工作,但我有两个问题。所以这是我的代码。 OpenGL 的所有代码都在单独的单元中,她就是这样。
unit OpenGLProc;
interface
uses
Winapi.Windows, Vcl.Graphics, OpenGL, Gifimg, Pngimage;
type
TTexture = record
Handle : GLuint;
Width : integer;
Height : integer;
end;
procedure InitOpenGL(DCin : HDC; FGLContext : HGLRC);
procedure LoadTexture(image : TBitmap; offsetX, offsetY, texWidth, texHeight : integer; mode : integer; out text : TTexture);
procedure DrawTexture(texIn : TTexture; width, height, winWidth, winHeight, texOffsetX, texOffsetY, offsetX, offsetY : single; flipped : integer);
procedure BindFramebufferTex(texIn : TTexture);
procedure FramebufferTexture2DTex(texIn : TTexture);
procedure UpdateTexture(inTex : TTexture; offsetXsrc, offsetYsrc, offsetXdst, offsetYdst, width, height : integer; outTex : TTexture);
type
TglGenFramebuffers = procedure(n: GLsizei; framebuffers: PGLuint); {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF}
TglBindFramebuffer = procedure(target: GLenum; framebuffer: GLuint); {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF}
TglFramebufferTexture2D = procedure(target: GLenum; attachment: GLenum; textarget: GLenum; texture: GLuint; level: GLint); {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF}
TglCopyImageSubData = procedure(srcName: GLuint; srcTarget: GLenum; srcLevel: GLint; srcX: GLint; srcY: GLint; srcZ: GLint; dstName: GLuint; dstTarget: GLenum; dstLevel: GLint; dstX: GLint; dstY: GLint; dstZ: GLint; width: GLsizei; height: GLsizei; depth: GLsizei); {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF}
var
glGenFramebuffers : TglGenFramebuffers = nil;
glBindFramebuffer : TglBindFramebuffer = nil;
glFramebufferTexture2D : TglFramebufferTexture2D = nil;
glCopyImageSubData : TglCopyImageSubData = nil;
FGLMainContext : HGLRC;
screenTex : TTexture;
screenFB : TTexture;
bckTex, signsTex : TTexture;
const
GL_FRAMEBUFFER = $8D40;
GL_COLOR_ATTACHMENT0 = $8CE0;
implementation
type
TRGBA = packed record
R, G, B, A : Byte;
end;
PRGBA = ^TRGBA;
procedure InitOpenGL(DCin : HDC; FGLContext : HGLRC);
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(DCin, @pfd);
SetPixelFormat(DCin, pf, @pfd);
glc := wglCreateContext(DCin);
wglMakeCurrent(DCin, 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);
// Enable texturing
glEnable(GL_TEXTURE_2D);
// Initialize OpnenGL functions
glGenFramebuffers := TglGenFramebuffers(wglGetProcAddress('glGenFramebuffers'));
glBindFramebuffer := TglBindFramebuffer(wglGetProcAddress('glBindFramebuffer'));
glFramebufferTexture2D := TglFramebufferTexture2D(wglGetProcAddress('glFramebufferTexture2D'));
glCopyImageSubData := TglCopyImageSubData(wglGetProcAddress('glCopyImageSubData'));
end;
procedure LoadTexture(image : TBitmap; offsetX, offsetY, texWidth, texHeight : integer; mode : integer; out text : TTexture);
var
PixelData : PByte;
Pixel : PRGBA;
x, y : integer;
row : pRGBQuadArray;
begin
case mode of
0: // empty texture will be created
begin
try
// Create and bind the texture object
glGenTextures(1, @text.Handle);
glBindTexture(GL_TEXTURE_2D, text.Handle);
text.Width := texWidth;
text.Height := texHeight;
// Set the texture parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
// Load the texture data into the texture object
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nil);
finally
end;
end;
1: // New texture will be created and populated
begin
// Allocate memory for the texture data
GetMem(PixelData, texWidth * texHeight * SizeOf(TRGBA));
try
// Copy the bitmap image data into the texture data
Pixel := PRGBA(PixelData);
for y := offsetY to texHeight - 1 do
begin
row := image.ScanLine[y];
for x := offsetX to texWidth - 1 do
begin
Pixel^.R := row[x].rgbRed;
Pixel^.G := row[x].rgbGreen;
Pixel^.B := row[x].rgbBlue;
Pixel^.A := row[x].rgbReserved;
Inc(Pixel);
end;
end;
// Create and bind the texture object
glGenTextures(1, @text.Handle);
glBindTexture(GL_TEXTURE_2D, text.Handle);
text.Width := texWidth;
text.Height := texHeight;
// Set the texture parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
// Load the texture data into the texture object
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, PixelData);
finally
FreeMem(PixelData);
end;
end;
end;
end;
procedure DrawTexture(texIn : TTexture; width, height, winWidth, winHeight, texOffsetX, texOffsetY, offsetX, offsetY : single; flipped : integer);
begin
glPushMatrix();
glTranslatef(-1 + (offsetX / winWidth * 2.0) + (width / winWidth), 1 - (offsetY / WinHeight * 2.0) - (height / winHeight), 0.0);
// Unbind the screen texture and framebuffer
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, texIn.Handle);
glBegin(GL_QUADS);
glTexCoord2f(texOffsetX / texIn.Width, (texOffsetY + height) / texIn.Height); glVertex2f(-width / winWidth, -height / winHeight);
glTexCoord2f((texOffsetX + width) / texIn.Width, (texOffsetY + height) / texIn.Height); glVertex2f(width / winWidth, -height / winHeight);
glTexCoord2f((texOffsetX + width) / texIn.Width, texOffsetY / texIn.Height); glVertex2f(width / winWidth, height / winHeight);
glTexCoord2f(texOffsetX / texIn.Width, texOffsetY / texIn.Height); glVertex2f(-width / winWidth, height / winHeight);
glEnd;
glFlush;
glPopMatrix();
end;
procedure BindFramebufferTex(texIn : TTexture);
begin
glBindFramebuffer(GL_FRAMEBUFFER, texIn.Handle);
end;
procedure FramebufferTexture2DTex(texIn : TTexture);
begin
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texIn.Handle, 0);
end;
procedure UpdateTexture(inTex : TTexture; offsetXsrc, offsetYsrc, offsetXdst, offsetYdst, width, height : integer; outTex : TTexture);
begin
glCopyImageSubData(inTex.Handle, GL_TEXTURE_2D, 0,
offsetXsrc, offsetYsrc, 0,
outTex.Handle, GL_TEXTURE_2D, 0,
offsetXdst, offsetYdst, 0,
width, height, 1);
end;
end.
现在在主要形式中我称这些程序为
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, OpenGLProc, Vcl.StdCtrls;
type
TForm1 = class(TForm)
btnClose: TButton;
btnDrawBck: TButton;
btnDrawCol: TButton;
btnDrawColOver: TButton;
procedure FormCreate(Sender: TObject);
procedure btnCloseClick(Sender: TObject);
procedure btnDrawBckClick(Sender: TObject);
procedure btnDrawColClick(Sender: TObject);
procedure btnDrawColOverClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
background, signs : TBitmap;
colTex : TTexture;
DC : HDC;
const
signHeight = 261;
implementation
{$R *.dfm}
procedure TForm1.btnCloseClick(Sender: TObject);
begin
Form1.Close;
end;
procedure TForm1.btnDrawBckClick(Sender: TObject);
begin
UpdateTexture(bckTex, 0, 0, 0, 0, bckTex.Width, bckTex.Height, screenTex);
DrawTexture(screenTex, screenTex.Width, screenTex.Height, Form1.Width, Form1.Height, 0, 0, 0, 0, 1);
SwapBuffers(Canvas.Handle);
end;
procedure TForm1.btnDrawColClick(Sender: TObject);
begin
UpdateTexture(bckTex, 0, 0, 0, 0, bckTex.Width, bckTex.Height, screenTex);
UpdateTexture(signsTex, 0, 1827, 198, 120, signsTex.Width, 3 * signHeight, screenTex);
DrawTexture(screenTex, screenTex.Width, screenTex.Height, Form1.Width, Form1.Height, 0, 0, 0, 0, 1);
SwapBuffers(Canvas.Handle);
end;
procedure TForm1.btnDrawColOverClick(Sender: TObject);
begin
UpdateTexture(signsTex, 0, 0, 0, 0, 305, signHeight, colTex);
UpdateTexture(signsTex, 0, 9 * signHeight, 0, signHeight, 305, signHeight, colTex);
UpdateTexture(signsTex, 0, 8 * signHeight, 0, 2 * signHeight - 8, 305, signHeight, colTex);
UpdateTexture(colTex, 0, 0, 503, 120, signsTex.Width, 3 * signHeight, screenTex);
DrawTexture(screenTex, screenTex.Width, screenTex.Height, Form1.Width, Form1.Height, 0, 0, 0, 0, 1);
SwapBuffers(Canvas.Handle);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
background := TBitmap.Create;
background.LoadFromFile('back1.bmp');
signs := TBitmap.Create;
signs.LoadFromFile('znakovi.bmp');
DC := GetDC(Handle);
Sleep(200);
InitOpenGL(DC, FGLMainContext);
// Create the texture for the framebuffer
LoadTexture(background, 0, 0, background.Width, background.Height, 0, screenTex);
// Set up the framebuffer
if Assigned(glGenFramebuffers) then
begin
glGenFramebuffers(1, @screenFB);
end
else
begin
ShowMessage('glGenFramebuffers is not initialized!');
end;
BindFramebufferTex(screenFB);
FramebufferTexture2DTex(screenTex);
LoadTexture(background, 0, 0, background.Width, background.Height, 1, bckTex);
LoadTexture(signs, 0, 0, signs.Width, signs.Height, 1, signsTex);
LoadTexture(signs, 0, 0, signs.Width, signs.Height, 0, colTex);
end;
end.
所以这是我的问题。
当我只点击按钮 btnDrawCol 时,第二个纹理的透明部分在屏幕上是黑色的。背景纹理没问题,第二个纹理的非透明部分没问题,但为什么透明部分是黑色的????
奇怪的是,当我第一次点击按钮 btnDrawBck(这只会在屏幕上绘制背景)然后点击按钮 btnDrawCol 一切正常。为什么?
第二个更大的问题。我想切割第二个纹理的部分并从中创建第三个纹理。一切都很好(除了上面的问题),直到我尝试重叠部分。例如,我切割了三个部分,第三部分与第二部分重叠 8 px 第二部分的最后 8 px 完全透支,即使第三部分中的线条是透明的。
我张贴一张图片作为例子。左侧是重叠的。我只需要上面的非透明部分透支内容(黄色框架应该接触)。