В конце два варианте FrameBufferunit. Та что без GL, GLu, GLext - пробовал, это реализация: {= Получение контекста для вывода ф-ми OpenGL на экран ========} function TForm1.GetScreenContext(const CanHandle: THandle): HGLRC; var nPixelFormat: Integer; PFD: TPixelFormatDescriptor; begin { См. Краснов, Ex25 - MDI, Глава 1 } {................. Устанавливаем формат пикселей .....................} FillChar(PFD, SizeOf(PFD), 0); With PFD do begin nSize := SizeOf(PFD); nVersion := 1; dwFlags := pfd_Draw_to_Window or pfd_Generic_Accelerated or pfd_Support_OpenGL or pfd_DoubleBuffer; iPixelType := pfd_Type_RGBA; cColorBits := 24; cDepthBits := 32; iLayerType := pfd_Main_Plane; end; nPixelFormat := ChoosePixelFormat(CanHandle, @PFD); SetPixelFormat(CanHandle, nPixelFormat, @PFD); Result := wglCreateContext(CanHandle); { Rendering Context } end; {========= Рендеринг рисунка в Bitmap с заданными размерами ==========} procedure TForm1.RenderToBitmap(ABitmap: TBitmap); var FrameBuffer: TFrameBuffer; var MyDC: HDC; GhostForm: TForm; Err:byte; FGLContext:HGLRC; s:string; begin glFinish; { Добавлено 18.11.11: ждём завершения всех GL-операций } ABitmap:=TBitmap.Create; Abitmap.PixelFormat := pf24bit; { С другими не пойдёт } ABitmap.SetSize(DrawTrans.Width,DrawTrans.Height); ABitmap.SetSize(DrawTrans.Width,DrawTrans.Height); ABitmap.Canvas.Lock; { Вспомогательная невидимая форма } GhostForm := TForm.Create(Self); GhostForm.ClientWidth := ABitmap.Width; GhostForm.ClientHeight := ABitmap.Height; { Получаем контекст для вспомогательной невидимой формы } MyDC := GetDC(GhostForm.Handle); FGLContext := GetScreenContext(MyDC); wglMakeCurrent(MyDC, FGLContext); FrameBuffer := TFrameBuffer.Create(ABitmap, Err); If Err = 0 then begin {....... Инициализация матриц проектирования и моделирования .........} // SetMatrixes(ABitmap.Width, ABitmap.Height); p:=tprogr.create(PanelErr{Trans},PanelEdit,DrawTrans,progress,false); p.is3D:=false;//is3D; p.name:='ProgrTransl'; p.isDrawBorderProgr:=true; p.isDrawEkvid:=false;//true; DrawTrans.fprogr:=p; p.open(DialogLoadSave.FileName); p.width_ekvid:=0;//Form_Const_Tools_New_DC_Width_sharp.Value/10; p.isCirclePrir:=progr.isCirclePrir; p.RaznRadius:=progr.RaznRadius; p.isSkipCadr:=progr.isSkipCadr; p.EkvidPodxod:= progr.EkvidPodxod; if (isShowProgr) then ShowIconOrProgr(false); if p.tip=typeESSI then sExt:=ext_esi else if p.tip=typeISO then sExt:=ext_iso; sExt:=sExt+ext_pic; if p.compile(true) then begin Panel_Flash_Stop.SetError(Mes_NotError_LNG,cf_Message); DrawTrans.DrawToScreen(stDrawToScreenProgr); DrawTrans.repaint; S:=ChangeFileExt(p.fullname,sExt); FileSetAttr(S,faArchive); end; ABitmap.Canvas.CopyRect(Rect(0,0,ABitmap.width,ABitmap.Height),DrawTrans.Canvas,Rect(0,0,ABitmap.width,ABitmap.Height)); // MyPaint(True); { Рисуем на контексте функциями OpenGL } FrameBuffer.TextureToBitmap; gif:=TGIFImage.Create; gif.Assign(ABitmap); if SSS<>sExt then gif.SaveToFile(ChangeFileExt(p.fullname,sss)) else gif.SaveToFile(ChangeFileExt(p.fullname,sExt)); ABitmap.Free; gif.Free; end; {....... Освобождение памяти и уничтожение временного контекста ......} FrameBuffer.Free; GhostForm.Free; wglMakeCurrent(0, 0); // wglDeleteContext(FGLContext); FGLContext := 0; { Признак - см. proc.MyPaint } ABitmap.Canvas.UnLock; end; Это реализация того что с GL, GLu, GLext: но как и писал выше не пробовал, т.к. не могу найти эти модули. (* procedure TForm1.RenderToBitmap(const ABitmap: TBitmap); var FormatIndex: Integer; PFD: TPixelFormatDescriptor; lFDC: HDC; FGLContext:HGLRC; begin lFDC := ABitmap.Canvas.Handle; FillChar(PFD, SizeOf(PFD), 0); With PFD do begin nSize := SizeOf(PFD); nVersion := 1; dwFlags := pfd_Draw_to_Bitmap or pfd_Support_OpenGL; iPixelType := pfd_Type_RGBA; cColorBits := 24; cDepthBits := 32; iLayerType := pfd_Main_Plane; end; FormatIndex := ChoosePixelFormat(lFDC, @PFD); SetPixelFormat(lFDC, FormatIndex, @PFD); FGLContext := wglCreateContext(lFDC); wglMakeCurrent(lFDC, FGLContext); //MyPaint(True); DrawTrans.DrawToScreen(stDrawToScreenProgr); DrawTrans.repaint; // ABitmap:=TBitmap.Create; ABitmap.PixelFormat:=pf24bit; ABitmap.SetSize(PanelTrans.Width,PanelTrans.Height); ABitmap.SetSize(PanelTrans.Width,PanelTrans.Height); ABitmap.Canvas.CopyRect(Rect(0,0,ABitmap.width,ABitmap.Height),DrawTrans.Canvas,Rect(0,0,ABitmap.width,ABitmap.Height)); gif.Assign(ABitmap); end; *) ****************************************** Это трансляция картинки gif: TDRawPicture = class (TGraphicControl) DrawTrans:TDRawPicture; procedure TForm1.Do_transl; var s{,sExt}:string; gif:TGIFImage; b:TBitmap; i:integer; Sender:TObject; SSS:string; Stream1:TStream; begin if (DialogLoadSave.FileName<>'') and (FileExists(DialogLoadSave.FileName)) then begin try SSS:=ExtractFileExt(DialogLoadSave.FileName)+'.GIF'; ImageTrans.Visible:=false; PanelDraw.Visible:=false; PanelTrans.Visible:=true; p:=tprogr.create(PanelErr{Trans},PanelEdit,DrawTrans,progress,false); p.is3D:=false;//is3D; p.name:='ProgrTransl'; p.isDrawBorderProgr:=true; p.isDrawEkvid:=false;//true; DrawTrans.fprogr:=p; p.open(DialogLoadSave.FileName); p.width_ekvid:=0;//Form_Const_Tools_New_DC_Width_sharp.Value/10; p.isCirclePrir:=progr.isCirclePrir; p.RaznRadius:=progr.RaznRadius; p.isSkipCadr:=progr.isSkipCadr; p.EkvidPodxod:= progr.EkvidPodxod; if (isShowProgr) then ShowIconOrProgr(false); if p.tip=typeESSI then sExt:=ext_esi else if p.tip=typeISO then sExt:=ext_iso; sExt:=sExt+ext_pic; if p.compile(true) then begin Panel_Flash_Stop.SetError(Mes_NotError_LNG,cf_Message); DrawTrans.DrawToScreen(stDrawToScreenProgr); DrawTrans.repaint; S:=ChangeFileExt(p.fullname,sExt); FileSetAttr(S,faArchive); try gif:=TGIFImage.Create; b:=TBitmap.Create; b.Width:=PanelTrans.Width; b.Height:=PanelTrans.Height; b.PixelFormat:=pf24bit; b.SetSize(PanelTrans.Width,PanelTrans.Height); b.SetSize(PanelTrans.Width,PanelTrans.Height); b.Canvas.CopyRect(Rect(0,0,b.width,b.Height),DrawTrans.Canvas,Rect(0,0,b.width,b.Height)); gif.Assign(b); if SSS<>sExt then gif.SaveToFile(ChangeFileExt(p.fullname,sss)) else gif.SaveToFile(ChangeFileExt(p.fullname,sExt)); finally b.Free; gif.Free; end; end else begin System.SysUtils.DeleteFile(ChangeFileExt(p.fullname,sExt)); Panel_Flash_STOP.SetError(Mes_Error__LNG,cf_Error); end; DialogLoadSave.DeActive; DialogLoadSave.Update; DialogLoadSave.FileList_SetFocus; DialogLoadSaveChangeFileList(Sender); finally p.Destroy; ImageTrans.Visible:=true; PanelTrans.Visible:=false; end; DialogLoadSave.FileList_SetFocus; if Panel_Flash_STOP.Status=cf_Error then begin PanelEdit.SetFocus; end; end; end; ********************************* (* unit FrameBufferUnit; interface uses Windows, SysUtils, Graphics, GL, GLu, GLext; type TFrameBuffer = class private width : Integer; height : Integer; frameb : GLuint; depthb : GLuint; texture : GLuint; ftex : boolean; public constructor Create(const nWidth,nHeight:Integer;ctexture:Integer = 0 ); destructor Destroy;override; procedure BindFrameBuffer; procedure UnbindFrameBuffer; function GetBitmap:TBitmap; procedure AttachTexture; procedure DettachTexture; end; implementation { TFrameBuffer } type TRGBLine = array [0..1023] of TRGBTriple; PRGBLine = ^TRGBLine; procedure TFrameBuffer.AttachTexture; begin glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_COLOR_ATTACHMENT0_EXT,GL_TEXTURE _2D,texture,0); end; procedure TFrameBuffer.BindFrameBuffer; begin glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,frameb); end; constructor TFrameBuffer.Create(const nWidth, nHeight: Integer;ctexture:Integer); var res : Integer; ww,hh : Integer; begin Width:=nWidth; Height:=nHeight; { ww:=1; while ww0; if ftex then texture:=ctexture else glGenTextures(1,@texture); glBindTexture(GL_TEXTURE_2D,texture); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR_MIPMAP_LINEAR); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); glTexParameterf(GL_TEXTURE_2D,GL_GENERATE_MIPMAP,0); glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8,ww,hh,0,GL_RGBA,GL_UNSIGNED_BYTE,nil); glBindTexture(GL_Texture_2D,0); glGenFramebuffersEXT(1,@frameb); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,frameb); glGenRenderbuffersEXT(1,@depthb); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT,depthb); glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,GL_DEPTH_COMPONENT,width,height); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT,0); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_COLOR_ATTACHMENT0_EXT,GL_TEXTURE _2D,texture,0); glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,GL_DEPTH_ATTACHMENT_EXT,GL_RENDE RBUFFER_EXT,depthb); res:=glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); if res<>GL_FRAMEBUFFER_COMPLETE_EXT then raise Exception.Create('frame buffer error'); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0); end; destructor TFrameBuffer.Destroy; begin DettachTexture; glDeleteFramebuffersEXT(1,@frameb); glDeleteRenderbuffersEXT(1,@depthb); if not ftex then glDeleteTextures(1,@texture); inherited; end; procedure TFrameBuffer.DettachTexture; begin glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_COLOR_ATTACHMENT0_EXT,GL_TEXTURE _2D,0,0); end; function TFrameBuffer.GetBitmap: TBitmap; var buf : Pointer; l : PRGBLine; b : ^TRGBTriple; i,j : Integer; h,w : Integer; function PtrAllign(APointer:Pointer; bytes: cardinal):Pointer; begin Result := Ptr(cardinal(APointer) + (bytes-cardinal(APointer) mod bytes) mod bytes); end; begin w:=width; h:=height; result:=TBitmap.Create; result.PixelFormat:=pf24bit; result.Width:=w; result.Height:=h; GetMem(buf,w*h*3); glBindTexture(GL_TEXTURE_2D,texture); ZeroMemory(buf,w*h*3); glGetTexImage(GL_TEXTURE_2D,0,GL_RGB,GL_UNSIGNED_BYTE,buf); glBindTexture(GL_TEXTURE_2D,0); b:=buf; for i:=h-1 downto 0 do begin l:=result.ScanLine[i]; for j:=0 to w-1 do begin l[j].rgbtBlue:=b.rgbtRed; l[j].rgbtGreen:=b.rgbtGreen; l[j].rgbtRed:=b.rgbtBlue; Inc(b); end; b:=PtrAllign(b,4); end; FreeMemory(buf); end; procedure TFrameBuffer.UnbindFrameBuffer; begin glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0); end; end. *) unit FrameBufferUnit; {======= Работа с Frame Buffer Object для сохранения в Bitmap ======} interface uses Windows, SysUtils, Graphics, OpenGL, Dialogs; type TFrameBuffer = class private Width, Height: Integer; FrameBuf, DepthBuf, Texture: GLuint; Bitmap: TBitmap; public constructor Create(const TargetBitmap: TBitmap; out Err: byte); destructor Destroy; override; procedure TextureToBitmap; end; {---------------------------------------------------------------------} procedure glGenTextures(n: GLsizei; Textures: PGLuint); stdcall; external 'opengl32.dll'; procedure glBindTexture(Target: GLenum; Texture: GLuint); stdcall; external 'opengl32.dll'; procedure glDeleteTextures(n: GLsizei; const Textures: PGLuint); stdcall; external 'opengl32.dll'; function wglGetProcAddress(ProcName: PAnsiChar): Pointer; stdcall; external 'opengl32.dll'; {---------------------------------------------------------------------} implementation { TFrameBuffer } type TglFramebufferTexture2DEXT = procedure(Target: GLenum; Attachment: GLenum; TexTarget: GLenum; Texture: GLuint; level: GLint); stdcall; TglBindFramebufferEXT = procedure(Target: GLenum; FrameBuffer: GLuint); stdcall; TglGenFramebuffersEXT = procedure(n: GLsizei; FrameBuffers: PGLuint); stdcall; TglGenRenderbuffersEXT = procedure(n: GLsizei; RenderBuffers: PGLuint); stdcall; TglBindRenderbufferEXT = procedure(Target: GLenum; RenderBuffer: GLuint); stdcall; TglRenderbufferStorageEXT = procedure(Target: GLenum; InternalFormat: GLenum; Width: GLsizei; Height: GLsizei); stdcall; TglFramebufferRenderbufferEXT = procedure(target: GLenum; Attachment: GLenum; RenderBufferTarget: GLenum; renderbuffer: GLuint); stdcall; TglCheckFramebufferStatusEXT = function(Target:GLenum):GLenum; stdcall; TglDeleteFramebuffersEXT = procedure(n: GLsizei; const FrameBuffers: PGLuint); stdcall; TglDeleteRenderbuffersEXT = procedure(n: GLsizei; const RenderBuffers: PGLuint); stdcall; var glFramebufferTexture2DEXT: TglFramebufferTexture2DEXT; glBindFramebufferEXT: TglBindFramebufferEXT; glGenFramebuffersEXT: TglGenFramebuffersEXT; glGenRenderbuffersEXT: TglGenRenderbuffersEXT; glBindRenderbufferEXT: TglBindRenderbufferEXT; glRenderbufferStorageEXT: TglRenderbufferStorageEXT; glFramebufferRenderbufferEXT: TglFramebufferRenderbufferEXT; glCheckFramebufferStatusEXT: TglCheckFramebufferStatusEXT; glDeleteFramebuffersEXT: TglDeleteFramebuffersEXT; glDeleteRenderbuffersEXT: TglDeleteRenderbuffersEXT; const gl_FrameBuffer_EXT = $8D40; gl_Color_Attachment0_EXT = $8CE0; gl_Generate_MipMap = $8191; gl_RGBA8 = $8058; gl_RenderBuffer_EXT = $8D41; gl_Depth_Attachment_EXT = $8D00; gl_FrameBuffer_COMPLETE_EXT = $8CD5; gl_BGR = $80E0; {===============================================================} constructor TFrameBuffer.Create(const TargetBitmap: TBitmap; out Err: Byte); begin Err := 0; If Pos(PAnsiChar('GL_EXT_framebuffer_object'), glGetString(gl_Extensions)) = 0 then Err := 1; If Err = 1 then begin MessageDlg( 'No FrameBuffer Extensions. Refresh VIDEO drivers !', mtWarning, [mbCancel], 0); Exit; end; {........... Загружаем внешние функции-расширения OpenGL .............} glFramebufferTexture2DEXT := wglGetProcAddress('glFramebufferTexture2DEXT'); glGenFramebuffersEXT := wglGetProcAddress('glGenFramebuffersEXT'); glBindFramebufferEXT := wglGetProcAddress('glBindFramebufferEXT'); glGenRenderbuffersEXT := wglGetProcAddress('glGenRenderbuffersEXT'); glBindRenderbufferEXT := wglGetProcAddress('glBindRenderbufferEXT'); glRenderbufferStorageEXT := wglGetProcAddress('glRenderbufferStorageEXT'); glFramebufferRenderbufferEXT := wglGetProcAddress('glFramebufferRenderbufferEXT'); glCheckFramebufferStatusEXT := wglGetProcAddress('glCheckFramebufferStatusEXT'); glDeleteFramebuffersEXT:= wglGetProcAddress('glDeleteFramebuffersEXT'); glDeleteRenderbuffersEXT := wglGetProcAddress('glDeleteRenderbuffersEXT'); {............... Генерация и инициализация текстуры ..................} Bitmap := TargetBitmap; Width := Bitmap.Width; Height := Bitmap.Height; Try glGenTextures(1, @Texture); glBindTexture(gl_Texture_2D, Texture); glTexParameterf(gl_Texture_2D, gl_Texture_Mag_Filter, gl_Linear); glTexParameterf(gl_Texture_2D, gl_Texture_Mag_Filter, gl_Linear_MipMap_Linear); glTexParameterf(gl_Texture_2D, gl_Texture_Wrap_S, gl_Repeat); glTexParameterf(gl_Texture_2D, gl_Texture_Wrap_T, gl_Repeat); glTexParameterf(gl_Texture_2D, gl_Generate_MipMap,0); glTexImage2D(gl_Texture_2D, 0, gl_RGBA8, Width, Height, 0, gl_RGBA, gl_UnSigned_Byte, nil); glBindTexture(gl_Texture_2D, 0); {............ Присоединяем Frame- и Render-buffers .................} glGenFramebuffersEXT(1, @FrameBuf); glBindFramebufferEXT(gl_FrameBuffer_EXT, FrameBuf); glGenRenderbuffersEXT(1, @DepthBuf); glBindRenderbufferEXT(gl_RenderBuffer_EXT, DepthBuf); glRenderbufferStorageEXT(gl_RenderBuffer_EXT, gl_Depth_Component, Width, Height); glBindRenderbufferEXT(gl_RenderBuffer_EXT, 0); glFramebufferTexture2DEXT(gl_FrameBuffer_EXT, gl_Color_Attachment0_EXT, gl_Texture_2D, Texture, 0); glFramebufferRenderbufferEXT(gl_FrameBuffer_EXT, gl_Depth_Attachment_EXT, gl_RenderBuffer_EXT, DepthBuf); {............... Проверка успешности инициализации ...................} If glCheckFramebufferStatusEXT(gl_FrameBuffer_EXT) <> gl_FrameBuffer_Complete_EXT then Err := 2; { Присоединяем Texture } glFramebufferTexture2DEXT(gl_FrameBuffer_EXT, gl_Color_Attachment0_EXT, gl_Texture_2D, Texture, 0); except Err := 2; end; If Err = 2 then MessageDlg('Frame Buffer creation not complete !', mtWarning, [mbCancel], 0); end; {========= Уничтожение вспомогательных буферов и текстуры ============} destructor TFrameBuffer.Destroy; begin { Отключение и уничтожение RenderBuffer } glBindRenderbufferEXT(gl_RenderBuffer_EXT, 0); glDeleteRenderbuffersEXT(1, @DepthBuf); { Отключение и уничтожение FrameBuffer } glBindFramebufferEXT(gl_FrameBuffer_EXT, 0); glDeleteFramebuffersEXT(1, @FrameBuf); { Отключение и уничтожение Texture } glBindTexture(gl_Texture_2D, 0); glDeleteTextures(1, @Texture); inherited Destroy; end; {=============== Сохранение текстуры в TargetBitmap ==================} procedure TFrameBuffer.TextureToBitmap; var TBuf, Buf ,Pline: Pointer; I: Integer; begin Buf := nil; Try GetMem(Buf, Width * Height * 3); glPixelStorei(gl_Pack_Alignment, 1); glBindTexture(gl_Texture_2D, Texture); glGetTexImage(gl_Texture_2D, 0, gl_BGR, gl_UnSigned_Byte, Buf); TBuf := Buf; For I := Height - 1 downto 0 do begin Pline := Bitmap.ScanLine[i]; Move(TBuf^, Pline^, Width*3); Inc(NativeInt(TBuf), Width*3); end; finally FreeMemory(Buf); end; end; end.