C Board  

Go Back   C Board > General Programming Boards > Game Programming

Reply
 
LinkBack Thread Tools Display Modes
Old 10-30-2005, 04:42 AM   #1
Super Moderator
 
Bubba's Avatar
 
Join Date: Aug 2001
Posts: 7,472
New editor updates

Check out this editor I've been toiling over forever.

I finally got transparent blitting working in GDI.

Pretty simple really. Link with msimg32.lib and use TransparentBlt(). It's faster than writing your own and it stretches/shrinks images to fit the destination rectangle. Nice...very nice.
__________________
If you aim at everything you will hit something but you won't know what it is.
Bubba is offline   Reply With Quote
Old 10-30-2005, 06:30 AM   #2
Registered User
 
Join Date: May 2004
Posts: 1,362
Is this what you have done with MFC?
sand_man is offline   Reply With Quote
Old 10-30-2005, 08:10 AM   #3
 
Join Date: May 2005
Posts: 962
Looks like a very functional tile editor, keep up the good work.
__________________
argus triad mingus
BobMcGee123 is offline   Reply With Quote
Old 10-30-2005, 01:09 PM   #4
Super Moderator
 
Bubba's Avatar
 
Join Date: Aug 2001
Posts: 7,472
Yeppers. This is what I've done with MFC. I'm not a woman, but I'm sure this experience has been akin to childbirth.

__________________
If you aim at everything you will hit something but you won't know what it is.
Bubba is offline   Reply With Quote
Old 10-30-2005, 05:34 PM   #5
Registered User
 
Join Date: May 2004
Posts: 1,362
lol well it looks well worth it.
sand_man is offline   Reply With Quote
Old 10-30-2005, 06:49 PM   #6
 
Join Date: May 2005
Posts: 962
Quote:
Originally Posted by Bubba
Yeppers. This is what I've done with MFC. I'm not a woman, but I'm sure this experience has been akin to childbirth.

ha, I'll have to remember that one
__________________
argus triad mingus
BobMcGee123 is offline   Reply With Quote
Old 11-05-2005, 07:30 AM   #7
Super Moderator
 
Bubba's Avatar
 
Join Date: Aug 2001
Posts: 7,472
Added more support to the editor. Having a lot of problems with zooming. Anyone have any ideas on how to do this?

As you can see really big maps are supported. Here is one with 17 layers and a map size of 1000x1000.
__________________
If you aim at everything you will hit something but you won't know what it is.
Bubba is offline   Reply With Quote
Old 11-05-2005, 08:38 AM   #8
Registered User
 
Join Date: Aug 2001
Posts: 411
Quote:
Originally Posted by Bubba
Added more support to the editor. Having a lot of problems with zooming. Anyone have any ideas on how to do this?

As you can see really big maps are supported. Here is one with 17 layers and a map size of 1000x1000.

Provided that i have no idea how your code is designed, what I would try first is to create a new child window, like one of the tile selection windows, and use it to display a 50x50 grid of the main map It should not be too hard to setup methods to transfer all the data for a small grid back and forth. Give it scroll bars so you can move around, and maybe even another mouse tool so you can snap the focus to another spot by clicking on the desired spot on the main map. Make the soom window resizable, but with a fixed aspect ratio, and instead of changing the number of tiles displayed, if grows and shrinks the tiles.
__________________
www.EberKain.com
Eber Kain is offline   Reply With Quote
Old 11-05-2005, 03:26 PM   #9
Super Moderator
 
Bubba's Avatar
 
Join Date: Aug 2001
Posts: 7,472
Well here is what I have. The scrolling is done in the main window. I would like to create that type of map system but the calculations are far beyond what I would have imagined - they get complicated. You can zoom in on this map until cell sizes reach 256 pixels. My idea is that I never want the map to have borders. In other words if you zoom out far enough, I never want you to be able to see off of the map. My calculations are as follows. It works fine for computing the scrolling maxX and maxY, but when you zoom in, scroll down, and then zoom out.....everything goes to um...crap.

Code:
void CZeldaEditorView::UpdateScrollSizes()
{
  //Set new scroll sizes based on map size and current cellsize
  //or grid size  
  CSize size;

  //Get pointer to document class for map info
  CZeldaEditorDoc *pDoc=(CZeldaEditorDoc *)GetDocument();
  size.cx=pDoc->m_iMapSizeX*m_iGridSize;
  size.cy=pDoc->m_iMapSizeY*m_iGridSize;
  SetScrollSizes(MM_TEXT,size);

  //Retrieve width and height of client rect
  CRect rect;
  GetClientRect(&rect);
 
  int mapx=pDoc->m_iMapSizeX;
  int mapy=pDoc->m_iMapSizeY;
  int maxx=pDoc->m_iMapSizeX*m_iGridSize;
  int maxy=pDoc->m_iMapSizeY*m_iGridSize;

  //Set max scroll
  m_iMaxScrollX=(m_iGridSize*(mapx-1))-rect.Width();
  m_iMaxScrollY=(m_iGridSize*mapy)-rect.Height();
  
  //Don't show borders
  if (m_iMaxScrollX<0) m_iMaxScrollX=0;
  if (m_iMaxScrollY<0) m_iMaxScrollY=0;
  
  //If map size won't fit in window because map is too small
  //Re-adjust cell size so map fits perfectly in window
  if (rect.Width()>=maxx-m_iGridSize) 
  {
    m_iGridSize=rect.Width()/mapx;
    m_iScrollX=-m_iMaxScrollX;
    m_iScrollY=-m_iMaxScrollY;
  }

}

//Transforms mouse clicks to always click on nearest tile
//to cursor regardless of zoom and scroll
void CZeldaEditorView::TransformMouseXY(CPoint mouse,CRect &rect,DWORD &offset)
{
  //Find out remainder of m_iScrollX/m_iGridSize
  int offsetx=(m_iScrollX % m_iGridSize);
  int offsety=(m_iScrollY % m_iGridSize);

  //Temporaries so I don't have to use mouse.x, mouse.y every
  //time
  int mx=mouse.x;
  int my=mouse.y;

  //Subtract mouse by offsets
  mx-=offsetx;
  my-=offsety;

  //Snap to grid size
  mx-=(mx % m_iGridSize);
  my-=(my % m_iGridSize);

  //Re-adjust on-screen rect to new grid rectangle
  rect.left=mx+offsetx;
  rect.top=my+offsety;
  rect.right=mx+m_iGridSize+offsetx;
  rect.bottom=my+m_iGridSize+offsety;

  //Compute actual memory location of grid clicked
  int MemoryX=(mouse.x - m_iScrollX)/m_iGridSize;
  int MemoryY=(mouse.y - m_iScrollY)/m_iGridSize;

  //Set offset in document
  CZeldaEditorDoc *ptrDoc=(CZeldaEditorDoc *)GetDocument();
  offset=MemoryY*ptrDoc->m_iMapSizeX+MemoryX;

}

Sorry for the mess but MFC code is a mess. Basically I'm adhering to the document/view architecture so that the document handles the info about the map and the view just draws the map according to the info. It's a real pain in the arse.

These calculations work but zooming only zooms in on the upper left corner. I know why it does this, but how would I zoom in on an area? Do I have to draw my map relative to the center of the screen, or can I just start at the upper left corner and set m_iScrollX and m_iScrollY to different values when zooming to get the zoom in on a point effect?

Hard to explain.

Maybe showing the actual OnDraw() will help.

Pardon the mess but it's a major work in progress.

Code:
void CZeldaEditorView::OnDraw(CDC* pDC)
{
  //Pointer to document class
  CZeldaEditorDoc* pDoc = (CZeldaEditorDoc *)GetDocument();
  //Pointer to frame clasee
  CMainFrame *ptrFrame=(CMainFrame *)AfxGetMainWnd();
  //Number of maps (layers)
  DWORD numMaps=pDoc->m_pMapManager->GetNumberOfMaps();

  //Handle to destination DC
  HDC dcDest=pDC->GetSafeHdc();
    
  //Black brush for drawing
  CBrush blackbrush;
  blackbrush.CreateSolidBrush(RGB(0,0,0));
  
  //Retrieve client rect
  CRect ScreenRect;
  GetClientRect(&ScreenRect);

  //Fill it with black
  pDC->FillRect(&ScreenRect,&blackbrush);

  //Check for tile manager and map count
  //Don't draw if null or maps=0
  if (pDoc->m_pTileManager && numMaps>1)
  {
    //Tile size from bitmap
    int TileSize=pDoc->m_iTileSize;

    //Horizontal offset - debug info
    int iOffsetHoriz=abs(m_iScrollX/m_iGridSize);

    //Vertical offset - debug info
    int iOffsetVert=abs(m_iScrollY/m_iGridSize);

     //Function to compute relative to center of screenrect
     //Algos don't work right with this yet
    //ComputeStartGrid();
    
    //Iterate through maps
    //m_dwStartMapNum  is starting map
    //m_dwEndMapNum is ending map
    //To view one layer set start to layer and end to start+1
    for (DWORD map=m_dwStartMapNum;map<m_dwEndMapNum;map++)
    {

      //Get pointer to map
      CMap *ptrMap=pDoc->m_pMapManager->GetMapClass(map);

      //Get pointer to movement map - disabled
     //CMap *ptrMove=pDoc->m_pMapManager->GetMapClass(0);
   
      //Screen calculations for memory offset
      int CurrentY=(-m_iScrollY/m_iGridSize);
      int CurrentX=(-m_iScrollX/m_iGridSize);

      //Remember CurrentX before it changes
      int OriginX=CurrentX;

      //Compute memory offset
      DWORD offset=CurrentY*pDoc->m_iMapSizeX+CurrentX;
      int offsetx=m_iScrollX % m_iGridSize;
      int offsety=m_iScrollY % m_iGridSize;
  
      //Save starting offset
      DWORD startoffset=offset;

     //Rect for grid display - if enabled 
     CRect GridRect;
     

      //Draw the map finally
      for (int i=offsety;i<ScreenRect.bottom;i+=m_iGridSize)
      {
        for (int j=offsetx;j<ScreenRect.right;j+=m_iGridSize)
        {
          
          //Retrieve ID from map            
          DWORD ID=ptrMap->GetValueAtOffset(offset);
          
          //If this block is not empty          
          if (ID!=0xFFFFFFFF)
          {
            //Get DC of tile bitmap from tile manager
            CDC *tempDC=pDoc->m_pTileManager->GetTileDC(ID);

            //Get handle to tile bitmap DC
            HDC dcSource=tempDC->GetSafeHdc();

            //Get transparent color of tile
            UINT dwTransColor=pDoc->m_pTileManager->GetTransColor(ID);
            
          //Do a transparent blit
          ::TransparentBlt(dcDest,
                             j,i,
                             m_iGridSize,m_iGridSize,
                             dcSource,
                             0,0,
                             TileSize,TileSize,
                             dwTransColor);
          }

          //Draw the grid
          GridRect.left=j;
          GridRect.top=i;
          GridRect.right=j+m_iGridSize;
          GridRect.bottom=i+m_iGridSize;
          
          //If view->Grid checked then draw grid
          if (m_bGrid) 
          {
                      
            CBrush gridbrush;
            gridbrush.CreateSolidBrush(RGB(255,255,255));

            pDC->FrameRect(&GridRect,&gridbrush);
          }

          //Increment offset into memory                 
          offset++;
          
          //Increment cell column counter
          CurrentX++;

          //If column is at width of map break
          if (CurrentX>=pDoc->m_iMapSizeX-1) break;
        }
          //Set column counter to origin 
          CurrentX=OriginX;

          //Increment startoffset by one row
          startoffset+=pDoc->m_iMapSizeX;

          //Save startoffset
          offset=startoffset;

          //Increment row counter
          CurrentY++;

          //If no more rows, break
          if (CurrentY>pDoc->m_iMapSizeY-1) break;     
      }
    }
  }

}
Now the reason that the OnDraw is so extensive is because I did not want to compute the memory offset inside of the loop to render the grid. That would be slow. So I pre-compute the memory offset - which is already taking into account the scrolling values and so it is at the right spot in memory to correctly display the grid. The entire visible portion of the map can be drawn without re-computing the offset. When the column counter reaches the map size OR the X value of the render reaches the right side of the client rectangle, the row counter is incremented, column counter is reset (originX at current is always 0), starting offset is incremented by one row (m_iMapSizeX), and current offset is set to the starting offset.

It'a a pain in the arse but it's a linear algorithm and it's quite fast.
The array is indexed in linear fashion and the render is done in linear fashion. The Tile manager holds all of the tiles. But get this. Instead of storing bitmaps each tile is an object with a device context that has been prepared beforehand so the image data is on the device context. Then blitting the image is as simple as using TransparentBlt from the API using the handles to the source DC and the dest DC. Simple.

It all works great. But zooming is a mess. The ComputeStartGrid() function is a function that can center the grid inside of the client rect, but then all of the LButtonDown and MouseMove() functions don't compute the mouse cursor to grid and mouse cursor to memory right.

If you'ev ever done a tile engine I'm sure you will understand in the editor you must transform mouse clicks to align with the displayed grid or you cannot place tiles correctly.

Also if the current tile is the selected tile and you click on the tile in the map, it erases it. The selected tile is stored in the m_pTileManager class and is set by the tile tool dialogs when you select a tile to use.

This hasn't been easy so forgive me if the algo sucks.
__________________
If you aim at everything you will hit something but you won't know what it is.

Last edited by Bubba; 11-05-2005 at 03:51 PM.
Bubba is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Forum Jump


All times are GMT -6. The time now is 12:18 PM.


Powered by vBulletin® Version 3.8.1
Copyright ©2000 - 2009, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.3.0 RC2

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22