DirectDraw -> Direct3D

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
DirectDraw -> Direct3D
by on (#103604)
DirectDraw is dead and I am totally rewriting my emulator and I have no experience whatsoever in programming D3D. What I need to do is what I did when I used DirectDraw; i.e. create a surface, fill a buffer with the pixels, lock the surface, pass the buffer, unlock and then blit to the window etc.

Only I can't seem to find any really helpful info via google. How do you guys manage this?
Re: DirectDraw -> Direct3D
by on (#103617)
What you want to do is create a texture, put your pixels into that texture, and then draw that texture to the screen.
Re: DirectDraw -> Direct3D
by on (#103625)
tepples wrote:
What you want to do is create a texture, put your pixels into that texture, and then draw that texture to the screen.


Is that fast?
Re: DirectDraw -> Direct3D
by on (#103627)
Well, a better question is "is that fast enough?" and that is best answered by you trying it an measuring it in the situation you want to use it in, but yes, most setups these days will have no problem with uploading a single texture to the GPU every frame and rendering it to the screen with a single draw call. (You can also get nearest neighbour or bilinear filtering in the same step, done by the GPU, if you want them.) Though, if that's all your doing, you don't even really need Direct3D, pasting your bitmap to the window through the vanilla windows API is fine too.

If you want accurate NES emulation, you really don't have much opportunity to offload sprite and tile drawing to the GPU anyway, since what goes on the screen is interleaved with and affected by the NES CPU. Aside from the GPU rescaling step, there's really nothing that Direct3D can help you with (without a rather complicated solution).
Re: DirectDraw -> Direct3D
by on (#103628)
rainwarrior wrote:
Well, a better question is "is that fast enough?" and that is best answered by you trying it an measuring it in the situation you want to use it in, but yes, most setups these days will have no problem with uploading a single texture to the GPU every frame and rendering it to the screen with a single draw call. (You can also get nearest neighbour or bilinear filtering in the same step, done by the GPU, if you want them.) Though, if that's all your doing, you don't even really need Direct3D, pasting your bitmap to the window through the vanilla windows API is fine too.

If you want accurate NES emulation, you really don't have much opportunity to offload sprite and tile drawing to the GPU anyway, since what goes on the screen is interleaved with and affected by the NES CPU. Aside from the GPU rescaling step, there's really nothing that Direct3D can help you with (without a rather complicated solution).


I'd would like to use a Bitmap and Blit it but i can't get any of the examples of CreateDIBBitmap (or whatever they're called) to work in my own code. Does anyone else have an example that works?
Re: DirectDraw -> Direct3D
by on (#103687)
tepples wrote:
What you want to do is create a texture, put your pixels into that texture, and then draw that texture to the screen.

Yep. This is what I do. It's plenty fast.

If you want to see how this is done in D3D10 (warning: everyone here will tell you that you suck for not supporting Win XP :lol:), I can provide some sample code.
Re: DirectDraw -> Direct3D
by on (#103688)
Please do :).
Re: DirectDraw -> Direct3D
by on (#103742)
ok -- I'll put something together tomorrow morning.
Re: DirectDraw -> Direct3D
by on (#103809)
ok -- you'll need a basic shader:
Code:
Texture2D tex;

SamplerState sam_point
{
   Filter = MIN_MAG_MIP_POINT;
   AddressU = Clamp;
   AddressV = Clamp;
};

matrix world;
matrix view;
matrix proj;

struct VS_INPUT
{
    float4 pos : POSITION;
    float2 tex : TEXCOORD;
};

struct PS_INPUT
{
   float4 pos : SV_POSITION;
   float2 tex : TEXCOORD0;
};

PS_INPUT VS (VS_INPUT input)
{
   PS_INPUT output = (PS_INPUT)0;
   output.pos = mul (input.pos, world);
   output.pos = mul (output.pos, view);
   output.pos = mul (output.pos, proj);
   output.tex = input.tex;
   
   return output;
};

float4 PS (PS_INPUT input) : SV_Target
{
 float4 r = tex.Sample(sam_point, input.tex);
 r.w = 1.0;
 return r;
}

technique10 render
{
   pass P0
   {
      SetVertexShader(CompileShader(vs_4_0, VS()));
      SetGeometryShader(NULL);
      SetPixelShader(CompileShader(ps_4_0, PS()));
   }
}

Save it as shader.fx in the same directory as the .exe.

And here's the code. Try it out and let me know if you have any questions.
Code:
#include "windows.h"
#include "d3d10.h"
#include "d3dx10.h"
#include "stdio.h"

#pragma comment (lib, "d3d10.lib")
#pragma comment (lib, "d3dx10.lib")

#define release_com(x) { if(x) {x->Release(); x = 0;} }

bool vsync = false;

char *title = "2d";
int client_width = 640;
int client_height = 480;
int tex_width = 256;
int tex_height = 256;

HWND hwnd;
IDXGISwapChain *swapchain = 0;
ID3D10Device *d3d_dev = 0;
ID3D10Texture2D *depth_stencil_buffer = 0;
ID3D10RenderTargetView *render_target_view = 0;
ID3D10DepthStencilView *depth_stencil_view = 0;
ID3D10Texture2D *tex = 0;
ID3D10EffectTechnique *technique = 0;
ID3D10EffectMatrixVariable *var_world;
ID3D10EffectMatrixVariable *var_view;
ID3D10EffectMatrixVariable *var_proj;
ID3D10EffectShaderResourceVariable *var_tex;
ID3D10InputLayout *vertex_layout;
ID3D10Buffer *vertex_buffer;
D3DXMATRIX matrix_world;
D3DXMATRIX matrix_view;
D3DXMATRIX matrix_proj;

int frame_count = 0;
LARGE_INTEGER prev_time;
LARGE_INTEGER cur_time;
LARGE_INTEGER counter_freq;

struct vertex
{
   D3DXVECTOR3 pos;
   D3DXVECTOR2 tex;
};

void on_resize()
{
   release_com(depth_stencil_buffer);
   release_com(render_target_view);
   release_com(depth_stencil_view);

   swapchain->ResizeBuffers(1, client_width, client_height, DXGI_FORMAT_R8G8B8A8_UNORM, 0);
   ID3D10Texture2D *back_buffer;
   swapchain->GetBuffer(0, __uuidof(ID3D10Texture2D), (void **)(&back_buffer));
   d3d_dev->CreateRenderTargetView(back_buffer, 0, &render_target_view);
   release_com(back_buffer);

   D3D10_TEXTURE2D_DESC depth_stencil_desc;
   depth_stencil_desc.Width = client_width;
   depth_stencil_desc.Height = client_height;
   depth_stencil_desc.MipLevels = 1;
   depth_stencil_desc.ArraySize = 1;
   depth_stencil_desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
   depth_stencil_desc.SampleDesc.Count = 1;
   depth_stencil_desc.SampleDesc.Quality = 0;
   depth_stencil_desc.Usage = D3D10_USAGE_DEFAULT;
   depth_stencil_desc.BindFlags = D3D10_BIND_DEPTH_STENCIL;
   depth_stencil_desc.CPUAccessFlags = 0;
   depth_stencil_desc.MiscFlags = 0;

   d3d_dev->CreateTexture2D(&depth_stencil_desc, 0, &depth_stencil_buffer);
   d3d_dev->CreateDepthStencilView(depth_stencil_buffer, 0, &depth_stencil_view);

   d3d_dev->OMSetRenderTargets(1, &render_target_view, depth_stencil_view);

   D3D10_VIEWPORT vp;
   vp.TopLeftX = 0;
   vp.TopLeftY = 0;
   vp.Width = client_width;
   vp.Height = client_height;
   vp.MinDepth = 0.0f;
   vp.MaxDepth = 1.0f;

   d3d_dev->RSSetViewports(1, &vp);

   D3DXMatrixPerspectiveFovLH(&matrix_proj, D3DX_PI/4.0f, (float)client_width/(float)client_height, 1.0f, 1000.0f);
}

void init_d3d()
{
   DXGI_SWAP_CHAIN_DESC sd;
   sd.BufferDesc.Width = client_width;
   sd.BufferDesc.Height = client_height;
   sd.BufferDesc.RefreshRate.Numerator = 0;
   sd.BufferDesc.RefreshRate.Denominator = 1;
   sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
   sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
   sd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
   sd.SampleDesc.Count = 1;
   sd.SampleDesc.Quality = 0;
   sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
   sd.BufferCount = 1;
   sd.OutputWindow = hwnd;
   sd.Windowed = true;
   sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
   sd.Flags = 0;

   HRESULT hr = D3D10CreateDeviceAndSwapChain(
      0,
      D3D10_DRIVER_TYPE_HARDWARE,
      0,
      0,
      D3D10_SDK_VERSION,
      &sd,
      &swapchain,
      &d3d_dev
      );

   if (FAILED(hr))
   {
      MessageBox(NULL, "D3D10CreateDeviceAndSwapChain failed.", 0, 0);
      PostQuitMessage(0);
      return;
   }
   on_resize();

   D3D10_INPUT_ELEMENT_DESC element_desc[] =
   {
      { TEXT("POSITION"), 0, DXGI_FORMAT_R32G32B32_FLOAT, 0,  0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
      { TEXT("TEXCOORD"), 0, DXGI_FORMAT_R32G32_FLOAT,    0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 }
   };

   UINT num_elements = sizeof(element_desc)/sizeof(element_desc[0]);
   ID3D10Effect *effect = 0;

   hr = D3DX10CreateEffectFromFile("shader.fx", NULL, NULL, "fx_4_0", 0, 0, d3d_dev, NULL, NULL, &effect, NULL, NULL);
   if (FAILED(hr))
   {
      MessageBox(NULL, "D3DX10CreateEffectFromFile failed", 0, 0);
      PostQuitMessage(0);
      return;
   }
   technique = effect->GetTechniqueByName("render");
   var_world = effect->GetVariableByName("world")->AsMatrix();
   var_view = effect->GetVariableByName("view")->AsMatrix();
   var_proj = effect->GetVariableByName("proj")->AsMatrix();
   var_tex = effect->GetVariableByName("tex")->AsShaderResource();

   D3D10_PASS_DESC pass_desc;
   technique->GetPassByIndex(0)->GetDesc(&pass_desc);
   d3d_dev->CreateInputLayout(element_desc, num_elements, pass_desc.pIAInputSignature, pass_desc.IAInputSignatureSize, &vertex_layout);

   vertex vertices[] =
   {
      { D3DXVECTOR3( -4.0f/3.0f, -1.0f, 0.0f ), D3DXVECTOR2(0.0f, 1.0f) },
      { D3DXVECTOR3( -4.0f/3.0f, 1.0f, 0.0f ), D3DXVECTOR2(0.0f, 0.0f) },
      { D3DXVECTOR3( 4.0f/3.0f, -1.0f, 0.0f ), D3DXVECTOR2(1.0f, 1.0f) },
      { D3DXVECTOR3( 4.0f/3.0f, 1.0f, 0.0f ), D3DXVECTOR2(1.0f, 0.0f) },
   };
   D3D10_BUFFER_DESC buffer_desc;
   buffer_desc.Usage = D3D10_USAGE_DEFAULT;
   buffer_desc.ByteWidth = sizeof(vertex) * 4;
   buffer_desc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
   buffer_desc.CPUAccessFlags = 0;
   buffer_desc.MiscFlags = 0;
   D3D10_SUBRESOURCE_DATA init_data;
   init_data.pSysMem = vertices;
   hr = d3d_dev->CreateBuffer(&buffer_desc, &init_data, &vertex_buffer);

   D3D10_TEXTURE2D_DESC tex_desc;
   tex_desc.Width = tex_width;
   tex_desc.Height = tex_height;
   tex_desc.MipLevels = 1;
   tex_desc.ArraySize = 1;
   tex_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
   tex_desc.SampleDesc.Count = 1;
   tex_desc.SampleDesc.Quality = 0;
   tex_desc.Usage = D3D10_USAGE_DYNAMIC;
   tex_desc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
   tex_desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
   tex_desc.MiscFlags = 0;

   d3d_dev->CreateTexture2D(&tex_desc, 0, &tex);

   D3D10_SHADER_RESOURCE_VIEW_DESC desc_rv;
   desc_rv.Format = tex_desc.Format;
   desc_rv.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
   desc_rv.Texture2D.MipLevels = 1;
   desc_rv.Texture2D.MostDetailedMip = 0;
   ID3D10ShaderResourceView *tex_rv;
   d3d_dev->CreateShaderResourceView(tex, &desc_rv, &tex_rv);

   D3DXMatrixIdentity(&matrix_world);
   D3DXMatrixLookAtLH(
      &matrix_view,
      &D3DXVECTOR3(0.0f, 0.0f, -(1.0 / tan( (D3DX_PI/4)/2.0 ))),
      &D3DXVECTOR3(0.0f, 0.0f, 0.0f),
      &D3DXVECTOR3(0.0f, 1.0f, 0.0f));
   var_tex->SetResource(tex_rv);
}

void draw_scene()
{
   UINT stride = sizeof(vertex);
   UINT offset = 0;
   d3d_dev->IASetInputLayout(vertex_layout);
   d3d_dev->IASetVertexBuffers(0, 1, &vertex_buffer, &stride, &offset);
   d3d_dev->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);

   D3D10_MAPPED_TEXTURE2D map;
   map.pData = 0;
   tex->Map(0, D3D10_MAP_WRITE_DISCARD, NULL, &map);

   //*** plot pixels here ***

   int *p = 0;
   for (int y = 0; y < tex_height; ++y)
   {
      p = (int*)map.pData + y * (map.RowPitch / 4);
      for (int x = 0; x < tex_width; ++x)
      {
         *p++ = (0xFF << 24) | (x << 16) | y;
      }
   }
   tex->Unmap(0);
   D3DXMatrixTranslation(&matrix_world, 0.0f, 0.0f, 0.0f);
   var_proj->SetMatrix((float*)&matrix_proj);
   var_view->SetMatrix((float*)&matrix_view);
   var_world->SetMatrix((float*)&matrix_world);
   technique->GetPassByIndex(0)->Apply(0);
   d3d_dev->Draw(4, 0);
}

void run()
{
   MSG msg = {0};
   while (msg.message != WM_QUIT)
   {
      if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
      {
         TranslateMessage(&msg);
         DispatchMessage(&msg);
      }
      else
      {
         d3d_dev->ClearRenderTargetView(render_target_view, D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f));
         d3d_dev->ClearDepthStencilView(depth_stencil_view, D3D10_CLEAR_DEPTH | D3D10_CLEAR_STENCIL, 1.0f, 0);
         draw_scene();
         swapchain->Present(vsync ? 1 : 0, 0);
         frame_count++;
      }
   }
}

LRESULT CALLBACK wnd_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
   switch (msg)
   {
   case WM_SIZE:
      client_width = LOWORD(lParam);
      client_height = HIWORD(lParam);
      if (d3d_dev)
         on_resize();
      return 0;
   case WM_GETMINMAXINFO:
      ((MINMAXINFO*)lParam)->ptMinTrackSize.x = 100;
      ((MINMAXINFO*)lParam)->ptMinTrackSize.y = 100;
      return 0;
   case WM_DESTROY:
      PostQuitMessage(0);
      return 0;
   case WM_TIMER:
      switch (wParam)
      {
      case 0:
         QueryPerformanceCounter(&cur_time);
         double elapsed = ((cur_time.QuadPart - prev_time.QuadPart) * 1000) / (double)counter_freq.QuadPart;
         double fps = frame_count / (elapsed / 1000.0);
         char buf[32];
         _snprintf(buf, 32, "%s - %.2f fps", title, fps);
         SetWindowText(hwnd, buf);
         frame_count = 0;
         prev_time = cur_time;
         return 0;
      }
      break;
   }
   return DefWindowProc(hWnd, msg, wParam, lParam);
}

void init(HINSTANCE hinstance)
{
   WNDCLASS wc;
   wc.style = CS_HREDRAW | CS_VREDRAW;
   wc.lpfnWndProc = wnd_proc;
   wc.cbClsExtra = 0;
   wc.cbWndExtra = 0;
   wc.hInstance = hinstance;
   wc.hIcon = LoadIcon(0, IDI_APPLICATION);
   wc.hCursor = LoadCursor(0, IDC_ARROW);
   wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
   wc.lpszMenuName = 0;
   wc.lpszClassName = "2d_wnd_class";

   RegisterClass(&wc);

   RECT r = {0, 0, client_width, client_height};
   AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW, false);
   int width = r.right - r.left;
   int height = r.bottom - r.top;

   hwnd = CreateWindow("2d_wnd_class",
      title,
      WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT,
      CW_USEDEFAULT,
      width,
      height,
      0,
      0,
      hinstance,
      NULL
      );

   ShowWindow(hwnd, SW_SHOW);
   UpdateWindow(hwnd);
   QueryPerformanceFrequency(&counter_freq);
   QueryPerformanceCounter(&prev_time);
}

int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lp_cmdline, int n_showcmd)
{
   init(hinstance);
   init_d3d();
   SetTimer(hwnd, 0, 1000, NULL);
   run();
}

James
Re: DirectDraw -> Direct3D
by on (#104531)
Thanks, but tbh I can't really go through all of that.

Code:
LPDIRECT3D9 d3d;
LPDIRECT3DDEVICE9 d3ddev;
D3DPRESENT_PARAMETERS d3dpp;
IDirect3DTexture9 *Texture = NULL;
D3DLOCKED_RECT pLockedRect;
DWORD *Data;
HRESULT hResult;

void CreateDirectX()
{
   d3d = Direct3DCreate9(D3D_SDK_VERSION);

   ZeroMemory(&d3dpp, sizeof(d3dpp));
   d3dpp.hDeviceWindow = hWnd;
   d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
   d3dpp.Windowed = true;
   d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;

   if (d3d->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev) != D3D_OK)
      MessageBox(NULL, "d3d fail", "", 0);

   if (d3ddev->CreateTexture(256, 256, 0, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &Texture, NULL) != D3D_OK)
      MessageBox(NULL, "CT Fail!", "", 0);
}

int temp;

void render_frame(void)
{
   d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
   d3ddev->BeginScene();


   if (Texture->LockRect(0, &pLockedRect, 0, D3DLOCK_DISCARD) != D3D_OK)
      MessageBox(NULL, "LR Fail!", "", 0);
   
   Data = (DWORD*)pLockedRect.pBits;

   temp = 0;

   while (temp < 10000)
   {
      Data[temp] = 0x00FFFFFF;
      temp++;
   }

   if (Texture->UnlockRect(0) != D3D_OK)
      MessageBox(NULL, "UR Fail!", "", 0);

   if (d3ddev->SetTexture(0, Texture) != D3D_OK)
      MessageBox(NULL, "ST Fail!", "", 0);

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

void ReleaseDirectX()
{
   d3ddev->Release();
   d3d->Release();
}


This throws up no error messages but still doesn't work. Does anyone know why?
Re: DirectDraw -> Direct3D
by on (#104546)
What are you applying the texture to?
Re: DirectDraw -> Direct3D
by on (#104571)
Just the client area of a window so that I can write pixels for my NES emulator to the texture and then Blt them.
Re: DirectDraw -> Direct3D
by on (#104589)
I understand what you're trying to do, but where is the code that actually applies the texture to something (not to mention camera setup, etc.)? It looks like you're just updating a texture every frame.
Re: DirectDraw -> Direct3D
by on (#104594)
James wrote:
I understand what you're trying to do, but where is the code that actually applies the texture to something (not to mention camera setup, etc.)? It looks like you're just updating a texture every frame.


No idea. In that case could you please rectify my mistake.
Re: DirectDraw -> Direct3D
by on (#104596)
WedNESday wrote:
James wrote:
I understand what you're trying to do, but where is the code that actually applies the texture to something (not to mention camera setup, etc.)? It looks like you're just updating a texture every frame.


No idea. In that case could you please rectify my mistake.

Yes. See DX10 version above :).

In all seriousness, I don't know DX9, so I can't really help. Maybe take a look at this: http://www.drunkenhyena.com/cgi-bin/view_cpp_article.pl?chapter=2;article=30.
Re: DirectDraw -> Direct3D
by on (#104606)
You don't actually have any drawing commands in there, except Clear. You fill in the texture and set it up for rendering but you never apply it with any draw commands. What you need to do is call DrawPrimitive with a full-screen quad of vertices.

For starters, maybe try DrawPrimitiveUP. It's not as efficient (but perfectly fine for drawing a single quad per frame), but avoids a bunch of necessary setup that you have to do for DrawPrimitive (build a vertex buffer, etc.).
Re: DirectDraw -> Direct3D
by on (#104651)
I've managed to find an old DXSDK on the microsoft website that still has the DDraw files in so I'm back to that.

Now that I've locked on offscreen plain surface I want to copy the pixel data straight to the lpSurface pointer after I lock a surface.

Code:
lpDDSBack->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR, NULL);
(COLORREF *)Pixel = (COLORREF *)ddsd.lpSurface;

memcpy(&Pixel, &buffer, 1);

lpDDSBack->Unlock(NULL);


...either crashes or does absolutely nothing. Ideas?
Re: DirectDraw -> Direct3D
by on (#104653)
I would guess Pixel is NULL or something? Have you verified that the lock was successful?

Also:
Back buffer surfaces, which may be accessed using the IDirect3DDevice9::GetBackBuffer and IDirect3DSwapChain9::GetBackBuffer methods, may be locked only if the swap chain was created with the Flags member of D3DPRESENT_PARAMETERS to include D3DPRESENTFLAG_LOCKABLE_BACKBUFFER.
Re: DirectDraw -> Direct3D
by on (#104655)
WedNESday wrote:
I've managed to find an old DXSDK on the microsoft website that still has the DDraw files in so I'm back to that.

You'll only get nearest neighbor scaling on Vista+ (unsure if this is Nvidia specific, though). This was my motivation for switching from DirectDraw to Direct3D several years ago.
Re: DirectDraw -> Direct3D
by on (#104658)
rainwarrior the lock was succesful as I can use Pixel[10] = ... to plot pixels no problem.

James I've already got a workaround for that. Just write more pixels to the buffer and Flip a larger picture to take into account stretching etc.
Re: DirectDraw -> Direct3D
by on (#104659)
you probably want
Code:
memcpy(Pixel, &buffer, 1);

instead of
Code:
memcpy(&Pixel, &buffer, 1);
Re: DirectDraw -> Direct3D
by on (#104660)
Work now James, even though I tried just that earlier.
Re: DirectDraw -> Direct3D
by on (#104662)
WedNESday wrote:
Work now James, even though I tried just that earlier.

Provide the variable declarations themselves and we can tell you if you should be using & for dereferencing or not (for both Pixel and buffer). Don't forget related lines like how you're allocating memory for these (i.e. malloc, statically on the heap, etc.).
Re: DirectDraw -> Direct3D
by on (#104677)
WedNESday wrote:
Code:
(COLORREF *)Pixel = (COLORREF *)ddsd.lpSurface;

I have to comment on this one. It's a very strange thing to do, to cast an l-value to COLORREF* and then assign to it. It doesn't change the type of Pixel so it's pointless. It's also non-standard.
Re: DirectDraw -> Direct3D
by on (#104680)
thefox wrote:
WedNESday wrote:
Code:
(COLORREF *)Pixel = (COLORREF *)ddsd.lpSurface;

I have to comment on this one. It's a very strange thing to do, to cast an l-value to COLORREF* and then assign to it. It doesn't change the type of Pixel so it's pointless. It's also non-standard.


Had to do that in order for it to compile.
Re: DirectDraw -> Direct3D
by on (#104681)
WedNESday wrote:
thefox wrote:
WedNESday wrote:
Code:
(COLORREF *)Pixel = (COLORREF *)ddsd.lpSurface;

I have to comment on this one. It's a very strange thing to do, to cast an l-value to COLORREF* and then assign to it. It doesn't change the type of Pixel so it's pointless. It's also non-standard.


Had to do that in order for it to compile.

You could've cast ddsd.lpSurface to whatever type Pixel was.
Re: DirectDraw -> Direct3D
by on (#104703)
WedNESday wrote:
Had to do that in order for it to compile.

That's not really an explanation. O_o You could just as easily have commented it out in order to compile. What is the type of Pixel, and why on earth would you be casting Pixel into a different type as you're assigning to it?
Re: DirectDraw -> Direct3D
by on (#104704)
COLORREF *Pixel;

...

(COLORREF *)Pixel = (COLORREF *)ddsd.lpSurface;
Re: DirectDraw -> Direct3D
by on (#104705)
If Pixel is already a COLORREF* you should not cast it.

The cast doesn't add anything, and it takes away type safety for Pixel. (E.g. if you changed Pixel and forgot to change that line, you could be assigning to it incorrectly without the compiler error that would normally catch that.)

It'd be normal to write:

Pixel = (COLORREF*)ddsd.lpSurface;

If that doesn't compile, there is another problem going on, but casting the l-value shouldn't be the solution to it.
Re: DirectDraw -> Direct3D
by on (#104706)
WedNESday wrote:
COLORREF *Pixel;


So this explains a portion of the memcpy() issue you had. memcpy(&Pixel, &buffer, 1) would have handed memcpy() the address/memory location of the Pixel variable itself, not what Pixel pointed to.

Had you declared Pixel as COLORREF Pixel, then memcpy(&Pixel ...) would have been correct (because the declaration in that case would have meant you allocated on the heap whatever the size/type of COLORREF was itself, rather than just allocating on the heap a pointer to some piece of memory considered to be type COLORREF (which you then would have to allocate memory for using LocalAlloc() or whatever Windows uses).

As for the casting issue -- what rainwarrior and thefox have said is absolutely correct. Rule of thumb with C: do not force casting on things unless you know absolutely 100% that what you're doing is correct. I fully understand the need to squelch warnings from the compiler (even more important if you use -Werror or the compilers' equivalent of -Werror (treat warnings as errors)), but forcing a cast should not be the immediate solution to that. Possibly provide the warning/error you get and we can tell you what's going on. :-)
Re: DirectDraw -> Direct3D
by on (#104709)
COLORREF *Pixel;

...

Pixel = (COLORREF *)ddsd.lpSurface;

...now works even though it didn't before, wierd. Thanks guys.
Re: DirectDraw -> Direct3D
by on (#104711)
Remember that despite lpSurface containing the address of the linear piece of memory, the data format of that memory is defined somewhat when you create the surface itself.

So when I see something like this:

Code:
lpDDSBack->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR, NULL);
(COLORREF *)Pixel = (COLORREF *)ddsd.lpSurface;
memcpy(&Pixel, &buffer, 1);

I immediately go "errm... this isn't like the old DOS VGA 320x200 mode stuff in segment A000h!" :-) Of course at the same time I'm also having to make some assumptions about the surface you created (that code is missing so my apologies if I'm jumping the gun!).

The format of each pixel -- meaning, the format of the data/bytes that lpSurface points to vary depending on the underlying hardware/GPU used, video driver, and many other things. See here:

http://msdn.microsoft.com/en-us/library ... 85%29.aspx

The byte ordering (for RGB) change depending on the underlying video card hardware and so on (some are BGR, some are RGB, some are in weird formats). Plus you have the whole 8 vs 16 vs 24 vs 32 bit thing to deal with too. That's why GetPixelFormat() is important.

I think this post might help out a bit too (it helped me anyway):

http://us.generation-nt.com/answer/ddsu ... l#26065902
Re: DirectDraw -> Direct3D
by on (#104724)
When I first started writing my emulator way back in 2003 colour depth was a concern of mine. But this is 2012 and to be fair, anyone who is still using anything less than a 32-bit colour depth graphics cards need to buy themselves a new PC.

Although of course you are correct about BGR/RGB and so on.
Re: DirectDraw -> Direct3D
by on (#104730)
If bit depths less than 32 are obsolete, and I am making a native PC game using Direct3D or OpenGL, how do I do palette swaps without using 8-bit textures?
Re: DirectDraw -> Direct3D
by on (#104731)
Name me 1 Graphics Card that is 16-bit that supports either Direct3D or OpenGL. And I mean within the last 1000 years...Oh and I mean good...
Re: DirectDraw -> Direct3D
by on (#104732)
I'm aware that a lot of more recent graphics cards use 48-bit or deeper pixels for high dynamic range imaging. But to take an example from the past decade, Nintendo DS (2004) graphics output is 18-bit in 1-pass mode (limit 1500 quads, 512 KiB texture memory) or 15-bit in 2-pass mode (limit 3000 quads, 256 KiB texture memory). The platform wasn't superseded until the first quarter of 2011 when the 3DS with a PICA GPU came out.

I was referring to low-bit paletted textures drawn to a 32-bit image buffer. Is it just 16-bit output that is obsolete, or are 4-, 8-, and 16-bit textures also obsolete?
Re: DirectDraw -> Direct3D
by on (#104744)
Textures are flexible, tepples. Lots of formats are supported by most cards. It's the hardware's job to unpack the texture and render it to its backbuffer, whatever format the backbuffer happens to be in.

This is also one of the reasons why it's more common to do your software rendering to a texture, and then draw it to the backbuffer with a fullscreen quad. If you make a texture you can specify the format a lot more directly, whereas the backbuffer will only support a limited set of formats, very unflexible.
Re: DirectDraw -> Direct3D
by on (#104757)
That is, in fact, exactly tepples's point.
Re: DirectDraw -> Direct3D
by on (#104764)
lidnariq wrote:
That is, in fact, exactly tepples's point.

And it's a valid point too.

However, in this case the person who's defining the texture and the pixel format of the surface data is WedNESday. :-) He has control over what the underlying code does, so I don't think he necessarily needs to handle lots of separate cases (8-bit / 16-bit textures, for example -- unless that's what he wants to use). It's his call. The underlying DX API should result in a failed called during surface creation if the underlying GPU driver doesn't support the surface capabilities he requests.