   Simple surface clipping with Dx9
  Hello,I''d like to know how to perform clipping on the DIRECT3DSURFACE9. When I use LoadSurfaceFormSurface(), if the destination rect is not inside the destination surface an error is raised and no clipping is performed. In DirectDraw there used to be the DIRECTDRAWCLIPPER for directdraw surfaces. Is there any function in Dx9 that can copy a surface to another with blitting if necessary. I''d like to know by the way if there''s a means to perform a rotation on a DIRECT3DSURFACE9 (I know the old method for the DIRECTDRAWSURFACEs).Thank you very much. 
  You can always use render-blitting, where you use orthogonal projection and then draw your two surfaces you want to blit as rectangular quads onto another surface. (SetRenderTarget to your destination surface, then render the two quads). That will do the necessary clipping.Edit: You can also rotate, scale, and totally mess with the quads when you do it like this.   [edited by - Erzengeldeslichtes on February 2, 2004 7:38:45 PM];  Could you show me some code explaining how to do this please. So I have my two surfaces filled with the right bitmap. What do I have to do then to blit them correctly to the back buffer:LPDIRECTSURFACE3D9 testSurf1;LPDIRECTSURFACE3D9 testSurf2;LPDIRECTSURFACE3D9 backBuffer;D3DXLoadSurfaceFromFile(testSurf1,NULL,NULL,"img1.bmp",NULL,....D3DXLoadSurfaceFromFile(testSurf2,NULL,NULL,"img2.bmp",NULL,....device -> GetBackBuffer (...,&backBuffer,../* What I do And don''t work because of the clippingwhere rect is not fully included il backBuffer''s rectD3DXLoadSurfaceFromSurface(backBuffer, NULL, rect, testSurf1,...*/So what do I have to make this work?Thanks;  I can use textures but it incredibly slows down the framerate. And using 3d objects mapped with textures so as to render 2d graphics doesn''t seem very natural even if much spe fx can then be performed. Even manual clipping proceeds 10 times faster so there should be a better way. The first mario bros on the nes was running with only 1mhz and I need 700mhz to do the same thing!!!! ;  Why doesn't it seem natural? A bitmap is just a flat rectangle. You blit by putting two of these rectangles on top of each other. A bitmap is a peice of paper with colors drawn onto it (and parts cut out if you use alpha mapping). It has four corners, these are the vertices. You blit by taking two peices of paper, setting them on top of each other, and then taking a picture of the two.Mario Bros was written by professionals in NES ASM that knew how to optimize, you can't expect to run that well unless you, too, are a professional who can optimize and are writing in assembly. (IOW, you're comparing apples and pcs... err, apples and oranges) //I'm going to assume you can make a rectangular quad.//g_VBQuad is a 1 unit x 1 unit rectangle.//FVF_SIZE is sizeof(Vertex) in the VB.//This assumes you will NOT be using it within a BeginScene/EndScene blockvoid BlitToTexture(IDirect3DSurface9* Destination, IDirect3DTexture9* TextureBottom, D3DXVECTOR2 PositionBottom, D3DXVECTOR3 RotationBottom,IDirect3DTexture9* TextureTop, D3DXVECTOR2 PositionTop, D3DXVECTOR3 RotationTop){    //Check to make sure destination is render surface    D3DSURFACE_DESC TargDesc;    Destination->GetDesc(&TargDesc);    if(TargDesc.Usage != D3DUSAGE_RENDERTARGET)    {   return;    }    IDirect3DDevice9* GD=NULL;    Destination->GetDevice(&GD);    //If you can make note of the backbuffer outside of this function and reset it to that afterward, that would be preferable to doing this:    IDirect3DSurface9* PreviousSurface=NULL;    GD->GetRenderTarget(0, &PreviousSurface);//Save previous surface    GD->SetRenderTarget(0, Destination);//Set new render surface    D3DSURFACE_DESC SurDesc;    TextureBottom->GetLevelDesc(0, &SurDesc);//Get the dimensions of the texture    GD->BeginScene();//Should probably error check to see if we succeded, but I'd rather not take up too much more typing.    D3DXMATRIX Temp, World;    //Set to orthoganal projection of the target surface's size    D3DXMatrixOrthoLH(&Temp, TargDesc.Width, TargDesc.Height, 0, 2);    GD->SetTransform(D3DTS_PROJECTION, &Temp);    //Set up the first quad for rendering.    D3DXMatrixIdentity(&World);    D3DXMatrixScaling(&Temp, SurDesc.Width, SurDesc.Height, 0);    D3DXMatrixMultiply(&World, &World, &Temp);    D3DXMatrixRotationX(&Temp, D3DXToRadian(RotationBottom.x));    D3DXMatrixMultiply(&World, &World, &Temp);    D3DXMatrixRotationY(&Temp, D3DXToRadian(RotationBottom.y));    D3DXMatrixMultiply(&World, &World, &Temp);    D3DXMatrixRotationZ(&Temp, D3DXToRadian(RotationBottom.z));    D3DXMatrixMultiply(&World, &World, &Temp);    D3DXMatrixTranslation(&Temp, PositionBottom.x, PositionBottom.y, 1);    D3DXMatrixMultiply(&World, &World, &Temp);    GD->SetTransform(D3DTS_WORLD, &World);    GD->SetStreamSource(0, &g_VBQuad, 0, FVF_SIZE);    GD->SetTexture(0, TextureBottom);    GD->DrawPrimitive(D3DPT_TRAINGLESTRIP, 0, 4);    TextureTop->GetLevelDesc(0, &SurDesc);    D3DXMatrixIdentity(&World);    D3DXMatrixScaling(&Temp, SurDesc.Width, SurDesc.Height, 0);    D3DXMatrixMultiply(&World, &World, &Temp);    D3DXMatrixRotationX(&Temp, D3DXToRadian(RotationTop.x));    D3DXMatrixMultiply(&World, &World, &Temp);    D3DXMatrixRotationY(&Temp, D3DXToRadian(RotationTop.y));    D3DXMatrixMultiply(&World, &World, &Temp);    D3DXMatrixRotationZ(&Temp, D3DXToRadian(RotationTop.z));    D3DXMatrixMultiply(&World, &World, &Temp);    D3DXMatrixTranslation(&Temp, PositionTop.x, PositionTop.y, 0);    D3DXMatrixMultiply(&World, &World, &Temp);    GD->SetTransform(D3DTS_WORLD, &World);    GD->SetStreamSource(0, &g_VBQuad, 0, FVF_SIZE);    GD->SetTexture(0, TextureTop);    GD->DrawPrimitive(D3DPT_TRAINGLESTRIP, 0, 4);    GD->Present(NULL,NULL,NULL,NULL);//Present the rendering to the surface.    GD->EndScene();    GD->SetRenderTarget(0, PreviousSurface);//Reset the previous surface    PreviousSurface->Release();//Reduces the internal referance count so that when we actually quit it will delete it.}Please excuse any sloppyness and/or mistakes, I didn't test the code, I just wrote it. But theoretically it should work.And if doing it manually is faster... You don't have a very good graphics card! Manual blitting is done via CPU. What I just did is completely on the GPU (and that's very desirable, it frees up the CPU to do other things!) which is much better at dealing with vertices and pixels than the CPU is, not to mention the less bandwidth used in moving textures around from system memory to graphics memory and vice versa that you are doing in manual blitting. [edited by - Erzengeldeslichtes on February 4, 2004 2:41:09 PM];  If all you want to do is draw bitmaps to the screen (potentially with rotation) look at D3DXSprite.  It''s probably the easiest way to go, and it''s about as complex as a DirectDraw blit.Trying to use LoadSurfaceFromSurface as a blitter is a very bad idea, it''s painfully slow. Stay Casual,KenDrunken Hyena;  Thank you guys for answering. I just figured out that''s the best way to do such things. By the way, is it necessary to use the vertex buffer for unly 4 vertexes? And even if I had many sprites would there really be a noticeable change? (sorry to bug you with so stupid questions but I''m really new to all this stuff).One last question: I would like to make a mario like game but I dont have all the theory with dx9. So if I want to have a scrolling background I will have to load all my background components (tiles) into textures. What to do then with these tiles? Can I apply them all on the same quad? Thank you very much Erzengeldeslichtes for your code.  ;  You can learn how to use ID3DXSprite, which is probably easier and faster (I don't know, never tried it), but that teaches you nothing about 3D, and the books I've looked at (granted I've been after 3d books), when they talk about 2d, use textured quad method. Also my method is order-indipendant, you simply use .z as layers."By the way, is it necessary to use the vertex buffer for unly 4 vertexes?"Well, you have two options, VertexBuffer or UserPointer. DrawPrimitive uses the VertexBuffer, DrawPrimitiveUP uses a pointer to your own data. In the words of the professionals and the nVidia tutors: ALWAYS ALWAYS ALWAYS USE VERTEX BUFFERS.You can use the same VertexBuffer with different matrices to draw the same model in different places without increasing your memory cost. So apply a different texture to the same quad, with a different matrix, creates a different object.Also, if you're making a 2d game you can, instead of using my previous code, draw each and every sprite seperately onto the backbuffer. A modification to my previous code would be thus: typedef struct _Vertex{    float x, y, z;    float u, v;} Vertex;#define VERTEX (D3DFVF_XYZ|D3DFVF_TEX1)#define VERTEXSIZE sizeof(Vertex)IDirect3DVertexBuffer9* g_VBQuad=NULL;void Set2D(IDirect3DDevice9* GD){    //Getting the screen size (would be better if you provide it)    IDirect3DSurface9* BackBuffer=NULL;    GD->GetBackBuffer(0,0,D3DBACKBUFFER_TYPE_MONO,&BackBuffer);    D3DSURFACE_DESC Desc;    BackBuffer->GetDesc(&Desc);    D3DXMATRIX Temp;    //Note: I put the far plane at 100. You can set it to whatever. You won't be able to set your position.z any further away than whatever you set.    //Note: I also set the near plane to 0. Set it to whatever as well, you just can't set the position.z of your objects closer.    //FinalNote: With orthogonal projection, the distance doesn't matter except in the order of drawing. Further away objects look NO SMALLER.    D3DXMatrixOrthoLH(&Temp, Desc.Width, Desc.Height, 0, 100);    GD->SetTransform(D3DTS_PROJECTION, &Temp);    BackBuffer->Release();//So that we reduce the internal count}void MakeDefaultQuad(IDirect3DDevice9* GD){    Vertex vertices[4] = {    { -0.5,  0.5,  0.0,  0.0,  0.0},    {  0.5,  0.5,  0.0,  1.0,  0.0},    { -0.5, -0.5,  0.0,  0.0,  1.0},    {  0.5, -0.5,  0.0,  1.0,  1.0}};    GD->CreateVertexBuffer(VERTEXSIZE*4, D3DUSAGE_WRITEONLY, VERTEXFVF, D3DPOOL_DEFAULT, &g_VBQuad, NULL);    BYTE *Ptr;    g_VBQuad->Lock(0, 0, (VOID**)&Ptr, 0);    memcpy(Ptr, vertices, VERTEXSIZE*4);    g_VBQuad->Unlock();}//Blit(Texture, Position, Rotation)//Texture: the 2d Sprite you want drawn (Doesn't contain functionality for multiple sprites on texture)//Position: x and y are the screen position of the CENTER of the texture, z is the layer (0 is closest, + is further away)//Rotation: z is the normal rotation compared to screen, x and y are pitch and roll (usually 0)//You MUST BeginScene before this! (Present and EndScene to actually display it)void Blit(IDirect3DTexture9* Texture, D3DXVECTOR3 Position, D3DXVECTOR3 Rotation){    IDirect3DDevice9* GD=NULL;    Texture->GetDevice(&GD);    if(GD != NULL)    {   IDirect3DDevice9* BuffGD=NULL;   g_VBQuad->GetDevice(&BuffGD);   if(GD != BuffGD)   {  return;   }    }    else    {   return;    }    D3DSURFACE_DESC SurDesc;    Texture->GetLevelDesc(0, &SurDesc);    D3DXMATRIX Temp, World;    D3DXMatrixIdentity(&World);    D3DXMatrixScaling(&Temp, SurDesc.Width, SurDesc.Height, 0);    D3DXMatrixMultiply(&World, &World, &Temp);    D3DXMatrixRotationX(&Temp, D3DXToRadian(Rotation.x));    D3DXMatrixMultiply(&World, &World, &Temp);    D3DXMatrixRotationY(&Temp, D3DXToRadian(Rotation.y));    D3DXMatrixMultiply(&World, &World, &Temp);    D3DXMatrixRotationZ(&Temp, D3DXToRadian(Rotation.z));    D3DXMatrixMultiply(&World, &World, &Temp);    D3DXMatrixTranslation(&Temp, Position.x, Position.y, Position.z);    D3DXMatrixMultiply(&World, &World, &Temp);    GD->SetTransform(D3DTS_WORLD, &World);    GD->SetStreamSource(0, &g_VBQuad, 0, VERTEXSIZE);    GD->SetTexture(0, Texture);    GD->DrawPrimitive(D3DPT_TRAINGLESTRIP, 0, 4);}That SHOULD work (theoretically) for any 2d you want to do, but it draws straight to the backbuffer. However, if I were you I'd go and get a book such as Programming Role Playing Games with DirectX by Jim Adams which has a great section on using 2d graphics (Chapter 11: "Using 2D Graphics").Also, a scrolling background would be one quad with a changing x/y position until the quad doesn't cover the entire screen at which point you would render another quad to make up the difference.Edit: Note to self: GameDev uses HTML, not UBB...   [edited by - Erzengeldeslichtes on February 4, 2004 9:41:15 PM];quote:Original post by Erzengeldeslichtes  You can learn how to use ID3DXSprite, which is probably easier and faster (I don''t know, never tried it), but that teaches you nothing about 3D, and the books I''ve looked at (granted I''ve been after 3d books), when they talk about 2d, use textured quad method.Using someone else''s "blit" function from a forum post doesn''t teach anything about 3D either. D3DXSprite (DX9-Summer 2003 edition) does texture batching and lots of other good stuff which will outperform the code you''ve provided quite substantially.  It would take quite a bit of effort for someone new to DX to make something that performed anywhere near the same level as D3DXSprite.quote:Also my method is order-indipendant, you simply use .z as layers.Since sprites typically have transparency, you still need to be concerned about drawing order.  However the new D3DXSprite interface can do the sorting for you automagically if you like, so in a sense it is order-independant. Stay Casual,KenDrunken Hyena;  As I said, I haven''t used ID3DXSprite very much, I don''t know much about it. Last I heard it was very order dependent. Apparently I''m wrong, and if it does texture batching then yes, it''s much better than the code I provided. I felt that rewriting my render queue code to make it run better and take advantage of blending would be a bit hard on someone starting DirectX.And using someone else''s blit function is more likely to teach you something about 3d than the ID3DXSprite interface because ID3DXSprite doesn''t provide you with easy access to the code to figure out what they''re doing, wheras my code does show you exactly what I''m doing so you can possibly figure it out when you want to figure out how to do more 3d work.Either way works, I''m sure. Fastest is probably ID3DXSprite, most relevent for later learning is probably mine. 