Code:
typedef HANDLE THREAD;
typedef bool (*RENDERPROC)(void);
typedef void (*INITSCENE)(void);
typedef struct _rend_dat {
HWND parHwnd;
THREAD Thr;
PIMGBUFFER Image;
HDC MemDC;
HGLRC MemRC;
HANDLE Timer;
INITSCENE Init;
RENDERPROC Render;
INITSCENE UnInit;
UINT16 Width;
UINT16 Height;
UINT32 Flags;
ULONG ID;
} THR_REND_DATA, *PTHR_REND_DATA, *PPTHR_REND_DATA;
#define WM_RENDERR (WM_USER+1)
#define WM_RENDDONE (WM_USER+2)
#define WM_RENDVIEW (WM_USER+3)
#define ERROR_NO_RENDER_FUNC 0x00
#define ERROR_IMAGE_BUFFER 0x01
#define ERROR_WINDOW_DC 0x02
#define ERROR_MEMORY_DC 0x03
#define ERROR_MEMDC_SETUP 0x04
#define ERROR_GL_CONTEXT 0x05
#define ERROR_GLCONTEXT_SETUP 0x06
#define ERROR_TIMER 0x07
#define FLAG_THREAD 0x01
#define FLAG_RESIZE 0x02
#define FLAG_RENDER 0x04
#define FLAG_ERROR 0x08
bool SetUpDC(HDC hDC){
PIXELFORMATDESCRIPTOR pix;
MClr(&pix,sizeof(pix));
pix.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pix.nVersion = 1;
pix.dwFlags = PFD_DRAW_TO_BITMAP|PFD_SUPPORT_OPENGL|PFD_SUPPORT_GDI;
pix.iPixelType = PFD_TYPE_RGBA;
pix.cColorBits = 32;
pix.cDepthBits = 16;
pix.iLayerType = PFD_MAIN_PLANE;
int iFor = ChoosePixelFormat(hDC,&pix);
if(!iFor) return false;
DescribePixelFormat(hDC,iFor,sizeof(pix),&pix);
return SetPixelFormat(hDC,iFor,&pix);
}
ULONG WINAPI RenderThr(PTHR_REND_DATA ThrData){
if(!ThrData){
ExitThread(ERROR_INVALID_PARAMETER);
return 1;
}
if(!ThrData->parHwnd){
ExitThread(ERROR_INVALID_PARAMETER);
return 1;
}
if(!ThrData->Render){
PostMessage(ThrData->parHwnd,WM_RENDERR,ERROR_NO_RENDER_FUNC,ERROR_INVALID_PARAMETER);
ExitThread(ERROR_INVALID_PARAMETER);
return 1;
}
ThrData->Image = NewImageBuffer(ThrData->Width,ThrData->Height);
if(!ThrData->Image){
PostMessage(ThrData->parHwnd,WM_RENDERR,ERROR_IMAGE_BUFFER,GetLastError());
ExitThread(ERROR_SUCCESS);
return 0;
}
register HDC hDC = GetDC(ThrData->parHwnd);
if(!hDC){
PostMessage(ThrData->parHwnd,WM_RENDERR,ERROR_WINDOW_DC,GetLastError());
ExitThread(ERROR_SUCCESS);
return 0;
}
ThrData->MemDC = CreateCompatibleDC(hDC);
if(!ThrData->MemDC){
ReleaseDC(ThrData->parHwnd,hDC);
PostMessage(ThrData->parHwnd,WM_RENDERR,ERROR_MEMORY_DC,GetLastError());
ExitThread(ERROR_SUCCESS);
return 0;
}
ReleaseDC(ThrData->parHwnd,hDC);
HBITMAP OldBit = SelectObject(ThrData->MemDC,ThrData->Image->Bitmap);
if(!SetUpDC(ThrData->MemDC)){
PostMessage(ThrData->parHwnd,WM_RENDERR,ERROR_MEMDC_SETUP,GetLastError());
ExitThread(ERROR_SUCCESS);
return 0;
}
ThrData->MemRC = wglCreateContext(ThrData->MemDC);
if(!ThrData->MemRC){
PostMessage(ThrData->parHwnd,WM_RENDERR,ERROR_GL_CONTEXT,GetLastError());
ExitThread(ERROR_SUCCESS);
return 0;
}
if(!wglMakeCurrent(ThrData->MemDC,ThrData->MemRC)){
PostMessage(ThrData->parHwnd,WM_RENDERR,ERROR_GLCONTEXT_SETUP,GetLastError());
ExitThread(ERROR_SUCCESS);
return 0;
}
LARGE_INTEGER Due;
MClr(&Due,sizeof(Due));
Due.QuadPart = -166666;
ThrData->Timer = CreateWaitableTimer(NULL,TRUE,NULL);
if(!ThrData->Timer){
PostMessage(ThrData->parHwnd,WM_RENDERR,ERROR_TIMER,GetLastError());
ExitThread(ERROR_SUCCESS);
return 0;
}
if(ThrData->Init!=NULL) ThrData->Init();
while(ThrData->Flags & FLAG_THREAD){
if(ThrData->Flags & FLAG_RESIZE){
SelectObject(ThrData->MemDC,OldBit);
ResizeImageBuffer(&ThrData->Image,ThrData->Width,ThrData->Height);
OldBit = SelectObject(ThrData->MemDC,ThrData->Image->Bitmap);
wglMakeCurrent(ThrData->MemDC,ThrData->MemRC);
glViewport(0,0,ThrData->Width,ThrData->Height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60,(float)ThrData->Width/(float)ThrData->Height,0.1,100.0);
glTranslated(0.0,0.0,-2.75);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
ThrData->Flags &= ~FLAG_RESIZE;
}
if(ThrData->Flags & FLAG_RENDER){
SetWaitableTimer(ThrData->Timer,&Due,0,NULL,NULL,0);
bool update = ThrData->Render();
glFlush();
if(update) PostMessage(ThrData->parHwnd,WM_RENDVIEW,0,0);
WaitForSingleObject(ThrData->Timer,INFINITE);
}else{
SetWaitableTimer(ThrData->Timer,&Due,0,NULL,NULL,0);
WaitForSingleObject(ThrData->Timer,INFINITE);
}
}
if(ThrData->UnInit!=NULL) ThrData->UnInit();
CloseHandle(ThrData->Timer);
ThrData->Timer = NULL;
wglMakeCurrent(NULL,NULL);
wglDeleteContext(ThrData->MemRC);
ThrData->MemRC = NULL;
DeleteDC(ThrData->MemDC);
ThrData->MemDC = NULL;
DeleteImageBuffer(&ThrData->Image);
PostMessage(ThrData->parHwnd,WM_RENDDONE,0,0);
ExitThread(ERROR_SUCCESS);
return 0;
}
bool CreateRendThread(PTHR_REND_DATA Data){
if(!Data){
SetLastError(ERROR_INVALID_PARAMETER);
return false;
}
Data->Thr = CreateThread(NULL,2048,(LPTHREAD_START_ROUTINE)RenderThr,(PVOID)Data,0,&Data->ID);
if(!Data->Thr) return false;
return true;
}
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
UCHAR8 err[512];
UINT64 GetScreenRes(){
register UINT64 Res = 0;
Res = GetSystemMetrics(SM_CXSCREEN);
Res <<= 32;
Res |= GetSystemMetrics(SM_CYSCREEN);
return Res;
}
#define HIDWORD(Q) ((Q & 0xFFFFFFFF00000000uLL)>>32)
#define LODWORD(Q) (Q & 0xFFFFFFFF)
void RenderLightning(UINT8 Seg,double zapFact,double x1,double y1,double z1,double x2,double y2,double z2){
double subX = (x2-x1)/(double)Seg,
subY = (y2-y1)/(double)Seg,
subZ = (z2-z1)/(double)Seg,
x,y,z,xVar,yVar,zVar,xPrev,yPrev,zPrev;
UINT8 i;
srand(time(0));
xPrev = x1;
yPrev = y1;
zPrev = z1;
for(i=1;i<Seg;i++){
xVar = (double)rand()/((double)RAND_MAX+1)/(double)Seg*zapFact;
yVar = (double)rand()/((double)RAND_MAX+1)/(double)Seg*zapFact;
zVar = (double)rand()/((double)RAND_MAX+1)/(double)Seg*zapFact;
if(rand()%2) xVar = -xVar;
if(rand()%2) yVar = -yVar;
if(rand()%2) zVar = -zVar;
x = x1+(double)i*subX+xVar;
y = y1+(double)i*subY+yVar;
z = z1+(double)i*subZ+zVar;
glBegin(GL_LINES);
glVertex3d(xPrev,yPrev,zPrev);
glVertex3d(x,y,z);
glEnd();
xPrev = x;
yPrev = y;
zPrev = z;
}
glBegin(GL_LINES);
glVertex3d(xPrev,yPrev,zPrev);
glVertex3d(x2,y2,z2);
glEnd();
return;
}
char szClassName[ ] = "WhiteLightning";
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nFunsterStil)
{
HWND hwnd;
MSG messages;
WNDCLASSEX wincl;
MClr(err,sizeof(err));
wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure;
wincl.style = CS_DBLCLKS;
wincl.cbSize = sizeof (WNDCLASSEX);
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL;
wincl.cbClsExtra = 0;
wincl.cbWndExtra = 0;
wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
if (!RegisterClassEx (&wincl)) return 0;
register UINT64 Resolution = GetScreenRes();
hwnd = CreateWindowEx (
0,
szClassName,
"Lightning",
WS_OVERLAPPEDWINDOW,
HIDWORD(Resolution)/8,
LODWORD(Resolution)/8,
HIDWORD(Resolution)*0.75,
LODWORD(Resolution)*0.75,
HWND_DESKTOP,
NULL,
hThisInstance,
NULL);
ShowWindow (hwnd, nFunsterStil);
while (GetMessage (&messages, NULL, 0, 0))
{
TranslateMessage(&messages);
DispatchMessage(&messages);
}
return messages.wParam;
}
void InitScene(void){
glEnable(GL_DEPTH_TEST);
glLineWidth(1.0);
return;
}
bool RenderScene(void){
glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
RenderLightning(25,5.0,-2.0,2.0,-2.0,0.0,-1.0,-0.5);
return true;
}
void UnInitScene(void){
glDisable(GL_DEPTH_TEST);
return;
}
HGLRC glDisp = NULL;
HDC Display = NULL;
PIMGBUFFER Image = NULL;
UINT Timer = 0;
THR_REND_DATA ThrDat = {NULL,NULL,NULL,NULL,NULL,NULL,0,0,0,0};
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) /* handle the messages */
{
case WM_GETMINMAXINFO: ;
((PMINMAXINFO)lParam)->ptMinTrackSize.x = 200;
((PMINMAXINFO)lParam)->ptMinTrackSize.y = 200;
break;
case WM_RENDVIEW: ;
InvalidateRect(hwnd,NULL,FALSE);
break;
case WM_PAINT: ;
ThrDat.Flags &= ~FLAG_RENDER;
PAINTSTRUCT ps;
HDC hDC = BeginPaint(hwnd,&ps);
BitBlt(hDC,0,0,ThrDat.Width,ThrDat.Height,ThrDat.MemDC,0,0,SRCCOPY);
EndPaint(hwnd,&ps);
ThrDat.Flags |= FLAG_RENDER;
break;
case WM_SIZE: ;
ThrDat.Width = LOWORD(lParam);
ThrDat.Height = HIWORD(lParam);
ThrDat.Flags |= FLAG_RESIZE;
break;
case WM_CREATE: ;
ThrDat.parHwnd = hwnd;
ThrDat.Width = ((LPCREATESTRUCT)lParam)->cx;
ThrDat.Height = ((LPCREATESTRUCT)lParam)->cy;
ThrDat.Init = InitScene;
ThrDat.Render = RenderScene;
ThrDat.UnInit = UnInitScene;
ThrDat.Flags |= FLAG_THREAD|FLAG_RENDER;
CreateRendThread(&ThrDat);
break;
case WM_RENDERR: ;
register PUCHAR8 Error = NULL;
switch(wParam){
case ERROR_IMAGE_BUFFER: ;
Error = "Image Buffer Error: %u";
break;
case ERROR_WINDOW_DC: ;
Error = "Window Device Context Error: %u";
break;
case ERROR_MEMORY_DC: ;
Error = "Memory Context Creation Error: %u";
break;
case ERROR_MEMDC_SETUP: ;
Error = "Memory Context Setup Error: %u";
break;
case ERROR_GL_CONTEXT: ;
Error = "OpenGL Context Creation Error: %u";
break;
case ERROR_GLCONTEXT_SETUP: ;
Error = "OpenGL Context Setup Error: %u";
break;
}
if(wParam>ERROR_IMAGE_BUFFER){
DeleteImageBuffer(&ThrDat.Image);
ThrDat.Image = NULL;
}
if(wParam>ERROR_MEMORY_DC){
DeleteDC(ThrDat.MemDC);
ThrDat.MemDC = NULL;
}
if(wParam>ERROR_GL_CONTEXT){
wglDeleteContext(ThrDat.MemRC);
ThrDat.MemRC = NULL;
}
ThrDat.Flags |= FLAG_ERROR;
sprintf(err,Error,lParam);
ErrorBox(hwnd,err);
break;
case WM_CLOSE: ;
if(ThrDat.Flags & FLAG_ERROR) PostMessage(hwnd,WM_RENDDONE,0,0);
ThrDat.Flags &= ~FLAG_THREAD;
break;
case WM_RENDDONE: ;
CloseHandle(ThrDat.Thr);
PostQuitMessage(0);
break;
default: ;
return DefWindowProc (hwnd, message, wParam, lParam);
}
return ERROR_SUCCESS;
}