2D Map Viewer Unhandled Exception

46 views Asked by At

Currently I'm trying to get a Tiled map to load correctly. I've spent the majority of a day searching for help including on here and I've found nothing. So I decided to go on my instinct, rewrite the code from how I thought it should work, and ignore the Beginning Game Programming book I have, because the chapter involving tile maps is using LPDIRECT3DSURFACE9 instead of a LPDIRECT3DTEXTURE9, and I need the transparency.

So I removed all the extra code, and I'm left with what my gut tells me should render the tile map if it didn't throw an exception. I have spent all day with varying success on rendering the map, which is why I'm stripping it down to bare minimum of what it needs.

Unhandled exception at 0x00893eaa in Platformer.exe: 0xC0000005: Access violation reading location 0x008a9000.

The specific function that this error points to is this:

void BuildGameWorld()
{
    int x, y;
    LPDIRECT3DTEXTURE9 tiles = nullptr;

    //load the texture file
    tiles = LoadTexture("tiles_spritesheet.png", D3DCOLOR_XRGB(255, 0, 255));

    for(y = 0; y < GAMEWORLDHEIGHT; y++)
    {
        for(x = 0; x < GAMEWORLDWIDTH; x++)
        {
                    /****** THIS LINE HERE ******/
            DrawTile(tiles, MAPDATA[y * MAPWIDTH + x], 2, 70, 70, 12, backbuffer, x * 70, y * 70, D3DCOLOR_XRGB(255,255,255));
        }
    }

    //release the texture file
    tiles->Release();
}

The rest of the source code is here

//Filename: MyDirectX.h
#pragma once

//header files
#define WIN32_EXTRA_LEAN
#include <windows.h>
#include <d3d9.h>
#include <d3dx9.h>
#include <ctime>
#include <iostream>
#include <sstream>
#include <iomanip>
using namespace std;

//libraries
#pragma comment(lib,"winmm.lib")
#pragma comment(lib,"user32.lib")
#pragma comment(lib,"gdi32.lib")
#pragma comment(lib,"dxguid.lib")
#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")

//program values
extern const string APPTITLE;
extern const int SCREENW;
extern const int SCREENH;
extern bool gameover;

//Direct3D objects
extern LPDIRECT3D9 d3d; 
extern LPDIRECT3DDEVICE9 d3ddev; 
extern LPDIRECT3DSURFACE9 backbuffer;
extern LPD3DXSPRITE spriteobj;

//Direct3D functions
bool Direct3D_Init(HWND hwnd, int width, int height, bool fullscreen);
void Direct3D_Shutdown();

LPDIRECT3DSURFACE9 LoadSurface(string filename);
void DrawSurface(LPDIRECT3DSURFACE9 dest, float x, float y, LPDIRECT3DSURFACE9 source);

LPDIRECT3DTEXTURE9 LoadTexture(string filename, D3DCOLOR transcolor = D3DCOLOR_XRGB(0,0,0));
//game functions
bool Game_Init(HWND window);
void Game_Run(HWND window);
void Game_End();

void DrawTile(LPDIRECT3DTEXTURE9 source, int frame,int spacing, int width, int height, int columns, LPDIRECT3DSURFACE9 dest, int destx, int desty, D3DCOLOR color);
void BuildGameWorld();


//Filename: MyDirectX.cpp
#include "MyDirectX.h"
#include <iostream>
using namespace std;

//Direct3D variables
LPDIRECT3D9 d3d = NULL; 
LPDIRECT3DDEVICE9 d3ddev = NULL; 
LPDIRECT3DSURFACE9 backbuffer = NULL;
LPD3DXSPRITE spriteobj;

bool Direct3D_Init(HWND window, int width, int height, bool fullscreen)
{
    //initialize Direct3D
    d3d = Direct3DCreate9(D3D_SDK_VERSION);
    if (!d3d) return false;

    //set Direct3D presentation parameters
    D3DPRESENT_PARAMETERS d3dpp; 
    ZeroMemory(&d3dpp, sizeof(d3dpp));
    d3dpp.hDeviceWindow = window;
    d3dpp.Windowed = (!fullscreen);
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.EnableAutoDepthStencil = 1;
    d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
    d3dpp.Flags = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;
    d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
    d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
    d3dpp.BackBufferCount = 1;
    d3dpp.BackBufferWidth = width;
    d3dpp.BackBufferHeight = height;

    //create Direct3D device
    d3d->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window,
        D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev);
    if (!d3ddev) return false;


    //get a pointer to the back buffer surface
    d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);

    //create sprite object
    D3DXCreateSprite(d3ddev, &spriteobj);

    return 1;
}
void Direct3D_Shutdown()
{
    if (spriteobj) spriteobj->Release();

    if (d3ddev) d3ddev->Release();
    if (d3d) d3d->Release();
}

void DrawSurface(LPDIRECT3DSURFACE9 dest, float x, float y, LPDIRECT3DSURFACE9 source)
{
    //get width/height from source surface
    D3DSURFACE_DESC desc;
    source->GetDesc(&desc);

    //create rects for drawing
    RECT source_rect = {0, 0, (long)desc.Width, (long)desc.Height };
    RECT dest_rect = { (long)x, (long)y, (long)x+desc.Width, (long)y+desc.Height};

    //draw the source surface onto the dest
    d3ddev->StretchRect(source, &source_rect, dest, &dest_rect, D3DTEXF_NONE);

}
LPDIRECT3DSURFACE9 LoadSurface(string filename)
{
    LPDIRECT3DSURFACE9 image = NULL;

    //get width and height from bitmap file
    D3DXIMAGE_INFO info;
    HRESULT result = D3DXGetImageInfoFromFile(filename.c_str(), &info);
    if (result != D3D_OK)
        return NULL;

    //create surface
    result = d3ddev->CreateOffscreenPlainSurface(
        info.Width,         //width of the surface
        info.Height,        //height of the surface
        D3DFMT_X8R8G8B8,    //surface format
        D3DPOOL_DEFAULT,    //memory pool to use
        &image,             //pointer to the surface
        NULL);              //reserved (always NULL)

    if (result != D3D_OK) return NULL;

    //load surface from file into newly created surface
    result = D3DXLoadSurfaceFromFile(
        image,                  //destination surface
        NULL,                   //destination palette
        NULL,                   //destination rectangle
        filename.c_str(),       //source filename
        NULL,                   //source rectangle
        D3DX_DEFAULT,           //controls how image is filtered
        D3DCOLOR_XRGB(0,0,0),   //for transparency (0 for none)
        NULL);                  //source image info (usually NULL)

    //make sure file was loaded okay
    if (result != D3D_OK) return NULL;

    return image;
}

LPDIRECT3DTEXTURE9 LoadTexture(std::string filename, D3DCOLOR transcolor)
{  
    LPDIRECT3DTEXTURE9 texture = NULL;

    //get width and height from bitmap file
    D3DXIMAGE_INFO info;
    HRESULT result = D3DXGetImageInfoFromFile(filename.c_str(), &info);
    if (result != D3D_OK) return NULL;

    //create the new texture by loading a bitmap image file
    D3DXCreateTextureFromFileEx( 
        d3ddev,                //Direct3D device object
        filename.c_str(),      //bitmap filename
        info.Width,            //bitmap image width
        info.Height,           //bitmap image height
        1,                     //mip-map levels (1 for no chain)
        D3DPOOL_DEFAULT,       //the type of surface (standard)
        D3DFMT_UNKNOWN,        //surface format (default)
        D3DPOOL_DEFAULT,       //memory class for the texture
        D3DX_DEFAULT,          //image filter
        D3DX_DEFAULT,          //mip filter
        transcolor,            //color key for transparency
        &info,                 //bitmap file info (from loaded file)
        NULL,                  //color palette
        &texture );            //destination texture

    //make sure the bitmap textre was loaded correctly
    if (result != D3D_OK) return NULL;

    return texture;
}

//Filename: MyGame.cpp
#include "MyDirectX.h"
using namespace std;

const string APPTITLE = "2D Platformer";
const int SCREENW = 1024;
const int SCREENH = 768;

//settings for the scroller
const int TILEWIDTH = 70;
const int TILEHEIGHT = 70;
const int MAPWIDTH = 30;
const int MAPHEIGHT = 10;

//scrolling window size
const int WINDOWWIDTH = (SCREENW / TILEWIDTH) * TILEWIDTH;
const int WINDOWHEIGHT = (SCREENH / TILEHEIGHT) * TILEHEIGHT;

//entire gameworld dimensions
const int GAMEWORLDWIDTH = TILEWIDTH * MAPWIDTH;
const int GAMEWORLDHEIGHT = TILEHEIGHT * MAPHEIGHT;

int MAPDATA[MAPWIDTH*MAPHEIGHT] = 
{
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,
    10,10,10,10,10,10,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,153,
    153,153,153,153,153,153,153,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,153,
    153,153,153,153,153,153,153,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,133,0,0,153,
    153,153,153,153,153,153,153,10,10,10,10,10,103,103,103,103,103,103,103,103,103,103,103,103,103,10,10,10,10,153,
    153,153,153,153,153,153,153,153,153,153,153,153,44,44,44,44,44,44,44,44,44,44,44,44,44,153,153,153,153,153
};

bool Game_Init(HWND window)
{
    //initialize Direct3D
    Direct3D_Init(window, SCREENW, SCREENH, false);

    //create a pointer to the backbuffer
    d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);

    return true;
}
void Game_Run(HWND window)
{
    //make sure the Direct3D device is valid
    if (!d3ddev) return;

    //clear the scene
    d3ddev->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,100), 1.0f, 0);

        //start rendering
        if (d3ddev->BeginScene())
        {

           spriteobj->Begin(D3DXSPRITE_ALPHABLEND);

           BuildGameWorld();

           spriteobj->End();

            //stop rendering
            d3ddev->EndScene();
            d3ddev->Present(NULL, NULL, NULL, NULL);
        }

    //exit when escape key is pressed
    if (GetAsyncKeyState(VK_ESCAPE)) 
        gameover = true;

}
void Game_End()
{
    //free memory and shut down
    Direct3D_Shutdown();
}

void DrawTile(LPDIRECT3DTEXTURE9 source, int frame,int spacing, int width, int height, int columns, LPDIRECT3DSURFACE9 dest, int destx, int desty, D3DCOLOR color)
{
    //get dimensions for the tile
    RECT r1;
    r1.left = ((frame % columns) + spacing * frame) * width;
    r1.top = (frame / columns) * height;
    r1.right = r1.left + width;
    r1.bottom = r1.top + height;

    //draw the sprite
    spriteobj->Draw(source, &r1, &D3DXVECTOR3(r1.right / 2, r1.bottom / 2, 0), &D3DXVECTOR3(destx, desty, 0), color);
}

void BuildGameWorld()
{
    int x, y;
    LPDIRECT3DTEXTURE9 tiles = nullptr;

    //load the texture file
    tiles = LoadTexture("tiles_spritesheet.png", D3DCOLOR_XRGB(255, 0, 255));

    for(y = 0; y < GAMEWORLDHEIGHT; y++)
    {
        for(x = 0; x < GAMEWORLDWIDTH; x++)
        {
            DrawTile(tiles, MAPDATA[y * MAPWIDTH + x], 2, 70, 70, 12, backbuffer, x * 70, y * 70, D3DCOLOR_XRGB(255,255,255));
        }
    }

    //release the texture file
    tiles->Release();
}

//Filename: MyWindows.cpp
#include "MyDirectX.h"
using namespace std;
bool gameover = false;


LRESULT WINAPI WinProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
    switch( msg )
    {
        case WM_DESTROY:
            gameover = true;
            PostQuitMessage(0);
            return 0;
    }
    return DefWindowProc( hWnd, msg, wParam, lParam );
}


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    //initialize window settings
    WNDCLASSEX wc;
    wc.cbSize = sizeof(WNDCLASSEX); 
    wc.style         = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc   = (WNDPROC)WinProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = NULL;
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = APPTITLE.c_str();
    wc.hIconSm       = NULL;
    RegisterClassEx(&wc);

    //create a new window
    HWND window = CreateWindow( APPTITLE.c_str(), APPTITLE.c_str(),
       WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
       SCREENW, SCREENH, NULL, NULL, hInstance, NULL);
    if (window == 0) return 0;

    //display the window
    ShowWindow(window, nCmdShow);
    UpdateWindow(window);

    //initialize the game
    if (!Game_Init(window)) return 0;

    // main message loop
    MSG message;
    while (!gameover)
    {
        if (PeekMessage(&message, NULL, 0, 0, PM_REMOVE)) 
        {
            TranslateMessage(&message);
            DispatchMessage(&message);
        }

        //process game loop 
        Game_Run(window);
    }

    //shutdown
    Game_End();
    return message.wParam;
}
1

There are 1 answers

1
art On BEST ANSWER

Your map is declared as

int MAPDATA[MAPWIDTH*MAPHEIGHT]

While you are using x, y indexes as

for(y = 0; y < GAMEWORLDHEIGHT; y++) { 
  for(x = 0; x < GAMEWORLDWIDTH; x++) {  } }

Where

const int GAMEWORLDWIDTH = TILEWIDTH * MAPWIDTH; 
const int GAMEWORLDHEIGHT = TILEHEIGHT * MAPHEIGHT;