[TUTORIAL] Draw Text and Image from rF2 plugin

Discussion in 'Plugins' started by Gerald Jacobson, Jun 24, 2014.

  1. Gerald Jacobson

    Gerald Jacobson Registered

    Joined:
    Jan 26, 2013
    Messages:
    827
    Likes Received:
    11
    Here an example of code used to listen for UDP trame. As C language is not my programming language my code can be far from best.
    This code works in 32bit and 64bit (Use VC++ 2012 express - much easier to build DLL for 32bits and 64bits than VC++ 2010)

    Notes:
    - This example take the ISI example plugin as code base
    - In C when a variable is declared, it is not initialized with classical values (so if you do not explicitly set a variable default value in the constructor, a new created variable will have a random value) -> Main source of issue for JAVA, C#, ... developpers

    rF2 Plugin API notes
    There are two main methods, in the rF2 plugin API, allowing you to add your rendering code.

    - void RenderScreenBeforeOverlays( const ScreenInfoV01 &info ); // This method is called after the track/car rendering but before the rF2 overlays (like virtual mirrors)
    - void RenderScreenAfterOverlays( const ScreenInfoV01 &info ); // this method is called after rF2 overlays

    DirectX prerequisite
    To be able to use DirectX primitive, you need have DirectX SDK installed. You can download the "Microsoft DirectX SDK 28 June 2010"
    In you VC++ properties you need to set:
    - Project Properties > Configuration > VC++ Directories >> Include Directories : C:\Program Files %28x86%29\Microsoft DirectX SDK %28June 2010%29\Include;$(IncludePath)
    - Project Properties > Configuration > VC++ Directories >> Librairy Directories :
    ..... For 32bits: C:\Program Files %28x86%29\Microsoft DirectX SDK %28June 2010%29\Lib\x86;$(LibraryPath)
    ..... For 64bits: C:\Program Files %28x86%29\Microsoft DirectX SDK %28June 2010%29\Lib\x64;$(LibraryPath)

    DirectX includes
    In the Example.hpp, add the following includes:
    Code:
    #include <d3d9.h>
    #include <d3dx9.h>
    #pragma comment(lib, "d3d9.lib")
    #pragma comment(lib, "d3dx9.lib")
    
    Retrieve the DirectX device
    To be able to draw any kind of DirectX primitive, you need to retrieve the DirectX device from the rF2 API parameter "ScreenInfoV01 &info"
    Code:
        LPDIRECT3DDEVICE9 dev = static_cast<LPDIRECT3DDEVICE9>(info.mDevice);	
    
    Draw a text
    First, you need to create the DirectX font to use.
    Code:
    int fontSize = 16;
    int fontWeight = 400; // 400=Normal, 700=Bold (For all values, [URL="http://msdn.microsoft.com/en-us/library/windows/desktop/dd183499(v=vs.85).aspx"]see FW_xxxx constant for D3DXCreateFont[/URL])
    char fontName[] = "Arial";
    LPD3DXFONT font;
    D3DXCreateFont( dev, fontSize, 0, fontWeight, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH | FF_DONTCARE, TEXT(fontName), &font );
    
    Now, to draw a Text, you need to specify the rectangle in which the text will be drawn (and clipped), the text, alignment and the color.
    Code:
            RECT tmpRect;
            tmpRect.left = 100;
    	tmpRect.top = 100;
    	tmpRect.right = 400;
    	tmpRect.bottom = 150;
    
            int alignment = 1; // 0=left, 1=center, 2=right
            D3DCOLOR color= D3DCOLOR_ARGB( 255, 255, 0, 255 ); // alpha, r, g, b
    	font->DrawTextA(NULL, "Your text", -1, &tmpRect, alignment, color);
    
    Draw an image
    First you need to create the DirectX sprite object.
    Code:
        LPD3DXSPRITE sprite;
        D3DXCreateSprite(dev, &sprite);
    
    Then you need to create the texture object.
    You can create a texture from a file using
    Code:
        LPDIRECT3DTEXTURE9 texture;
        D3DXCreateTextureFromFileEx(dev, "c:/myImage.png", D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT, D3DX_FILTER_NONE, D3DX_FILTER_NONE, 0xFFFF00FF, NULL, NULL, &texture);
    
    or from a byte array "char buf[]" of length "int bufsize"
    Code:
        D3DXCreateTextureFromFileInMemory(device, &buf[0], bufsize, &texture); 
    
    If you need to retrieve the width and height of the image, you can use for a file
    Code:
            D3DXIMAGE_INFO imageInfo;
    	D3DXGetImageInfoFromFile("c:/myImage.png", &imageInfo);
    
    	float height = (float)imageInfo.Height;
    	float width = (float)imageInfo.Width;
    
    or from a buffer
    Code:
            D3DXIMAGE_INFO imageInfo;
    	D3DXGetImageInfoFromFileInMemory(&buf[0] , bufsize, &imageInfo);
    
    	float height = (float)imageInfo.Height;
    	float width = (float)imageInfo.Width;
    
    Now, you can render the sprite using matrix transformation for positioning, scaling, ...
    Code:
            D3DXMATRIX scaleMatrix; 
    	D3DXMATRIX transMatrix;
    	D3DXMatrixScaling(&scaleMatrix, 1, 1, 0); // x, y, z scale (z is not used as it is a 2D rendering)
    	D3DXMatrixTranslation(&transMatrix, 350, 500, 0); // x, y, z (z is not used as it is a 2D rendering)
    
    	D3DXMatrixMultiply(&transMatrix, &scaleMatrix, &transMatrix);
    	sprite->SetTransform(&transMatrix);
    
    	sprite->Begin(D3DXSPRITE_ALPHABLEND);
    	sprite->Draw(texture, NULL, NULL, NULL, color); //D3DCOLOR_RGBA(255,255,255,alpha));
    	sprite->End();
    
    Note : You can use the color to alter the original image color. For example, if you need several identical images but with different images (like colored rectangle, or colored spot), you can create you image as black/grey/white and apply a colored filter.
     
  2. cubbi

    cubbi Registered

    Joined:
    Jul 8, 2013
    Messages:
    90
    Likes Received:
    0
    Thanks a lot, that was really helpful!

    An important thing to note (might be obvious for people who often program in c++, but I had to find it out the hard way):

    You have to call Release() on LPD3DXFONT and LPDIRECT3DDEVICE9 or you will have a memory leak and your game will crash fairly soon :D

    So something like:

    Code:
    if (font != NULL)
        font->Release();
    
    if (dev == NULL)
        dev = static_cast<LPDIRECT3DDEVICE9>(info.mDevice);
    before the text is drawn.
     
  3. Gerald Jacobson

    Gerald Jacobson Registered

    Joined:
    Jan 26, 2013
    Messages:
    827
    Likes Received:
    11
    In a real plugin, you will not create a font or a sprite/texture before each draw call. You create it and store it to enhance performance. So you will release them only when necessary.
     

Share This Page