Sign in to follow this  
Yours3!f

OpenGL glTexSubImage2D in directx?

Recommended Posts

Yours3!f    1532
Hi,

in OpenGL I used glTexSubImage2D to fill part of a texture with an image, what is the corresponding function in directx (9)? I googled a lot, but I couldn't find it, neither in msdn...

Best regards,
Yours3!f

Share this post


Link to post
Share on other sites
mhagain    13430
There is none.

OK, that's the short and unhelpful version. The slightly longer version is that you use much the same process as when creating a texture for the first time (using pure D3D, not D3DX). This involves issuing a LockRect call, copying in the data, then issuing an UnlockRect call. You need to ensure that you've got the correct memory pool and/or usage flags set at creation time (D3DPOOL_MANAGED is normally sufficient for all cases, but you can also use the default pool with D3DUSAGE_DYNAMIC). Another alternative is to have two textures - one in the default pool, the other in the system memory pool. Update the system memory version (LockRect/UnlockRect), then use UpdateTexture to copy to the default pool version. UpdateSurface is another option which lets you specify subrects. Finally, when using LockRect/UnlockRect you can have some control over when dirty regions of the texture get updated.

By now you're probably getting the idea that there are many different ways of doing this, and you'd be right. This is both good and bad; it's good because it gives you a very fine level of control over the texture update process but it's bad because it means that you need to experiment with all of these different ways to find what's optimal for your use case - you could spend days, weeks or months playing with all the combinations of options and get nothing else done!

Probably the simplest way all round is what I'd initially recommend; you can then experiment with other ways if you need more performance or more control. It goes something like this:

[list][*]Initially create the texture in D3DPOOL_MANAGED with D3DFMT_X8R8G8B8 (D3DFMT_A8R8G8B8) and usage 0.[*]Use LockRect to access the texture data, a rect of NULL will get the entire texture rectangle or you can specify a subrect.[*]Cast the pBits member of your D3DLOCKED_RECT to unsigned char * or unsigned int * as required.[*]Write in your data.[*]Use UnlockRect to finish up.[/list]

Share this post


Link to post
Share on other sites
Yours3!f    1532
Thanks for the clarifying comment :)

I think I did most of what you told me right, although I don't know how to write in the raw data into the texture...

here's the function I made for this:
[code]
HRESULT create_sub_image(HBITMAP bitmap, LPDIRECT3DTEXTURE9* tex, int width, int height)
{
HRESULT result;

//get raw image data
BITMAP bmp;
GetObject(bitmap, sizeof(bmp), &bmp);
int size = bmp.bmWidth * bmp.bmHeight * (bmp.bmBitsPixel / 8);
BYTE* bytes = new BYTE[size];
GetBitmapBits(bitmap, size, bytes);

//create the texture
result = D3DXCreateTexture(dx_dev, width, height, D3DX_DEFAULT, NULL, D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, tex);
if(FAILED(result))
{
return result;
}

//define sub-rectangle (so we place the texture in the middle of the other one
RECT rect;
rect.left = (width - bmp.bmWidth) / 2;
rect.right = rect.left + bmp.bmWidth;
rect.top = (height - bmp.bmHeight) / 2;
rect.bottom = rect.top + bmp.bmHeight;

D3DLOCKED_RECT locked_rect; //do I need to specify anything?

//lock memory
result = (*tex)->LockRect(D3DX_DEFAULT, &locked_rect, &rect, NULL);
if(FAILED(result))
{
return result;
}

//cast bits to char* raw RGB data (0...255)
char* bits = (char*)locked_rect.pBits;

//write in data???
//
//

result = (*tex)->UnlockRect(D3DX_DEFAULT);

return result;
}
[/code]

Share this post


Link to post
Share on other sites
Yours3!f    1532
I wrote a small example in which lockrect fails...
it needs two 24bit bitmaps, which can be created in resource view.
it supposed to copy the content of the second bitmap onto the first, and as a texture display it.

[code]
#define WIN32_LEAN_AND_MEAN

#include <Windows.h>
#include <d3d9.h>
#include <d3dx9.h>

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <tchar.h>
#include <sstream>
#include <stdexcept>
#include <assert.h>

#include "resource.h"

LPDIRECT3D9 dx;
LPDIRECT3DDEVICE9 dx_dev;
D3DPRESENT_PARAMETERS dx_pp = {0};

HWND the_hwnd;
HINSTANCE the_instance;
WNDCLASSEX wc;

int screen_width = 0;
int screen_height = 0;

#define CFVF (D3DFVF_XYZ | D3DFVF_TEX1)
struct CV
{
CV(FLOAT xx, FLOAT yy, FLOAT zz, FLOAT uu, FLOAT vv)
{
x = xx;
y = yy;
z = zz;
u = uu;
v = vv;
}
FLOAT x, y, z, u, v;
};

LPDIRECT3DVERTEXBUFFER9 vbo = NULL;
LPDIRECT3DTEXTURE9 texture;

DWORD global_time = GetTickCount();

float rotation = 0.0f;

float near_p = 1.0f;
float far_p = 1000.0f;
float fovy = D3DXToRadian(45.0f);
float wi = 0.0f;
float he = 0.0f;
float aspect = 0.0f;

LRESULT CALLBACK window_process(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
HRESULT init(int w, int h);
void shutdown();
void enter_main_loop();
HRESULT init_dx();
HRESULT init_vbo();
void render();
void clean_up();
BOOL build_present_parameters();
void handle_keypress(WPARAM wparam);
HRESULT load_bitmap(LPCTSTR bitmap, LPDIRECT3DTEXTURE9* tex);
HRESULT create_sub_image(HBITMAP bitmap, LPDIRECT3DTEXTURE9* tex);

//enables key press handling
#ifndef D3BUG
#define D3BUG
#endif

HRESULT load_bitmap(LPCTSTR bitmap, LPDIRECT3DTEXTURE9* tex)
{
HRESULT result = D3DXCreateTextureFromResource(dx_dev,
NULL,
bitmap,
tex);

if(FAILED(result))
{
return result;
}

return result;
}

HRESULT create_sub_image(HBITMAP bitmap, LPDIRECT3DTEXTURE9* tex)
{
HRESULT result;

//get raw image data
BITMAP bmp;
GetObject(bitmap, sizeof(bmp), &bmp);
int size = bmp.bmWidth * bmp.bmHeight * (bmp.bmBitsPixel / 8);
BYTE* bytes = new BYTE[size];
GetBitmapBits(bitmap, size, bytes);

D3DSURFACE_DESC tex_desc;
(*tex)->GetLevelDesc(0, &tex_desc);

//define sub-rectangle (so we place the texture in the middle of the other)
unsigned int width = bmp.bmWidth;
unsigned int height = bmp.bmHeight;
unsigned int pitch = bmp.bmWidth * (bmp.bmBitsPixel / 8);

assert(tex_desc.Width >= width);
assert(tex_desc.Height >= height);

RECT rect;
rect.left = (tex_desc.Width / 2) - (width / 2);
rect.right = width;
rect.top = (tex_desc.Height / 2) - (height / 2);
rect.bottom = height;


D3DLOCKED_RECT locked_rect; //do I need to specify anything?

std::basic_stringstream<TCHAR> ss;

//lock memory
result = (*tex)->LockRect(0, &locked_rect, &rect, NULL);
if(FAILED(result))
{
return result;
}

//cast bits to char* raw RGB data (0...255)
BYTE* bits = (BYTE*)locked_rect.pBits;

//write in data???
for(unsigned int y = 0; y < rect.bottom; y++)
{
for(unsigned int x = 0; x < rect.right; x++)
{
unsigned int dest_index = (x * 4 + (y * (locked_rect.Pitch)));

//flip the source image horizontally
unsigned int source_index = (((rect.right - x - 1) * 4) + (y * pitch));

bits[dest_index] = bytes[source_index]; //r
bits[dest_index + 1] = bytes[source_index + 1]; //g
bits[dest_index + 2] = bytes[source_index + 2]; //b
bits[dest_index + 3] = bytes[source_index + 3]; //a
}
}

result = (*tex)->UnlockRect(0);

return result;
}

int WINAPI _tWinMain(HINSTANCE instance, HINSTANCE, LPTSTR, int nCmdShow)
{
the_instance = instance;

HRESULT result = init(1024, 576);

enter_main_loop();

shutdown();

return result;
}

HRESULT init(int w, int h)
{
screen_width = w;
screen_height = h;

ZeroMemory(&wc, sizeof(WNDCLASSEX));

wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = window_process;
wc.hInstance = the_instance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszClassName = L"WindowClass";

RegisterClassEx(&wc);

the_hwnd = CreateWindowEx(NULL,
L"WindowClass",
L"DX",
WS_OVERLAPPEDWINDOW,
20,
20,
screen_width,
screen_height,
NULL,
NULL,
the_instance,
NULL);

ShowWindow(the_hwnd, SW_SHOW);

return init_dx();
}

HRESULT init_dx()
{
HRESULT result;

dx = Direct3DCreate9(D3D_SDK_VERSION);

//build pp
if(!build_present_parameters())
{
return -1;
}

result = dx->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
the_hwnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&dx_pp,
&dx_dev);
if(FAILED(result))
{
return result;
}

result = dx_dev->SetRenderState(D3DRS_LIGHTING, FALSE);
if(FAILED(result))
{
return result;
}
result = dx_dev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
if(FAILED(result))
{
return result;
}
result = dx_dev->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
if(FAILED(result))
{
return result;
}
result = dx_dev->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
if(FAILED(result))
{
return result;
}
result = dx_dev->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL);
if(FAILED(result))
{
return result;
}

result = init_vbo();
if(FAILED(result))
{
return result;
}

result = load_bitmap(MAKEINTRESOURCE(IDB_BITMAP1), &texture);
if(FAILED(result))
{
return result;
}

HBITMAP bitmap = LoadBitmap(the_instance, MAKEINTRESOURCE(IDB_BITMAP2));
result = create_sub_image(bitmap, &texture);

return result;
}

BOOL build_present_parameters()
{
ZeroMemory(&dx_pp, sizeof(dx_pp));
dx_pp.Windowed = TRUE;
dx_pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
dx_pp.hDeviceWindow = the_hwnd;
dx_pp.BackBufferFormat = D3DFMT_X8R8G8B8;
dx_pp.BackBufferWidth = screen_width;
dx_pp.BackBufferHeight = screen_height;
dx_pp.EnableAutoDepthStencil = TRUE;
dx_pp.AutoDepthStencilFormat = D3DFMT_D16;

return TRUE;
}

HRESULT init_vbo()
{
HRESULT result;

aspect = (float)screen_width / (float)screen_height;
he = near_p * tan(fovy / 2.0f);
wi = abs(-he * aspect);
wi *= 2.0f;
he *= 2.0f;

CV vertices[] =
{
CV(wi / -2.0f, he / -2.0f, 0.0f, 0.0f, 1.0f),
CV(wi / 2.0f, he / -2.0f, 0.0f, 1.0f, 1.0f),
CV(wi / 2.0f, he / 2.0f, 0.0f, 1.0f, 0.0f),
CV(wi / -2.0f, he / -2.0f, 0.0f, 0.0f, 1.0f),
CV(wi / 2.0f, he / 2.0f, 0.0f, 1.0f, 0.0f),
CV(wi / -2.0f, he / 2.0f, 0.0f, 0.0f, 0.0f)
};

result = dx_dev->CreateVertexBuffer(6 * sizeof(CV), 0, CFVF, D3DPOOL_MANAGED, &vbo, NULL);
if(FAILED(result))
{
return result;
}

VOID* v;

vbo->Lock(0, 0, (void**)&v, 0);
memcpy(v, vertices, sizeof(vertices));
vbo->Unlock();
return result;
}

void render()
{
D3DXMATRIX mat_world, mat_view, mat_proj;

dx_dev->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 40, 100), 1.0f, 0);

dx_dev->BeginScene();

dx_dev->SetFVF(CFVF);

D3DXMatrixPerspectiveFovLH(&mat_proj, fovy, aspect, near_p, far_p);

dx_dev->SetTransform(D3DTS_PROJECTION, &mat_proj);

D3DXMatrixLookAtLH( &mat_view, &D3DXVECTOR3( 0.0f, 0.0f, 0.0f ),
&D3DXVECTOR3( 0.0f, 0.0f, -1.0f ),
&D3DXVECTOR3( 0.0f, 1.0f, 0.0f ) );
dx_dev->SetTransform( D3DTS_VIEW, &mat_view );

D3DXMATRIX mat_sca;
D3DXMatrixTranslation(&mat_world, 0.0f, 0.0f, -near_p);
dx_dev->SetTransform(D3DTS_WORLD, &mat_world);

dx_dev->SetTexture(0, texture);

dx_dev->SetStreamSource(0, vbo, 0, sizeof(CV));
dx_dev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);

dx_dev->EndScene();
dx_dev->Present(NULL, NULL, NULL, NULL);
}

void shutdown()
{
clean_up();
}

void clean_up()
{
vbo->Release();
dx_dev->Release();
dx->Release();
SendMessage(the_hwnd, WM_DESTROY, NULL, NULL);
}

void enter_main_loop()
{
MSG msg;
int return_value;

if(dx_dev)
{
render();
}

//the main message pump
while((return_value = GetMessage(&msg, NULL, 0, 0)) != 0)
{
if(return_value == -1)
{
//error
break;
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}

LRESULT CALLBACK window_process(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch(msg)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
break;
}
#ifdef D3BUG
case WM_KEYDOWN:
{
handle_keypress(wparam);
break;
}
#endif
default:
{
if(dx_dev)
{
int current_time = GetTickCount() - global_time;
if(current_time > 33)
{
render();
global_time = GetTickCount();
}
}
break;
}
}

return DefWindowProc(hwnd, msg, wparam, lparam);
}

void handle_keypress(WPARAM wparam)
{
switch(LOWORD(wparam))
{
case 0x20:
{
rotation += 1.0f;
}
default:
break;
};
}
}
[/code]

EDIT: ok I solved it. see the example above

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Similar Content

    • By povilaslt2
      Hello. I'm Programmer who is in search of 2D game project who preferably uses OpenGL and C++. You can see my projects in GitHub. Project genre doesn't matter (except MMO's :D).
    • By ZeldaFan555
      Hello, My name is Matt. I am a programmer. I mostly use Java, but can use C++ and various other languages. I'm looking for someone to partner up with for random projects, preferably using OpenGL, though I'd be open to just about anything. If you're interested you can contact me on Skype or on here, thank you!
      Skype: Mangodoor408
    • By tyhender
      Hello, my name is Mark. I'm hobby programmer. 
      So recently,I thought that it's good idea to find people to create a full 3D engine. I'm looking for people experienced in scripting 3D shaders and implementing physics into engine(game)(we are going to use the React physics engine). 
      And,ye,no money =D I'm just looking for hobbyists that will be proud of their work. If engine(or game) will have financial succes,well,then maybe =D
      Sorry for late replies.
      I mostly give more information when people PM me,but this post is REALLY short,even for me =D
      So here's few more points:
      Engine will use openGL and SDL for graphics. It will use React3D physics library for physics simulation. Engine(most probably,atleast for the first part) won't have graphical fron-end,it will be a framework . I think final engine should be enough to set up an FPS in a couple of minutes. A bit about my self:
      I've been programming for 7 years total. I learned very slowly it as "secondary interesting thing" for like 3 years, but then began to script more seriously.  My primary language is C++,which we are going to use for the engine. Yes,I did 3D graphics with physics simulation before. No, my portfolio isn't very impressive. I'm working on that No,I wasn't employed officially. If anybody need to know more PM me. 
       
    • By Zaphyk
      I am developing my engine using the OpenGL 3.3 compatibility profile. It runs as expected on my NVIDIA card and on my Intel Card however when I tried it on an AMD setup it ran 3 times worse than on the other setups. Could this be a AMD driver thing or is this probably a problem with my OGL code? Could a different code standard create such bad performance?
    • By Kjell Andersson
      I'm trying to get some legacy OpenGL code to run with a shader pipeline,
      The legacy code uses glVertexPointer(), glColorPointer(), glNormalPointer() and glTexCoordPointer() to supply the vertex information.
      I know that it should be using setVertexAttribPointer() etc to clearly define the layout but that is not an option right now since the legacy code can't be modified to that extent.
      I've got a version 330 vertex shader to somewhat work:
      #version 330 uniform mat4 osg_ModelViewProjectionMatrix; uniform mat4 osg_ModelViewMatrix; layout(location = 0) in vec4 Vertex; layout(location = 2) in vec4 Normal; // Velocity layout(location = 3) in vec3 TexCoord; // TODO: is this the right layout location? out VertexData { vec4 color; vec3 velocity; float size; } VertexOut; void main(void) { vec4 p0 = Vertex; vec4 p1 = Vertex + vec4(Normal.x, Normal.y, Normal.z, 0.0f); vec3 velocity = (osg_ModelViewProjectionMatrix * p1 - osg_ModelViewProjectionMatrix * p0).xyz; VertexOut.velocity = velocity; VertexOut.size = TexCoord.y; gl_Position = osg_ModelViewMatrix * Vertex; } What works is the Vertex and Normal information that the legacy C++ OpenGL code seem to provide in layout location 0 and 2. This is fine.
      What I'm not getting to work is the TexCoord information that is supplied by a glTexCoordPointer() call in C++.
      Question:
      What layout location is the old standard pipeline using for glTexCoordPointer()? Or is this undefined?
       
      Side note: I'm trying to get an OpenSceneGraph 3.4.0 particle system to use custom vertex, geometry and fragment shaders for rendering the particles.
  • Popular Now