Well, I've been messing around with the stuff Jim linked to and I'm getting along with it a lot better this time. Is it ok to do stuff like this:
#define VC_EXTRALEAN
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <math.h>
typedef struct
{
int wwidth,height,bpp;
unsigned int* argb;
}image_buffer;
typedef struct
{
HWND window;
image_buffer* buffer;
}window_struct;
image_buffer* create_image_buffer(int wwidth, int height)
{
image_buffer* buffer=(image_buffer*)malloc(sizeof (image_buffer));
buffer->wwidth=wwidth;
buffer->height=height;
buffer->argb=(unsigned int*)malloc(sizeof(unsigned int)*wwidth*height);
buffer->bpp=32;
return buffer;
}
void flip(window_struct* window)
{
BITMAPINFO bmi;
HDC hdc;
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = window->buffer->wwidth;
bmi.bmiHeader.biHeight = -window->buffer->height;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = window->buffer->bpp;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = 0;
bmi.bmiHeader.biXPelsPerMeter = 75;
bmi.bmiHeader.biYPelsPerMeter = 75;
bmi.bmiHeader.biClrUsed = 0;
bmi.bmiHeader.biClrImportant = 0;
hdc = GetDC(window->window);
SetDIBitsToDevice(hdc, 0,0, window->buffer->wwidth,window->buffer->height, 0,0, 0,window->buffer->height, window->buffer->argb, &bmi, DIB_RGB_COLORS);
ReleaseDC(window->window, hdc);
}
void setpixel(image_buffer* buffer,int x, int y, unsigned int colour)
{
if (x < 0 || x >= buffer->wwidth) return;
if (y < 0 || y >= buffer->height) return;
*(buffer->argb+x+buffer->wwidth*y)=colour;
}
unsigned int getpixel(image_buffer* buffer,int x, int y)
{
if (x < 0 || x >= buffer->wwidth) return 0;
if (y < 0 || y >= buffer->height) return 0;
return *(buffer->argb+x+buffer->wwidth*y);
}
void clear_buffer(image_buffer* buffer,unsigned int colour)
{
memset(buffer->argb, colour, buffer->wwidth*buffer->height*sizeof(int));
}
void shutdown(window_struct* window)
{
free(window->buffer->argb);
free(window->buffer);
free(window);
}
void init_fireworks(void);
void do_fireworks(image_buffer*);
void draw_fireworks(image_buffer*);
void do_graphics_stuff(window_struct* window)
{
clear_buffer(window->buffer,0);
do_fireworks(window->buffer);
InvalidateRect(window->window, NULL, FALSE);
UpdateWindow(window->window);
flip(window);
Sleep(16);
}
int quit = FALSE;
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_PAINT:
{
PAINTSTRUCT paint={0};
paint.hdc = (HDC)wParam;
GetUpdateRect(hwnd, &paint.rcPaint,TRUE);
BeginPaint(hwnd, &paint);
EndPaint(hwnd, &paint);
break;
}
case WM_DESTROY:
quit = TRUE;
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
window_struct* setup_window(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow,
int wwidth,
int height,
TCHAR title[])
{
WNDCLASSEX clas;
MSG msg;
TCHAR graphics_class[] = "SM3d";
clas.cbSize = sizeof(WNDCLASSEX);
clas.style = CS_HREDRAW | CS_VREDRAW;
clas.lpfnWndProc = WindowProc;
clas.cbClsExtra = 0;
clas.cbWndExtra = 0;
clas.hInstance = hInstance;
clas.hIcon = NULL;
clas.hCursor = NULL;
clas.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
clas.lpszMenuName = NULL;
clas.lpszClassName = graphics_class;
clas.hIconSm = 0;
RegisterClassEx(&clas);
window_struct* new_window=(window_struct*)malloc(sizeof(window_struct));
{
RECT rect={0,0,wwidth,height};
int style = WS_SYSMENU|WS_MINIMIZEBOX|WS_VISIBLE;
AdjustWindowRectEx(&rect, style, FALSE, WS_EX_TOPMOST);
new_window->window = CreateWindowEx(0, graphics_class, title, style, CW_USEDEFAULT, CW_USEDEFAULT, rect.right-rect.left, rect.bottom-rect.top, NULL, NULL, hInstance, 0);
}
ShowWindow(new_window->window, nCmdShow);
UpdateWindow(new_window->window);
new_window->buffer=create_image_buffer(wwidth,height);
return new_window;
}
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
window_struct* window=setup_window(hInstance,hPrevInstance,lpCmdLine,nCmdShow,640,480,"Stonemonkey");
init_fireworks();
while (!quit)
{
while (PeekMessage(&msg, window->window, 0, 0, PM_NOREMOVE))
{
if (!GetMessage(&msg, window->window, 0, 0))
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
do_graphics_stuff(window);
}
shutdown(window);
return 0;
}
typedef struct
{
float x,y,z;
} VECTOR;
typedef struct
{
unsigned int flags;
VECTOR posn;
VECTOR velocity;
float spin;
float spin_rate;
float life_span;
int age;
} COIN;
enum
{
COIN_ALIVE_F=1,
COIN_PARENT_F=2,
};
#define MAX_COINS 5000
#define MAX_GEN 500
COIN fireworks[MAX_COINS];
#define BIG_G -9.81f
int my_rand()
{
return rand()+(rand()<<15);
}
float rand_angle()
{
return (float)(my_rand()%360);
}
float rand_vel()
{
return (float)((my_rand()%201)-100);
}
float rand_yvel()
{
return (float)(my_rand()%750)-BIG_G;
}
float rand_rate()
{
return (float)((my_rand()%45)-23);
}
float rand_lifespan()
{
return (float)((my_rand()%3)+1);
}
void create_a_coin(COIN *coin, int always_alive)
{
if (always_alive)
coin->flags = COIN_ALIVE_F;
else
coin->flags = my_rand()&COIN_ALIVE_F;
if (coin->flags & COIN_ALIVE_F)
{
coin->posn.x = 320.0f;
coin->posn.y = 0.0f;
coin->posn.z = 0.0f;
coin->spin = rand_angle();
coin->spin_rate = rand_rate();
coin->velocity.x = rand_vel();
coin->velocity.z = rand_vel();
coin->velocity.y = rand_yvel();
coin->life_span = rand_lifespan();
coin->age = 0;
if ((my_rand()%10)==0)
coin->flags |= COIN_PARENT_F;
}
return;
}
void create_a_system(VECTOR *pos, int age)
{
int amount = 1+(my_rand()%MAX_GEN);
COIN *coin = fireworks;
int x;
age++;
for (x = 0; x < MAX_COINS && amount; x++, coin++)
{
if (!(coin->flags & COIN_ALIVE_F))
{
create_a_coin(coin, TRUE);
coin->posn.x = pos->x;
coin->posn.y = pos->y;
coin->posn.z = pos->z;
coin->velocity.x = rand_vel();
coin->velocity.z = rand_vel();
coin->velocity.y = rand_yvel()/(float)(age+1);
coin->life_span/=(float)(age+1);
coin->age = age;
amount--;
}
}
}
void init_fireworks()
{
int x;
COIN *coin = fireworks;
srand(time(NULL));
for (x = 0; x < MAX_GEN; x++, coin++)
{
create_a_coin(coin, FALSE);
}
for (x = MAX_GEN, coin = fireworks+MAX_GEN; x < MAX_COINS; x++, coin++)
coin->flags = 0;
return;
}
void process_fireworks(float elapsed_time)
{
int x;
COIN *coin = fireworks;
elapsed_time /= 1000.0f;
for (x = 0; x < MAX_COINS; x++, coin++)
{
if (coin->flags & COIN_ALIVE_F)
{
coin->spin += coin->spin_rate;
coin->posn.x += coin->velocity.x * elapsed_time;
coin->posn.y += coin->velocity.y * elapsed_time;
coin->posn.z += coin->velocity.z * elapsed_time;
coin->velocity.y += BIG_G;
coin->life_span -= elapsed_time;
if (coin->life_span < 0.0f)
{
if ((coin->flags & COIN_PARENT_F) && coin->age < 5)
{
create_a_system(&coin->posn, coin->age);
coin->flags &= ~COIN_ALIVE_F;
}
else
{
coin->flags &= ~COIN_ALIVE_F;
//create_a_coin(coin, TRUE);
}
}
if (coin->posn.y < 0.0f)
coin->flags &= ~COIN_ALIVE_F;
}
}
return;
}
int get_blit_size(float z)
{
z += 320.0;
return (int)(64.0f*z/640.0f);
}
void draw_fireworks(image_buffer* buffer)
{
int x;
COIN *coin = fireworks;
int population = 0;
for (x = 0; x < MAX_COINS; x++, coin++)
{
if (coin->flags & COIN_ALIVE_F)
{
setpixel(buffer,(int)coin->posn.x, 400-(int)coin->posn.y+1, 0x00ff00);
population++;
}
}
if (!population) init_fireworks();
return;
}
void do_fireworks(image_buffer* buffer)
{
process_fireworks(1000.0f/60.0f);
draw_fireworks(buffer);
}