Problem with an array return-type of a function

Started by
4 comments, last by Barrow Boy 15 years, 8 months ago
I have a function that takes two arrays of structs, 'colors' and 'verts' (for vertices), then updates the array of verts according to the colors array. It then returns the new verts array, and I think this is where it's having problems. Here is the function:
CUSTOMVERTEX[3] update_verts( CUSTOMVERTEX verts[3], COLOR colors[3] )
{
	verts[0].COLOR = D3DCOLOR_XRGB( colors[0].R, colors[0].G, colors[0].B );
	verts[1].COLOR = D3DCOLOR_XRGB( colors[1].R, colors[1].G, colors[1].B );
	verts[2].COLOR = D3DCOLOR_XRGB( colors[2].R, colors[2].G, colors[2].B );

	return verts;
}
CUSTOMVERTEX has been defined thus:
struct CUSTOMVERTEX { FLOAT X, Y, Z, RHW; DWORD COLOR; };
and COLOR thus:
struct COLOR
{
	DWORD R, G, B;
	bool isFadingRed, isFadingGreen, isFadingBlue;
};
Here are the declarations of the two arrays:
COLOR t_colors[] =
	{
		{ 0, 0, 255, true, false, false },
		{ 0, 255, 0, false, true, false },
		{ 255, 0, 0, false, false, true },
	};
CUSTOMVERTEX t_vert[] =
	{
		{ 320.0f, 50.0f, 0.5f, 1.0f, D3DCOLOR_XRGB( 0, 0, 255 ), },
		{ 520.0f, 400.0f, 0.5f, 1.0f, D3DCOLOR_XRGB( 0, 255, 0 ), },
		{ 120.0f, 400.0f, 0.5f, 1.0f, D3DCOLOR_XRGB( 255, 0, 0 ), },
	};
Is there something wrong with my return type? The errors are:
c:\documents and settings\sam\my documents\visual studio 2008\projects\triangle2\triangle2\triangle2.cpp(89) : error C2143: syntax error : missing ';' before '['
c:\documents and settings\sam\my documents\visual studio 2008\projects\triangle2\triangle2\triangle2.cpp(89) : error C3409: empty attribute block is not allowed
c:\documents and settings\sam\my documents\visual studio 2008\projects\triangle2\triangle2\triangle2.cpp(89) : error C2143: syntax error : missing ']' before 'constant'
c:\documents and settings\sam\my documents\visual studio 2008\projects\triangle2\triangle2\triangle2.cpp(89) : error C2059: syntax error : 'constant'
c:\documents and settings\sam\my documents\visual studio 2008\projects\triangle2\triangle2\triangle2.cpp(90) : error C2143: syntax error : missing ';' before '{'
c:\documents and settings\sam\my documents\visual studio 2008\projects\triangle2\triangle2\triangle2.cpp(90) : error C2447: '{' : missing function header (old-style formal list?)
c:\documents and settings\sam\my documents\visual studio 2008\projects\triangle2\triangle2\triangle2.cpp(152) : error C3861: 'update_verts': identifier not found
Advertisement
You cannot return an array: arrays decay to pointers when passed to or returned from functions. You could modify the return type to a pointer, which is safe in this case because you are not returning a local pointer. Alternatively, you could put the array in a structure so that passing and returning works as expected:
struct Vertices{    CUSTOMVERTEX data[3];};Vertices update_verts( Vertices verts, COLOR colors[3] ){	verts.data[0].COLOR = D3DCOLOR_XRGB( colors[0].R, colors[0].G, colors[0].B );	verts.data[1].COLOR = D3DCOLOR_XRGB( colors[1].R, colors[1].G, colors[1].B );	verts.data[2].COLOR = D3DCOLOR_XRGB( colors[2].R, colors[2].G, colors[2].B );	return verts;}
When you pass an array in that way, the changes made locally by the function will affect the caller's version of the array - the array is "decayed" to a pointer, so that the function works directly with the caller's array instead of a pointer.

Consequently, you could just return void and have the caller just expect the changes in the array. (But note that if you need to keep the original data around, you will have to make a copy yourself, explicitly.)

This is just something that C and C++ do with arrays. It's a hack in the language design, really. If you want your arrays to actually behave like other data types in the language, you may want to wrap them in a struct yourself (as shown), or save yourself that effort by using boost::array.
Ok, I tried putting t_verts into a struct, and I get an error saying that it can't convert CUSTOMVERTEX[3] to FLOAT. Here is my struct:

CUSTOMVERTEX t_vert[] =	{		{ 320.0f, 50.0f, 0.5f, 1.0f, D3DCOLOR_XRGB( 0, 0, 255 ), },		{ 520.0f, 400.0f, 0.5f, 1.0f, D3DCOLOR_XRGB( 0, 255, 0 ), },		{ 120.0f, 400.0f, 0.5f, 1.0f, D3DCOLOR_XRGB( 255, 0, 0 ), },	};	verticies verts = { t_vert };

I would write it like this
void update_verts( CUSTOMVERTEX * const verts, COLOR * const colors, const size_t  elements ){        for( size_t i = 0; i < elements; i++ )	    verts.COLOR = D3DCOLOR_XRGB( colors.R, colors.G, colors.B );}


That should work fine, and fits in more with the name because it is updating a prexisting array, not creating a new one.
Treb, using your code, the program will run, but now I have a bigger problem. The program is meant to change the colors of the vertices of a triangle, but now it simply displays the triangle and the colors remain constant. Here's the code:

// include the basic windows header files and the Direct3D header file#include <windows.h>#include <windowsx.h>#include <d3d9.h>// define the screen resolution and keyboard macros#define SCREEN_WIDTH 1024#define SCREEN_HEIGHT 768#define KEY_DOWN( vk_code ) ( ( GetAsyncKeyState( vk_code ) & 0x8000 ) ? 1 : 0 )#define KEY_UP( vk_code ) ( ( GetAsyncKeyState( vk_code ) & 0x8000 ) ? 0 : 1 )// include the Direct3D Library file#pragma comment ( lib, "d3d9.lib" )// global declarationsLPDIRECT3D9 d3d;    // the pointer to our Direct3D interfaceLPDIRECT3DDEVICE9 d3ddev;    // the pointer to the device classLPDIRECT3DVERTEXBUFFER9 t_buffer = NULL;    // the pointer to the vertex buffer// function prototypesvoid initD3D( HWND hWnd );    // sets up and initializes Direct3Dvoid render_frame( void );    // renders a single framevoid cleanD3D( void );    // closes Direct3D and releases memoryvoid init_graphics( void );    // 3D declarationsstruct CUSTOMVERTEX { FLOAT X, Y, Z, RHW; DWORD COLOR; };#define CUSTOMFVF ( D3DFVF_XYZRHW | D3DFVF_DIFFUSE )size_t elements = 3;struct COLOR{	DWORD R, G, B;	bool isFadingRed, isFadingGreen, isFadingBlue;};struct verticies{	CUSTOMVERTEX data[3];};void switch_color( COLOR colors[3] ){	// alter colors[0]	if( colors[0].isFadingRed )	{		colors[0].isFadingRed = !colors[0].isFadingRed;		colors[0].isFadingGreen = !colors[0].isFadingGreen;	}	else if( colors[0].isFadingGreen )	{		colors[0].isFadingGreen = !colors[0].isFadingGreen;		colors[0].isFadingBlue = !colors[0].isFadingBlue;	}	else	{		colors[0].isFadingBlue = !colors[0].isFadingBlue;		colors[0].isFadingRed = !colors[0].isFadingRed;	}	// alter colors[1]	if( colors[1].isFadingRed )	{		colors[1].isFadingRed = !colors[1].isFadingRed;		colors[1].isFadingGreen = !colors[1].isFadingGreen;	}	else if( colors[1].isFadingGreen )	{		colors[1].isFadingGreen = !colors[1].isFadingGreen;		colors[1].isFadingBlue = !colors[1].isFadingBlue;	}	else	{		colors[1].isFadingBlue = !colors[1].isFadingBlue;		colors[1].isFadingRed = !colors[1].isFadingRed;	}	// alter colors[2]	if( colors[2].isFadingRed )	{		colors[2].isFadingRed = !colors[2].isFadingRed;		colors[2].isFadingGreen = !colors[2].isFadingGreen;	}	else if( colors[2].isFadingGreen )	{		colors[2].isFadingGreen = !colors[2].isFadingGreen;		colors[2].isFadingBlue = !colors[2].isFadingBlue;	}	else	{		colors[2].isFadingBlue = !colors[2].isFadingBlue;		colors[2].isFadingRed = !colors[2].isFadingRed;	}}void update_verts( CUSTOMVERTEX * const verts, COLOR * const colors, const size_t  elements ){        for( size_t i = 0; i < elements; i++ )	    verts.COLOR = D3DCOLOR_XRGB( colors.R, colors.G, colors.B );}void graphics_loop( CUSTOMVERTEX verts[3], COLOR colors[3], short &count ){	// alter colors[0]	if( colors[0].isFadingRed )	{		colors[0].R++;		colors[0].B--;	}	else if( colors[0].isFadingGreen )	{		colors[0].G++;		colors[0].R--;	}	else	{		colors[0].B++;		colors[0].G--;	}	// alter colors[1]	if( colors[1].isFadingRed )	{		colors[1].R++;		colors[1].B--;	}	else if( colors[1].isFadingGreen )	{		colors[1].G++;		colors[1].R--;	}	else	{		colors[1].B++;		colors[1].G--;	}	// alter colors[2]	if( colors[2].isFadingRed )	{		colors[2].R++;		colors[2].B--;	}	else if( colors[2].isFadingGreen )	{		colors[2].G++;		colors[2].R--;	}	else	{		colors[2].B++;		colors[2].G--;	}	// update verts array	update_verts( verts, colors, elements );	if( count == 255 )	{		switch_color( colors );		count = 0;	}    VOID* pVoid;    // a void pointer    // lock t_buffer and load the vertices into it    t_buffer->Lock( 0, 0, ( void** )&pVoid, 0 );    memcpy( pVoid, verts, sizeof( verts ) );    t_buffer->Unlock();	return;}// the WindowProc function prototypeLRESULT CALLBACK WindowProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam );// the entry point for any Windows programint WINAPI WinMain( HINSTANCE hInstance,                   HINSTANCE hPrevInstance,                   LPSTR lpCmdLine,                   int nCmdShow ){    HWND hWnd;    WNDCLASSEX wc;    ZeroMemory( &wc, sizeof( WNDCLASSEX ) );    wc.cbSize = sizeof( WNDCLASSEX );    wc.style = CS_HREDRAW | CS_VREDRAW;    wc.lpfnWndProc = ( WNDPROC )WindowProc;    wc.hInstance = hInstance;    wc.hCursor = LoadCursor( NULL, IDC_ARROW );    // wc.hbrBackground = ( HBRUSH )COLOR_WINDOW;    // not needed any more    wc.lpszClassName = L"WindowClass";    RegisterClassEx( &wc );    hWnd = CreateWindowEx( NULL,                          L"WindowClass",                          L"Our Direct3D Program",                          WS_EX_TOPMOST | WS_POPUP,    // fullscreen values                          0, 0,    // the starting x and y positions should be 0                          SCREEN_WIDTH, SCREEN_HEIGHT,    // set the window to 640 x 480                          NULL,                          NULL,                          hInstance,                          NULL );    ShowWindow( hWnd, nCmdShow );    // set up and initialize Direct3D    initD3D( hWnd );	short count = 0;	COLOR t_colors[] =	{		{ 0, 0, 255, true, false, false },		{ 0, 255, 0, false, true, false },		{ 255, 0, 0, false, false, true },	};	CUSTOMVERTEX t_vert[] =	{		{ 320.0f, 50.0f, 0.5f, 1.0f, D3DCOLOR_XRGB( 0, 0, 255 ), },		{ 520.0f, 400.0f, 0.5f, 1.0f, D3DCOLOR_XRGB( 0, 255, 0 ), },		{ 120.0f, 400.0f, 0.5f, 1.0f, D3DCOLOR_XRGB( 255, 0, 0 ), },	};    // enter the main loop:    MSG msg;    while( TRUE )    {        DWORD starting_point = GetTickCount();        if ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )        {            if ( msg.message == WM_QUIT )                break;            TranslateMessage( &msg );            DispatchMessage( &msg );        }		graphics_loop( t_vert, t_colors, count );        render_frame();        // check the 'escape' key        if( KEY_DOWN( VK_ESCAPE ) )            PostMessage( hWnd, WM_DESTROY, 0, 0 );        while ( ( GetTickCount() - starting_point ) < 25 );    }    // clean up DirectX and COM    cleanD3D();    return msg.wParam;}// this is the main message handler for the programLRESULT CALLBACK WindowProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ){    switch( message )    {        case WM_DESTROY:            {                PostQuitMessage( 0 );                return 0;            } break;    }    return DefWindowProc ( hWnd, message, wParam, lParam );}// this function initializes and prepares Direct3D for usevoid initD3D( HWND hWnd ){    d3d = Direct3DCreate9( D3D_SDK_VERSION );    D3DPRESENT_PARAMETERS d3dpp;    ZeroMemory( &d3dpp, sizeof( d3dpp ) );    d3dpp.Windowed = FALSE;    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;    d3dpp.hDeviceWindow = hWnd;    d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;    d3dpp.BackBufferWidth = SCREEN_WIDTH;    d3dpp.BackBufferHeight = SCREEN_HEIGHT;    // create a device class using this information and the info from the d3dpp stuct    d3d->CreateDevice( D3DADAPTER_DEFAULT,                      D3DDEVTYPE_HAL,                      hWnd,                      D3DCREATE_SOFTWARE_VERTEXPROCESSING,                      &d3dpp,                      &d3ddev );	init_graphics();    return;}// this is the function used to render a single framevoid render_frame( void ){    d3ddev->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB( 0, 0, 0 ), 1.0f, 0 );    d3ddev->BeginScene();        // select which vertex format we are using        d3ddev->SetFVF( CUSTOMFVF );        // select the vertex buffer to display        d3ddev->SetStreamSource( 0, t_buffer, 0, sizeof( CUSTOMVERTEX ) );        // copy the vertex buffer to the back buffer        d3ddev->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 1 );    d3ddev->EndScene();    d3ddev->Present( NULL, NULL, NULL, NULL );    return;}// this is the function that cleans up Direct3D and COMvoid cleanD3D( void ){    t_buffer->Release();    // close and release the vertex buffer    d3ddev->Release();    // close and release the 3D device    d3d->Release();    // close and release Direct3D    return;}void init_graphics(){	CUSTOMVERTEX t_vert[] =	{		{ 320.0f, 50.0f, 0.5f, 1.0f, D3DCOLOR_XRGB( 0, 0, 255 ), },		{ 520.0f, 400.0f, 0.5f, 1.0f, D3DCOLOR_XRGB( 0, 255, 0 ), },		{ 120.0f, 400.0f, 0.5f, 1.0f, D3DCOLOR_XRGB( 255, 0, 0 ), },	};	// create a vertex buffer interface called t_buffer    d3ddev->CreateVertexBuffer( 3*sizeof( CUSTOMVERTEX ),                               0,                               CUSTOMFVF,                               D3DPOOL_MANAGED,                               &t_buffer,                               NULL );    VOID* pVoid;    // a void pointer    // lock t_buffer and load the vertices into it    t_buffer->Lock( 0, 0, ( void** )&pVoid, 0 );    memcpy( pVoid, t_vert, sizeof( t_vert ) );    t_buffer->Unlock();	return;}

This topic is closed to new replies.

Advertisement