Mira
> GetRenderTargetData кароч. Смотри msdn :)
Он с сурфейсами работает.
Наткнулся на интересную функцию
D3DXSaveTextureToFileInMemory
Она должна сохранять текстуру в памяти в формате файла.
Создаю
Buffer: ID3DXBUFFER;
Выделяю память с запасом.
D3DXCreateBuffer(32*800*600*4,buffer); D3DXSaveTextureToFileInMemory( buffer, D3DXIFF_BMP, RenderTexture,0);
Работает... Но как мне БМП из ID3DXBUFFER достать??
Ramm
Getrendertargetdata для твоего случая пойдёт. Из текстуры сурфейс кстати можно взять.
А если ниженаписаная функция возвращает норм буфер то залочь его и считай память.
Поидее там должно быть уже с bitmap хеадерами а не просто набор пикселей.
У буфера там полтора метода , не запутаешся. Залочить и получить содержимое , узнать размер содержимого, разлочить
Буфер поидне не надо создавать там разве не out параметр?
Ну и ты там в 32 раза больше памяти чем надо выделил:)
Mira
> возвращает норм буфер то залочь его и считай память.
Залочить буфер? Как? У него 5 методов.
Mira
> Поидее там должно быть уже с bitmap хеадерами а не просто набор пикселей.
Вооооот.
И как достать то из него?
Даже лочить не надо.
Getbufferpointer() указатель на начало памяти .
Getbuffersize размер буфера
Че в 3 соснах не можешь)
Mira
> Че в 3 соснах не можешь)
Mira
> Getbufferpointer() указатель на начало памяти .
Указатель) А для создания hbitmap нужен хендл...
Хз, у меня голова уже квадратная.
Ramm
Hbitmap это и есть хэндл. Ты че хочешь в итоге то получить ?
Ramm
Я так понял, ты всё мучаешься с выбором объекта мышкой на экране, вот я написал пример на VB6, это достаточно близко к Дельфи, тоже объекты передаются ссылками, методы пишутся через точку:
https://yadi.sk/d/HUm9GgxEr6BMA
Посмотри как работает EXE, открой файл RenderTarget2.frm блокнотом, там весь нужный тебе код.
Mira
> Hbitmap это и есть хэндл. Ты че хочешь в итоге то получить ?
Хочу HBiTMAP) А имею указатель на буфер, в котором лежит *.bmp в хз каком виде.
Mikle
> вот я написал пример на VB6, это достаточно близко к Дельфи
С++ ближе)
RenderTexture: IDirect3DTexture9;
RenderSurface: IDirect3DSurface9;
BackBuffer: IDirect3DSurface9;Я справился с рендером в текстуру, т.е. перед рендером однократно делаю так:
D3DXCreateTexture(DeviceDX, ScreenX, ScreenY, 0, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, RenderTexture); RenderTexture.GetSurfaceLevel( 0, RenderSurface); Devicedx.GetRenderTarget( 0, BackBuffer);
Если надо рендерить в текстуру, то делаю так:
DeviceDX.SetRenderTarget(0, RenderSurface);
И чтобы увидеть результат:
D3DXSaveTextureToFile('scene.png', D3DXIFF_PNG, RenderTexture, nil);
Пнг выводится. Все норм. Я эту текстуру конвертировать не могу, и заблочить ее у меня почему-то не выходит.
Ramm
> заблочить ее у меня почему-то не выходит.
Так я дал пример, где используется GetRenderTargetData, дальше без проблем лочится и копируется в массив в памяти, не нужно никаких файлов, даже в памяти, это всё равно медленно, не нужно даже битмапов, просто - из сюрфейса в массив.
Ramm
> И чтобы увидеть результат:
> D3DXSaveTextureToFile('scene.png', D3DXIFF_PNG, RenderTexture, nil);
это все очень медленно
Ramm
> D3DXSaveTextureToFileInMemory
значит это тебе не надо, возвращаемя снова к GetRenderTargetData
допустим ты разобрался с этой функций (если нет смотри пример Микла) и получил Pointer с пикселями из своей текстуры
дальше юзаешь CreateDIBSection , передаешь туда массив и корректно заполняешь заголовок.
PROFIT - юзаеш полученный хендл как HBITMAP
Mira
> возвращаемя снова к GetRenderTargetData
Хорошо
Приведу код инициализации, убрал все лишнее, убрал деструктор, лишние методы, оставил только суть:
unit INITDX; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Math, Direct3D9, D3DX9, CAMERADX; type INITDX9 = class constructor Create(f:TForm; R, G, B: cardinal); //рабочая форма и цвет заливки заднего буфера private { Private declarations } Form: TForm; //форма, на которой используем dx //цвет очистки ColorClearR,ColorClearG,ColorClearB:Cardinal; RenderTexture: IDirect3DTexture9; RenderSurface: IDirect3DSurface9; BackBuffer: IDirect3DSurface9; TSurf: IDirect3DSurface9; DrawOnTextureFLAG:boolean; procedure SaveTextureToBITMAP; public MainDirect:IDirect3D9;//главный объект с интерфейсом IDirect3D9 DeviceDX:IDirect3DDevice9;//объект устройства IDirect3DDevice9 Camera:TCAMERA; ScreenX,ScreenY:integer;//разрешение экрана procedure Draw; //вывод заднего буфера procedure DrawOnTexture( FLAG:BOOLEAN);//осуществлять ли вывод в текстуру procedure Clear; //очистка (заливка) заднего буфера, очистка z-буфера end; implementation procedure INITDX9.Clear; begin //очистка, как буфера кадра, так и буфера глубины DeviceDX.Clear( 0, NIL, D3DCLEAR_TARGET or D3DCLEAR_ZBUFFER, //or D3DCLEAR_STENCIL, D3DCOLOR_XRGB( ColorClearR, ColorClearG, ColorClearB), 1, 0); end; constructor INITDX9.Create( f: TForm; R, G, B: cardinal); var DisplayInfo:TD3DDisplayMode; Parameters:TD3DPresentParameters; d3dViewport1: TD3DViewport9; begin Form:=f; ScreenX:=form.ClientWidth; ScreenY:=form.ClientHeight; DrawOnTextureFLAG:=false; //создаем обект с интерфейсом IDirect3D9 MainDirect:=Direct3DCreate9( D3D_SDK_VERSION); //получаем установки текущего режима адаптера MainDirect.GetAdapterDisplayMode( D3DADAPTER_DEFAULT,DisplayInfo); //задаем пареметры усройства ZeroMemory( @Parameters,SizeOf( Parameters)); //использовать оконный режим да\нет Parameters.Windowed:=true; //режим переключения между буферами Parameters.SwapEffect:=D3DSWAPEFFECT_DISCARD; //формат буфера не определен Parameters.BackBufferFormat:=DisplayInfo.Format; Parameters.EnableAutoDepthStencil := TRUE; // формат буфера глубины Parameters.AutoDepthStencilFormat := D3DFMT_D16; //создаем объект устройства MainDirect.CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Form.Handle, D3DCREATE_SOFTWARE_VERTEXPROCESSING, @Parameters, DeviceDX); // Включаем поддержку Z-буфера устройством DeviceDX.SetRenderState( D3DRS_ZENABLE, 1); //D3DZB_TRUE // Отключаем освещение сцены DeviceDX.SetRenderState( D3DRS_LIGHTING, 0); //получаем параметры окна вывода //DeviceDX.GetViewport(d3dViewport1); ColorClearR:=R; ColorClearG:=G; ColorClearB:=B; /////////////////////////////////////////////////////////////////////////////////////////////// D3DXCreateTexture( DeviceDX, ScreenX, ScreenY, 0, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, RenderTexture); RenderTexture.GetSurfaceLevel( 0,RenderSurface); DeviceDX.CreateOffscreenPlainSurface( 800, 600, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, TSurf, nil); Devicedx.GetRenderTarget( 0, BackBuffer); /////////////////////////////////////////////////////////////////////////////////////////////// Clear; //очистка устройства Camera:=TCAMERA.Create( DeviceDX,Form); end; procedure INITDX9.Draw;//непосредственный вывод, либо в файл, либо задний буфер становится видимым begin if DrawOnTextureFLAG then begin D3DXSaveTextureToFile( 'scene.png', D3DXIFF_PNG, RenderTexture, nil); SaveTextureToBITMAP; end else begin DeviceDX.Present( NIL,NIL,0,NIL); end; end; procedure INITDX9.DrawOnTexture( FLAG: BOOLEAN); begin DrawOnTextureFLAG:=FLAG; //если да, то рендерить будем в текстуру if FLAG then begin DeviceDX.SetRenderTarget( 0, RenderSurface);//рендерить будем в сурфейс end else begin DeviceDX.SetRenderTarget( 0, BackBuffer);//рендерить будем в задний буфер end; end; procedure INITDX9.SaveTextureToBITMAP; var bmp: hbitmap; desc: D3DSURFACE_DESC; lr: D3DLOCKED_RECT; BmpVCL: TBitmap; begin DeviceDX.GetRenderTargetData( RenderSurface,TSurf); TSurf.GetDesc( desc); TSurf.LockRect( lr,0,0); form.Caption:=inttostr( lr.Pitch); //BmpVCL := TBitmap.Create(); //BmpVCL.Handle := bmp; //BmpVCL.SaveToFile('aaa666.bmp'); end; end.
Pitch теперь равен 3200, а при повторной отрисовке - более 1.5 млн.
Где-то TSurf надо чистить... Если сделать его локальным (определить в SaveTextureToBITMAP), то Pitch всегда 3200.
Я правильно понимаю, что нужно вообще отказаться от текстур, обойтись одними поверхностями (IDirect3DSurface9)?
Mikle
If tSurf.GetData(VarPtr(R), 800& * 600 * 4, VarPtr(Ar(0, 0))) Then//Что это такое?
Caption = Ar(Mx Mod 800, My Mod 600) And &HFFFFFF
End IfУ IDirect3DSurface9 у меня нет такого метода, есть GetPrivateData(TGUID, Pointer, Integer)
Ramm
Все верно.
Размер скрина 800 * sizeof(integer) размер пикселя = 3200
Теперь халява, сделать картинку из массива пикселей.
Юзаешь createcompatibledc или сторонний компонент умеющий быстрый доступ к пикселям.
Лично я юзал FastDIB
Ramm
> У IDirect3DSurface9 у меня нет такого метода
Да, забыл сразу написать, GetData() - это макрос, состоит из LockRect(), memcpy() и UnlockRect(), возвращает True, если LockRect() вернул D3D_OK. Всё остальное - стандартные D3D9 методы.
Mira
Mikle
аааааааааааааааАААААААААААААЗАРАБОТАЛО!!!!!!!!!!111111111111111111111111
Спасибо огромное!
procedure INITDX9.SaveTextureToBITMAP; var bmp: hbitmap; desc: D3DSURFACE_DESC; lr: D3DLOCKED_RECT; BmpVCL: TBitmap; TSurf: IDirect3DSurface9; begin DeviceDX.CreateOffscreenPlainSurface(800, 600, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, TSurf, nil); DeviceDX.GetRenderTargetData( RenderSurface,TSurf); TSurf.GetDesc( desc); TSurf.LockRect( lr,0,0); form.Caption:=inttostr( lr.Pitch); bmp := CreateCompatibleBitmap( GetDC( 0), desc.Width, desc.Height); SetBitmapBits( bmp,lr.Pitch*desc.Height,lr.pBits); TSurf.UnlockRect; BmpVCL:= TBitmap.Create( ); BmpVCL.Handle:=bmp; BmpVCL.SaveToFile( 'aaa666.bmp'); end;
Главное - это вот это:
DeviceDX.CreateOffscreenPlainSurface(800, 600, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, TSurf, nil); DeviceDX.GetRenderTargetData( RenderSurface,TSurf);
Единственное... Я правильно понял, что вообще без текстуры нельзя обойтись?
D3DXCreateTexture(DeviceDX, ScreenX, ScreenY, 0, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, RenderTexture); RenderTexture.GetSurfaceLevel( 0,RenderSurface); Devicedx.GetRenderTarget( 0, BackBuffer);
Т.е. без вот этого никак?
Тема в архиве.