So who is an expert at making a Windows GUI?

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

Stan Arts
Posts: 179
Joined: Fri Feb 14, 2014 10:53 pm
Location: the Netherlands

Re: So who is an expert at making a Windows GUI?

Post by Stan Arts »

Ed Trice wrote: That sounds like a good solution. Do you have a screenshot of your program? I searched lazily but couldn't find anything but trees :)
Yeah,
http://talkchess.com/forum/viewtopic.ph ... 05&t=62588
though I uploaded new versions to that archive since then and there are now a bunch more options. (Coordinates next to the board, move list, some default timecontrols, black background option, uses about 80MB less RAM, better proportioned pieces etc.)

Some minimal WinAPI and OpenGL code to do this. I use (Free)Pascal but the API and OpenGL calls should be close to identical in any C variant.
Pretty sure it won't get any Windows or OpenGL expert seal of approval but it seems to work.

It creates a dynamic chunk of memory at pointer screen^ that is spixx wide and spixy high starting in the upper left corner. Starting at 0 so you can draw to spixx-1 and spixy-1.
Here a pixel is 4 bytes/32 bit but OpenGL also lets you choose different pixel types such as floating point etc.

Code: Select all

Uses Windows,GL; 
Some global variables.:

Code: Select all

Type screent=array[0..68000000] of longword;  {Ready for ultra mega wide 8K..} 

Var 

screen:^screent;
WindowClass:WndClass;
hWindow:HWnd;
wMessage:Msg;
scrnrect:Rect;
contextw:HDC;
contextgl:HGLRC;
spixx,spixy:longword; 
stopit:byte;
Here I call resize from the startup procedure as well as from the Window procedure so it's separate.

Code: Select all

procedure resize;
begin
 freemem(screen,spixx*spixy*4);
 GetClientRect(hWindow,scrnrect);
 spixx:=scrnrect.right-scrnrect.left;
 spixy:=scrnrect.bottom-scrnrect.top;
 getmem(screen,spixx*spixy*4);

 glViewport(0,0,spixx,spixy);
 glMatrixMode(GL_PROJECTION);glLoadIdentity;
 glOrtho(0,spixx-1,spixy-1,0,-1,1);
 glMatrixMode(GL_MODELVIEW);glLoadIdentity;
 glRasterPos2s(0,0);
end;
The Window procedure.

Code: Select all

function WindowProc(Window:HWnd;AMessage:UINT;WParam:WPARAM;
                    LParam:LPARAM):LRESULT;stdcall;export;
begin
 if AMessage=wm_Destroy then begin PostQuitMessage(0);stopit:=1;end;
 if (AMessage=wm_Sizing)or(AMessage=wm_Size)or(AMessage=wm_Move) then
  resize;
 WindowProc:=DefWindowProc(Window,AMessage,WParam,LParam);
end;
And message pump.

Code: Select all

procedure windowsmessagepump;
begin
 while PeekMessage(@wMessage,0,0,0,PM_REMOVE) do begin
  TranslateMessage(wMessage);DispatchMessage(wMessage);end;
end;
Start. Create a 1024 by 768 window and the OpenGL thing ontop. At the end before doing anything it calls resize then it's ready for action.

Code: Select all

procedure startup;
var PixelFormat:GLuint;
  h_Instance:HINST;
  pfd:TPIXELFORMATDESCRIPTOR;
begin
 stopit:=0;spixx:=1024;spixy:=768;
 getmem(screen,spixx*spixy*4);
 WindowClass.Style:=cs_hRedraw or cs_vRedraw;
 WindowClass.lpfnWndProc:=WndProc(@WindowProc);
 WindowClass.cbClsExtra:=0;
 WindowClass.cbWndExtra:=0;
 WindowClass.hInstance:=system.MainInstance;
 WindowClass.hIcon:=LoadIcon(0,idi_application);
 WindowClass.hCursor:=LoadCursor(0,idc_arrow);
 WindowClass.hbrBackground:=GetStockObject(BLACK_BRUSH);
 WindowClass.lpszMenuName:=nil;
 WindowClass.lpszClassName:='Test';
 if RegisterClass(WindowClass)=0 then exit;
 hWindow:=CreateWindow('Test','Test',ws_OverlappedWindow,cw_UseDefault,
  cw_UseDefault,spixx,spixy,0,0,system.MainInstance,nil);
 if hWindow<>0 then begin
  ShowWindow&#40;hWindow,CmdShow&#41;;ShowWindow&#40;hWindow,SW_SHOW&#41;;
  UpdateWindow&#40;hWindow&#41;;end else exit;
 contextw&#58;=GetDC&#40;hWindow&#41;;

 pfd.nSize&#58;=SizeOf&#40;TPIXELFORMATDESCRIPTOR&#41;;pfd.nVersion&#58;=1;
 pfd.dwFlags&#58;=PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL;
 pfd.iPixelType&#58;=PFD_TYPE_RGBA;
 pfd.cColorBits&#58;=32;pfd.cRedBits&#58;=0;
 pfd.cRedShift&#58;=0;pfd.cGreenBits&#58;=0;
 pfd.cGreenShift&#58;=0;pfd.cBlueBits&#58;=0;
 pfd.cBlueShift&#58;=0;pfd.cAlphaBits&#58;=0;
 pfd.cAlphaShift&#58;=0;pfd.cAccumBits&#58;=0;
 pfd.cAccumRedBits&#58;=0;pfd.cAccumGreenBits&#58;=0;
 pfd.cAccumBlueBits&#58;=0;pfd.cAccumAlphaBits&#58;=0;
 pfd.cDepthBits&#58;=16;pfd.cStencilBits&#58;=0;
 pfd.cAuxBuffers&#58;=0;pfd.iLayerType&#58;=PFD_MAIN_PLANE;
 pfd.bReserved&#58;=0;pfd.dwLayerMask&#58;=0;
 pfd.dwVisibleMask&#58;=0;pfd.dwDamageMask&#58;=0;
 PixelFormat&#58;=ChoosePixelFormat&#40;contextw,@pfd&#41;;
 SetPixelFormat&#40;contextw,PixelFormat,@pfd&#41;;
 contextgl&#58;=wglCreateContext&#40;contextw&#41;;
 wglMakeCurrent&#40;contextw,contextgl&#41;;
 glClearColor&#40;0,0,0,1&#41;;glShadeModel&#40;GL_FLAT&#41;;
 glDepthFunc&#40;GL_ALWAYS&#41;;glDisable&#40;GL_DEPTH_TEST&#41;;
 glPointSize&#40;1&#41;;glLineWidth&#40;1&#41;;glpixelzoom&#40;1,-1&#41;;
 glClear&#40;GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT&#41;;glLoadIdentity;
 resize;
end;

procedure stoppen;
begin 
 freemem&#40;screen,spixx*spixy*4&#41;;
 wglMakeCurrent&#40;contextw,0&#41;;wglDeleteContext&#40;contextgl&#41;;
 ReleaseDC&#40;hWindow,contextw&#41;;DestroyWindow&#40;hWindow&#41;;
end;
Draw the screen buffer to screen and clear it in this case with black. (0)

Code: Select all

procedure drawscrn;
begin
 gldrawpixels&#40;spixx,spixy,GL_RGBA,GL_UNSIGNED_BYTE,@screen^);
 glflush;
 filldword&#40;screen^,spixx*spixy,0&#41;;
end;
And a main part.

Code: Select all

begin
startup; 

repeat

&#123;do and draw something..&#125; 

drawscrn;

Windowsmessagepump;

until stopit=1;

stoppen; 
end. 
Ed Trice
Posts: 100
Joined: Fri Sep 19, 2014 5:03 am

Re: So who is an expert at making a Windows GUI?

Post by Ed Trice »

Stan Arts wrote: Some minimal WinAPI and OpenGL code to do this. I use (Free)Pascal but the API and OpenGL calls should be close to identical in any C variant.
Pretty sure it won't get any Windows or OpenGL expert seal of approval but it seems to work.
Holy Schmoly!

You even draw the digital chess clocks in 3D?? That must have taken a great deal of trial and error to get just right.

I saw in your GL parameters list where you had the x and y dimensions in pixels the parameter to follow was 4. Is that the color depth exponent? Like 2^4 = 16 colors on the palette? Just wondering.

I have 3D-ish graphics going back to the 1996 Macintosh version:

Image

But I'm trying to really make the new version more visually appealing:

Image

Rather than rendering from scratch based on a changeable 3D origin and "view" location as you have done, I'm taking the easy way out. I'll only need to:

1. Create the offscreen graphics buffer
2. Draw my empty board by reading one png file.
3. Determine the rectangular bounds for each checker and King relative to the board's offscreen origin
4. Draw the proper "crown up" or "crown down" orientation of each red/white checker and King.
5. Stamp the offscreen buffer to the main graphics device.

And once I learn how to do steps 1 through 5 above, I can begin coding :)

Thanks for sharing your code. I may need to steal some of your OpenGL code at a later time.
Stan Arts
Posts: 179
Joined: Fri Feb 14, 2014 10:53 pm
Location: the Netherlands

Re: So who is an expert at making a Windows GUI?

Post by Stan Arts »

Nice board! Especially for 1996. What kind of resolution did that run at and do you keep this paper version on your wall as a poster? :)

The new stone looks very realistic and the deep red reminds me of a wax seal.
Ed Trice wrote: I saw in your GL parameters list where you had the x and y dimensions in pixels the parameter to follow was 4. Is that the color depth exponent? Like 2^4 = 16 colors on the palette? Just wondering.


Do you mean the *4 multiplier? That's the 4 bytes per pixel so to reserve memory it needs the resolution *4. It's RGBA so the bytes are Red, Green, Blue and Alpha. I access them as one double word instead of 4 separate bytes which I imagine speeds things up a bit.
In the current orientation say I want to make a pixel blue 100, green 200 and red 200. Alpha is 0. I shift left blue 100 16 bits, green 200 8 bits and add red 200 so the pixel value is 6605000.

From your 1-5 points reading the png file seems the tricky part. But it also seems the internet is rather helpful there so you can just load them into memory and manipulate them however you like. (Much easier than with regular Windows graphics anyway) Note that if the screen or part of it doesn't change you don't need to keep redrawing the screen (like I do in Nemeton) but can cut back on system resources a lot and make it quite light weight.
Ed Trice
Posts: 100
Joined: Fri Sep 19, 2014 5:03 am

Re: So who is an expert at making a Windows GUI?

Post by Ed Trice »

Stan Arts wrote:Nice board! Especially for 1996. What kind of resolution did that run at and do you keep this paper version on your wall as a poster? :)
That was my first software title I got published on both the Mac and PC. I printed that out on a Textronix color laser, I forget the model number, but it was a CMYK solid-ink printer, like laser wax almost. Every printout was shiny. I recently found it, couldn't believe it, 21-year old printout next to my original patent application for what eventually became US 6,481,716.
Ed Trice wrote: I saw in your GL parameters list where you had the x and y dimensions in pixels the parameter to follow was 4. Is that the color depth exponent? Like 2^4 = 16 colors on the palette? Just wondering.

Stan Arts wrote: Do you mean the *4 multiplier? That's the 4 bytes per pixel so to reserve memory it needs the resolution *4.
Ah, thanks. Encoding the data for shift operations, I'm used to that :)
Stan Arts wrote: From your 1-5 points reading the png file seems the tricky part.
From what little I know at present, there's an API call to read .png files into a RAM buffer that's pretty straightforward. The "hard part," as I understand it, will be taking the 600 dpi resolution, finding the "correct constant" in the sea of Microsoft constants that will allow for scaling it down with maximum retention of detail, setting up the 2015 equivalent of BitBlt(...), computing the destination rectangle for the offscreen board, then transferring the image like an old school "iron on" decal. I do this for each piece, then I BitBlt(...) the offscreen image to the main monitor to get a nice flicker-free update.

The only problem is, Microsoft stoped documenting this stuff, and there's no good single volume reference around anywhere.
mar
Posts: 2554
Joined: Fri Nov 26, 2010 2:00 pm
Location: Czech Republic
Full name: Martin Sedlak

Re: So who is an expert at making a Windows GUI?

Post by mar »

Stan Arts wrote:From your 1-5 points reading the png file seems the tricky part.
Not at all, Sean Barrett and his header-only public domain stb_image.h solves the problem easily. https://github.com/nothings/stb