Hello, my name's Lane Shaw, and this is my first post on a forum. I'm 16 and I use the Bloodshed Dev-C++ compiler to build my programs. The problem I'm having is an app I made to create lightning with OpenGL by plotting a line and shifting the points on it to make it look jagged. I also implemented an image buffer so I can manually edit the image made by OpenGL. It worked, but the image is rendered rather slowly, and I don't kno if it's the timer in the rendering thread or opengl. Here's my code:

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;
}