Archived

This topic is now archived and is closed to further replies.

Structs for bitmaps

This topic is 5772 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I copied some code from one function to another and now I get this- UCHAR blue = (bitmap.buffer[index_y*SCREENWIDTH*3 + index_x*3 + 0]) >> 3, green = (bitmap.buffer[index_y*SCREENWIDTH*3 + index_x*3 + 1]) >> 3, red = (bitmap.buffer[index_y*SCREENWIDTH*3 + index_x*3 + 2]) >> 3; (585) : error C2228: left of '.buffer' must have class/struct/union type (586) : error C2228: left of '.buffer' must have class/struct/union type (587) : error C2228: left of '.buffer' must have class/struct/union type the bitmap struct was made outside of a function, if that makes any difference.
the Particle Projection Cannon fires a shimmering blue bolt, much like a cross between lightning and a sine wave that ripples along its path. Edited by - felisandria on February 21, 2002 10:36:08 AM

Share this post


Link to post
Share on other sites
quote:
Original post by Jason Zelos
Have you declared bitmap as a variable ?

IE.

    
BITMAP bitmap;


A struct is just a type definition, used like ''int'' or ''char''.

,Jay

thats what I ment that I did! what''s an API?



the Particle Projection Cannon fires a shimmering blue bolt, much like a cross between lightning and a sine wave that ripples along its path.

Share this post


Link to post
Share on other sites
I think I'm with you, if you are defining blue I would use a macro like :

Blue = RGB (R, G, B)

in directX


if you want to shift bits and combine them, use a bitwise OR (| in C++ I think).

IE:

    
DWORD Colour = ((bitmap.buffer[index_y*SCREENWIDTH*3 + index_x*3 + 0]) >> 16))
| ((bitmap.buffer[index_y*SCREENWIDTH*3 + index_x*3 + 1]) >> 8)
| ((bitmap.buffer[index_y*SCREENWIDTH*3 + index_x*3 + 2]));


Assuming dword is 32 bits (or at least 24) and each call returns and 8 bit value.

eg.

Red = 11111111 >> 16 00000000 00000000 00000000 11111111
Green = 11000000 >> 8 00000000 00000000 11000000 11111111
Blue = 00000011 00000000 00000011 11000000 11111111

,Jay





Edited by - Jason Zelos on February 20, 2002 6:00:19 PM

Share this post


Link to post
Share on other sites
I just saw your other post, this is the line that creates the pixel (16 bit format).

  
USHORT pixel = _RGB16BIT565(red,green,blue);


The reason for the error, as near as I can make out is that you are defining bitmap in Game_Main() as a local variable and not in the function where you have moved your code to. Try copying that across too.


You will need to declare the other vars in the function as well.

,Jay

Share this post


Link to post
Share on other sites
actually that''s a small part of code that''s supposed to copy a bitmap into a directdraw surface. and I didn''t have a problem with it untill I moved it to a nother function.



the Particle Projection Cannon fires a shimmering blue bolt, much like a cross between lightning and a sine wave that ripples along its path.

Share this post


Link to post
Share on other sites
  
int Game_Main()
{
if (iWindowClosed) return(0);

if (KEYDOWN(VK_ESCAPE))
SendMessage(hwnd, WM_DESTROY,0,0);

DDraw_Fill_Surface(lpddsback, erasecolor);


if (FAILED(lpddsback->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL))) return(0);




DDRAW_INIT_STRUCT(ddbltfx);

if (FAILED(lpddsback->Blt(NULL, lpddsmmenu, NULL, DDBLT_WAIT, NULL))) return(0);

if (FAILED(lpddsback->Unlock(NULL))) return(0);

while (FAILED(lpddsprimary->Flip(NULL, DDFLIP_WAIT)));


return(1);

} // end game main


I still don''t see anything in game main that the code would need.



MSVC++ 6.0 intro
DX 8.0a DX SDK 6.1
win98
#define WIN32_LEAN_AND_MEAN
the Particle Projection Cannon fires a shimmering blue bolt, much like a cross between lightning and a sine wave that ripples along its path.

Share this post


Link to post
Share on other sites
quote:
Original post by Jason Zelos
Is the struct definition and the bitmap declaration global in the same module (.cpp file) as the new function. Could you include the code from the void NewFunction (void) { to the end }.

,Jay


yes they are both global and in the same source file. maybe I should just send the entire source file?



MSVC++ 6.0 intro
DX 8.0a DX SDK 6.1
win98
#define WIN32_LEAN_AND_MEAN
the Particle Projection Cannon fires a shimmering blue bolt, much like a cross between lightning and a sine wave that ripples along its path.

Share this post


Link to post
Share on other sites
   
// a work in progress!

//

//


// INCLUDES ///////////////////////////////////////////////


#define WIN32_LEAN_AND_MEAN // say no to MFC


#include <windows.h>
#include <windowsx.h>
#include <stdio.h>
#include <math.h>
#include <mmsystem.h>
#include <stdlib.h>
#include <iostream.h>
#include <conio.h>
#include <malloc.h>
#include <memory.h>
#include <string.h>
#include <stdarg.h>
#include <io.h>
#include <fcntl.h>

#include <ddraw.h>

#include "resourceh.h"
// DEFINES ////////////////////////////////////////////////


// defines for windows


#define WINDOW_CLASS_NAME "WINCLASS1"

#define KEYDOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)

#define SCREENWIDTH 640
#define SCREENHEIGHT 480
#define BITMAP_ID 0x4D42 // universal id for a bitmap


#define MAX_COLORS_PALETTE 256

// basic unsigned types ??????????????

typedef unsigned short USHORT;
typedef unsigned short WORD;
typedef unsigned char UCHAR;
typedef unsigned char BYTE;


typedef struct BITMAP_FILE_TAG
{
BITMAPFILEHEADER bitmapfileheader; // this contains the bitmapfile header

BITMAPINFOHEADER bitmapinfoheader; // this is all the info including the palette

PALETTEENTRY palette[256]; // we will store the palette here

UCHAR *buffer; // this is a pointer to the data


} BITMAP_FILE, *BITMAP_FILE_PTR;

/// macros /////////////////////////////////////////////////


#define DDRAW_INIT_STRUCT(ddstruct) { memset(&ddstruct,0,sizeof(ddstruct)); ddstruct.dwSize=sizeof(ddstruct); }

#define _RGB16BIT565(r,g,b) ((b%32) + ((g%64) << 6) + ((r%32) << 11))

// GLOBALS ////////////////////////////////////////////////


int iWindowClosed = 0;
HWND hwnd;

int erasecolor = ((0) + ((0)<<6) + ((0)<<11));

// Prototypes /////////////////////////////////////////////


int Game_Main();
int Game_Init();
int Game_Shutdown();

int Flip_Bitmap(UCHAR *image, int bytes_per_line, int height);

int Load_Bitmap_File(BITMAP_FILE_PTR bitmap, char *filename);

int Unload_Bitmap_File(BITMAP_FILE_PTR bitmap);

int DDraw_Fill_Surface(LPDIRECTDRAWSURFACE4 lpdds,int color);

// int Copy_Bitmap_Ddsurface(LPDIRECTDRAWSURFACE4 lpdds, BITMAP_FILE_PTR bitmap);

// DirectX stuff //////////////////////////////////////////


LPDIRECTDRAW lpdd = NULL;
LPDIRECTDRAW4 lpdd4 = NULL;
LPDIRECTDRAWSURFACE4 lpddsprimary = NULL;
LPDIRECTDRAWSURFACE4 lpddsback = NULL;
DDSURFACEDESC2 ddsd;
LPDIRECTDRAWPALETTE lpddpal = NULL;
LPDIRECTDRAWCLIPPER lpddclipper = NULL;
PALETTEENTRY palette[256];
PALETTEENTRY save_palette[256];
DDBLTFX ddbltfx;
DDSCAPS2 ddscaps;
HRESULT ddrval;
DWORD start_clock_count = 0;

BITMAP_FILE bitmap;

LPDIRECTDRAWSURFACE4 lpddsmmenu = NULL;
char buffer[80];

//////// message handeling function ///////////////////////////////////////////////


LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
HDC hgdc;
RECT rect;


// what is the message

switch(msg)
{
case WM_CREATE:
{

return(0);
} break;

case WM_PAINT:
{
hgdc = GetDC(hwnd);
ReleaseDC(hwnd,hgdc);
GetClientRect(hwnd,&rect);
ValidateRect(hwnd,&rect);
// return success

return(0);
} break;

case WM_DESTROY:
{
// kill the application, this sends a WM_QUIT message

iWindowClosed = 1;
PostQuitMessage(0);

// return success

return(0);
} break;

default:break;

} // end switch


// process any messages that we didn't take care of

return (DefWindowProc(hwnd, msg, wparam, lparam));

} // end WinProc


// WINMAIN ////////////////////////////////////////////////


int WINAPI WinMain( HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int ncmdshow)
{

WNDCLASSEX winclass; // this will hold the class we create

MSG msg; // generic message


winclass.cbSize = sizeof(WNDCLASSEX);
winclass.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
winclass.lpfnWndProc = WindowProc;
winclass.cbClsExtra = 0;
winclass.cbWndExtra = 0;
winclass.hInstance = hinstance;
winclass.hIcon = LoadIcon(hinstance, MAKEINTRESOURCE(ID_ICON1));
winclass.hCursor = LoadCursor(hinstance, MAKEINTRESOURCE(ID_CURSOR1));
winclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
winclass.lpszMenuName = "MainMenu";
winclass.lpszClassName = WINDOW_CLASS_NAME;
winclass.hIconSm = LoadIcon(hinstance, MAKEINTRESOURCE(ID_ICON1));

// register the window class

if (!RegisterClassEx(&winclass))
return(0);

// create the first window

if (!(hwnd = CreateWindowEx(NULL, // extended style

WINDOW_CLASS_NAME, // class

"Window 1 Based on WINCLASS1", // title

WS_POPUP | WS_VISIBLE,
0,0, // initial x,y

400,400, // initial width, height

NULL, // handle to parent

NULL, // handle to menu

hinstance,// instance of this application

NULL))) // extra creation parms

return(0);

Game_Init();

// enter main event loop, but this time we use PeekMessage()

// instead of GetMessage() to retrieve messages

while(TRUE)
{
// test if there is a message in queue, if so get it

if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
// test if this is a quit

if (msg.message == WM_QUIT)
break;
// translate any accelerator keys

TranslateMessage(&msg);

// send the message to the window proc

DispatchMessage(&msg);
} // end if


if (KEYDOWN(VK_ESCAPE))
{
SendMessage(hwnd, WM_DESTROY,0,0);
}
// main game processing goes here


Game_Main();

} // end while


Game_Shutdown();

// return to Windows like this

return(msg.wParam);

} // end WinMain


////////////////// Game Main ///////////////////////////////////////////////////////////


int Game_Main()
{
if (iWindowClosed) return(0);

if (KEYDOWN(VK_ESCAPE))
SendMessage(hwnd, WM_DESTROY,0,0);

DDraw_Fill_Surface(lpddsback, erasecolor);


if (FAILED(lpddsback->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL))) return(0);


DDRAW_INIT_STRUCT(ddbltfx);

if (FAILED(lpddsback->Blt(NULL, lpddsmmenu, NULL, DDBLT_WAIT, NULL))) return(0);

if (FAILED(lpddsback->Unlock(NULL))) return(0);

while (FAILED(lpddsprimary->Flip(NULL, DDFLIP_WAIT)));


return(1);

} // end game main


/////////////////// Game Init //////////////////////////////////////////////////////////


int Game_Init()
{
if (FAILED(DirectDrawCreate(NULL, &lpdd, NULL))) // get the directdraw interface

return(0);

if (FAILED(lpdd->QueryInterface(IID_IDirectDraw4, (LPVOID *)&lpdd4))) // get interface v4.0

return(0);


lpdd->Release(); // blow the old interface away

lpdd = NULL;

if (FAILED(lpdd4->SetCooperativeLevel(hwnd, DDSCL_FULLSCREEN | DDSCL_ALLOWMODEX | DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT)))
return(0); // set the cooperation level



if (FAILED(lpdd4->SetDisplayMode( SCREENWIDTH, SCREENHEIGHT, 16,0,0)))
return(0); // set the display mode



memset(&ddsd, 0,sizeof(ddsd)); // set the directdraw surface discription struct


ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd.dwBackBufferCount = 1;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;

if (FAILED(lpdd4->CreateSurface(&ddsd, &lpddsprimary, NULL)))
return(0); // creat a dd primary surface with a backbuffer



ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER; // WTF!


if (FAILED(lpddsprimary->GetAttachedSurface(&ddsd.ddsCaps, &lpddsback)))
return(0); // get the backbuffer



if (FAILED(lpdd4->CreateClipper(0, &lpddclipper, NULL)))
return(0); // create a clipper object


RECT ddclprect;
ddclprect.left = 0;
ddclprect.top = 0;
ddclprect.right = SCREENWIDTH-1;
ddclprect.bottom = SCREENHEIGHT-1;

LPRGNDATA region_data;

region_data = (LPRGNDATA)malloc(sizeof(RGNDATAHEADER)+sizeof(RECT));

memcpy( region_data->Buffer, (void *)&ddclprect, sizeof(RECT));

region_data->rdh.dwSize = sizeof(RGNDATAHEADER);
region_data->rdh.iType = RDH_RECTANGLES;
region_data->rdh.nCount = 1;
region_data->rdh.nRgnSize = sizeof(RECT);

region_data->rdh.rcBound.left = 64000;
region_data->rdh.rcBound.top = 64000;
region_data->rdh.rcBound.right = -64000;
region_data->rdh.rcBound.bottom = -64000;

if (FAILED(lpddclipper->SetClipList(region_data, 0)))
{
free(region_data);
return(NULL);
}

if (FAILED(lpddsback->SetClipper(lpddclipper)))
{
free(region_data);
return(NULL);
}

free(region_data);


DDRAW_INIT_STRUCT(ddsd);

ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
ddsd.dwWidth = SCREENWIDTH;
ddsd.dwHeight = SCREENHEIGHT;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;

if (FAILED(lpdd4->CreateSurface(&ddsd, &lpddsmmenu, NULL)))
return(NULL);

if (!Load_Bitmap_File(&bitmap, "MYGAME1.bmp")) return(0);


//if (!Copy_Bitmap_Ddsurface(lpddsmmenu, &bitmap))

//return(NULL);


return(1);
} // end game init


//////////////////// Game Shutdown /////////////////////////////////////////////////////


int Game_Shutdown()
{
if (lpddsback)
{
lpddsback->Release();
lpddsback = NULL;
}

if (lpddsprimary)
{
lpddsprimary->Release();
lpddsprimary = NULL;
}

if (lpdd4)
{
lpdd4->Release();
lpdd4 = NULL;
}
Unload_Bitmap_File(&bitmap);



return(1);
} // end game shutdown


///////////////////////////////////////////////////////////


int Load_Bitmap_File(BITMAP_FILE_PTR bitmap, char *filename)
{
// this function opens a bitmap file and loads the data into bitmap


int file_handle, // the file handle

index; // looping index


UCHAR *temp_buffer = NULL; // used to convert 24 bit images to 16 bit

OFSTRUCT file_data; // the file data information


// open the file if it exists

if ((file_handle = OpenFile(filename,&file_data,OF_READ))==-1)
return(0);

// now load the bitmap file header

_lread(file_handle, &bitmap->bitmapfileheader,sizeof(BITMAPFILEHEADER));

// test if this is a bitmap file

if (bitmap->bitmapfileheader.bfType!=BITMAP_ID)
{
// close the file

_lclose(file_handle);

// return error

return(0);
} // end if


// now we know this is a bitmap, so read in all the sections


// first the bitmap infoheader


// now load the bitmap file header

_lread(file_handle, &bitmap->bitmapinfoheader,sizeof(BITMAPINFOHEADER));

// now load the color palette if there is one

if (bitmap->bitmapinfoheader.biBitCount == 8)
{
_lread(file_handle, &bitmap->palette,MAX_COLORS_PALETTE*sizeof(PALETTEENTRY));

// now set all the flags in the palette correctly and fix the reversed

// BGR RGBQUAD data format

for (index=0; index < MAX_COLORS_PALETTE; index++)
{
// reverse the red and green fields

int temp_color = bitmap->palette[index].peRed;
bitmap->palette[index].peRed = bitmap->palette[index].peBlue;
bitmap->palette[index].peBlue = temp_color;

// always set the flags word to this

bitmap->palette[index].peFlags = PC_NOCOLLAPSE;
} // end for index


} // end if


// finally the image data itself

_lseek(file_handle,-(int)(bitmap->bitmapinfoheader.biSizeImage),SEEK_END);

// now read in the image, if the image is 8 or 16 bit then simply read it

// but if its 24 bit then read it into a temporary area and then convert

// it to a 16 bit image


if (bitmap->bitmapinfoheader.biBitCount==8 || bitmap->bitmapinfoheader.biBitCount==16 ||
bitmap->bitmapinfoheader.biBitCount==24)
{
// delete the last image if there was one

if (bitmap->buffer)
free(bitmap->buffer);

// allocate the memory for the image

if (!(bitmap->buffer = (UCHAR *)malloc(bitmap->bitmapinfoheader.biSizeImage)))
{
// close the file

_lclose(file_handle);

// return error

return(0);
} // end if


// now read it in

_lread(file_handle,bitmap->buffer,bitmap->bitmapinfoheader.biSizeImage);

} // end if

else
{
// serious problem

return(0);

} // end else


#if 0
// write the file info out

printf("\nfilename:%s \nsize=%d \nwidth=%d \nheight=%d \nbitsperpixel=%d \ncolors=%d \nimpcolors=%d",
filename,
bitmap->bitmapinfoheader.biSizeImage,
bitmap->bitmapinfoheader.biWidth,
bitmap->bitmapinfoheader.biHeight,
bitmap->bitmapinfoheader.biBitCount,
bitmap->bitmapinfoheader.biClrUsed,
bitmap->bitmapinfoheader.biClrImportant);
#endif

// close the file

_lclose(file_handle);

// flip the bitmap

Flip_Bitmap(bitmap->buffer,
bitmap->bitmapinfoheader.biWidth*(bitmap->bitmapinfoheader.biBitCount/8),
bitmap->bitmapinfoheader.biHeight);

if (FAILED(lpddsmmenu->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL)))
return(NULL);

// get video pointer to a surfce UCHAR for 8 bit USHORT for 16 bit

USHORT *pddsurface = (USHORT *)ddsd.lpSurface;

// process each line and copy it into the ddsurface

for (int index_y = 0; index_y < SCREENHEIGHT; index_y++)
{
for (int index_x = 0; index_x < SCREENWIDTH; index_x++)
{
// get BGR values, note the scaling down of the channels, so that they

// fit into the 5.6.5 format

UCHAR blue = (bitmap.buffer[index_y*SCREENWIDTH*3 + index_x*3 + 0]) >> 3,
green = (bitmap.buffer[index_y*SCREENWIDTH*3 + index_x*3 + 1]) >> 3,
red = (bitmap.buffer[index_y*SCREENWIDTH*3 + index_x*3 + 2]) >> 3;

// this builds a 16 bit color value in 5.6.5 format (green dominant mode)

USHORT pixel = _RGB16BIT565(red,green,blue);

// write the pixel

pddsurface[index_x + (index_y*ddsd.lPitch >> 1)] = pixel;

} // end for index_x


} // end for index_y


// return success

return(1);

} // end Load_Bitmap_File


///////////////////////////////////////////////////////////


int Unload_Bitmap_File(BITMAP_FILE_PTR bitmap)
{
// this function releases all memory associated with "bitmap"

if (bitmap->buffer)
{
// release memory

free(bitmap->buffer);

// reset pointer

bitmap->buffer = NULL;

} // end if


// return success

return(1);

} // end Unload_Bitmap_File


///////////////////////////////////////////////////////////


int Flip_Bitmap(UCHAR *image, int bytes_per_line, int height)
{
// this function is used to flip bottom-up .BMP images


UCHAR *buffer; // used to perform the image processing

int index; // looping index


// allocate the temporary buffer

if (!(buffer = (UCHAR *)malloc(bytes_per_line*height)))
return(0);

// copy image to work area

memcpy(buffer,image,bytes_per_line*height);

// flip vertically

for (index=0; index < height; index++)
memcpy(&image[((height-1) - index)*bytes_per_line],
&buffer[index*bytes_per_line], bytes_per_line);

// release the memory

free(buffer);

// return success

return(1);

} // end Flip_Bitmap


///////////////////////////////////////////////////////////////


int DDraw_Fill_Surface(LPDIRECTDRAWSURFACE4 lpdds,int color)
{


// clear out the structure and set the size field

DDRAW_INIT_STRUCT(ddbltfx);

// set the dwfillcolor field to the desired color

ddbltfx.dwFillColor = color;

// ready to blt to surface

lpdds->Blt(NULL, // ptr to dest rectangle

NULL, // ptr to source surface, NA

NULL, // ptr to source rectangle, NA

DDBLT_COLORFILL | DDBLT_WAIT, // fill and wait

&ddbltfx); // ptr to DDBLTFX structure


// return success

return(1);
} // end DDraw_Fill_Surface



///////////////////////////////////////////////////////////////

/*
int Copy_Bitmap_Ddsurface(LPDIRECTDRAWSURFACE4 lpdds, BITMAP_FILE_PTR bitmap)
{



return(1);
}
*/





MSVC++ 6.0 intro
DX 8.0a DX SDK 6.1
win98
#define WIN32_LEAN_AND_MEAN
the Particle Projection Cannon fires a shimmering blue bolt, much like a cross between lightning and a sine wave that ripples along its path.

Edited by - PPCThug on February 20, 2002 7:51:57 PM

Share this post


Link to post
Share on other sites
ok the errors disappeared, but all I get is a blank screen? and theres the fact that the code worked as it was(bitmap.buffer) in Game_Main? I''m confused.



MSVC++ 6.0 intro
DX 8.0a DX SDK 6.1
win98
#define WIN32_LEAN_AND_MEAN
the Particle Projection Cannon fires a shimmering blue bolt, much like a cross between lightning and a sine wave that ripples along its path.

Share this post


Link to post
Share on other sites
The code will have worked as it was because ''.'' is a valid option for a type, it just won''t have done what you wanted and propably would have crashed or caused a memory leak.

I can''t say why your code does not display anything caus I can''t see it all from here (try posting the new function in whole).

A good way to check if the problem is your RGB code, is to ''fill'' the surface and blit to the backbuffer.

  
DDBLTFX ddbltfx;

ZeroMemory( &ddbltfx, sizeof(DDBLTFX));
ddbltfx.dwSize = sizeof(DDBLTFX);
ddbltfx.dwFillColor = RGB(255,0,0); //red

pddsBackBuffer->Blt( NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT , &ddbltfx );



Also check out this link for a good explanation :

http://www.gamedev.net/reference/programming/features/gpgenesis6/

You might recognize the site :-)

,Jay

Share this post


Link to post
Share on other sites
it works since I deleted the lock unlock function calls around the blt call!
and as for the struct stuff... I think I need a refresher course.
THANKS FOR ALL THE HELP EVERY ONE!!



MSVC++ 6.0 intro
DX 8.0a DX SDK 6.1
win98
#define WIN32_LEAN_AND_MEAN
the Particle Projection Cannon fires a shimmering blue bolt, much like a cross between lightning and a sine wave that ripples along its path.

Share this post


Link to post
Share on other sites