unit MainUnit;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ComCtrls, ToolWin, Menus, StdCtrls, ExtCtrls, LIbV, OpenGL, Tabs;

type
  TMainForm = class(TForm)
    ToolBar: TToolBar;
    menuWinOps: TPopupMenu;
    CreateItem: TMenuItem;
    DestroyItem: TMenuItem;
    btnWinOps: TToolButton;
    MainMenu: TMainMenu;
    FileMenu: TMenuItem;
    ExitItem: TMenuItem;
    StatusBar: TStatusBar;
    Panel: TPanel;
    Splitter: TSplitter;
    PageControl1: TPageControl;
    TabSheet1: TTabSheet;
    TabSheet2: TTabSheet;
    TabSheet3: TTabSheet;
    Panel1: TPanel;
    PaintBox1: TPaintBox;
    Splitter1: TSplitter;
    PaintBox2: TPaintBox;
    procedure OnResize(Sender: TObject);
    procedure CreateItemClick(Sender: TObject);
    procedure DestroyItemClick(Sender: TObject);
    procedure ExitItemClick(Sender: TObject);
    procedure FormShow(Sender: TObject);
  private
	GlWindow 	: array[0..1] of glw_t;
    IndBeforeMenuLoop : glw_t;
    MenuLoop	: Boolean;
	function	GetNextEvent(var event:input_record_t;var From:glw_t):Boolean;
	procedure	DispatchInputEvents;

    procedure	OnEnterMenuLoop(var Msg:TMsg);message WM_ENTERMENULOOP;
    procedure	OnExitMenuLoop(var Msg:TMsg);message WM_EXITMENULOOP;
  	//procedure	OnGlNotification(var Msg:TMsg);message gl_msg_notification;
    function	GetGLLeft(ind:integer):integer;
    function	GetGLTop(ind:integer):integer;
    function	GetGLWidth(ind:integer):integer;
    function	GetGLHeight(ind:integer):integer;
    procedure	OnIdle(Sender: TObject;var Done:Boolean);
  public
	procedure GLMouseMove(X, Y: Integer);
	procedure GLKeyDown(code, ch: Integer);
	procedure GLKeyUp(code, ch: Integer);
  end;

var
  MainForm: TMainForm;

implementation

{$R *.DFM}

procedure	TMainForm.OnEnterMenuLoop(var Msg:TMsg);
begin
    IndBeforeMenuLoop:=vglGetCurrentWindow;
    MenuLoop:=True;
    if IndBeforeMenuLoop <> nil then
    begin
      vglMakeCurrent(nil);
    end;
end;

procedure	TMainForm.OnExitMenuLoop(var Msg:TMsg);
begin
    MenuLoop:=False;
    if IndBeforeMenuLoop <> nil then
    begin
		  vglMakeCurrent(IndBeforeMenuLoop);
      vglSetFocus();
    end;
end;

function	TMainForm.GetGLLeft;
begin
	case ind of
    	0:	Result:=PaintBox1.Left;
        1:	Result:=PaintBox2.Left;
        else	Result:=0;
    end;
end;

function	TMainForm.GetGLTop;
begin
	case ind of
    	0:	Result:=PaintBox1.Top;
        1:	Result:=PaintBox2.Top;
        else	Result:=0;
    end;
end;

function	TMainForm.GetGLWidth;
begin
	case ind of
    	0:	Result:=PaintBox1.Width;
        1:	Result:=PaintBox2.Width;
        else	Result:=128;
    end;
end;

function	TMainForm.GetGLHeight;
begin
	case ind of
    	0:	Result:=PaintBox1.Height;
        1:	Result:=PaintBox2.Height;
        else	Result:=128;
    end;
end;

(*
procedure	TMainForm.OnGlNotification(var Msg:TMsg);
begin
	DispatchMessages;
end;
*)

function
TMainForm.GetNextEvent(var event:input_record_t;var From:glw_t):Boolean;
var
	i : integer;
begin
	for i:=0 to 1 do
  begin
    if GlWindow[i]=nil then
      continue;
    vglMakeCurrent(GlWindow[i]);
    if vglPending then
    begin
      vglNextEvent(event);
      From:=GlWindow[i];
      Result:=True;
      Exit;
    end;
  end;
  Result:=False;
end;

procedure	TMainForm.DispatchInputEvents;
var
	ev	: input_record_t;
	ind	: integer;
  win	: glw_t;
begin
	while GetNextEvent(ev,win) do
	begin
    case ev.event of
      ev_os_dependent:
      begin
        case ev.first_code of
          WM_SIZE,WM_MOVE:
          begin
            for ind:=0 to 1 do
            begin
              if GlWindow[ind]=nil then
                continue;
              vglMakeCurrent(GlWindow[ind]);
              glViewport(0,0,GetGLWidth(ind),GetGLHeight(ind));
            end;
          end;
        end;
      end;
      ev_mouse_move:
        GLMouseMove(ev.first_code,ev.second_code);
      ev_key_down:
        GLKeyDown(ev.first_code,ev.second_code);
      ev_key_up:
        GLKeyUp(ev.first_code,ev.second_code);
      end;
  end;
end;

procedure TMainForm.ExitItemClick(Sender: TObject);
begin
	DestroyItemClick(nil);
	Close;
end;

procedure TMainForm.OnResize(Sender: TObject);
var
	i : integer;
begin
	for i:=0 to 1 do
		if GlWindow[i] <> nil then
		begin
      vglMakeCurrent(GlWindow[i]);
			vglMoveWindow(GetGLLeft(i),GetGLTop(i));
			vglResizeWindow(GetGLWidth(i),GetGLHeight(i));
		end;
end;

procedure TMainForm.CreateItemClick(Sender: TObject);
var
	ind 	: integer;
  parent	: HWND;
begin
	ind:=0;
  while ind<2 do
  begin
    if GlWindow[ind]=nil then
      Break;
    ind:=ind+1;
  end;
  if ind=2 then
  begin
    ShowMessage('Both windows already exists.');
    Exit;
  end;
  parent:=Panel1.Handle;
  GlWindow[ind]:=vglCreateChildWindow('Place for graph ...',
    GetGLLeft(ind),GetGLTop(ind),
    GetGLWidth(ind),GetGLHeight(ind),
    parent);
  glViewport(0,0,GetGLWidth(ind),GetGLHeight(ind));
end;

procedure TMainForm.DestroyItemClick(Sender: TObject);
var
	ind 	: integer;
  win		: glw_t;
begin
	ind:=0;
  while ind<2 do
  begin
    if GlWindow[ind]<>nil then
      Break;
    ind:=ind+1;
  end;
  if ind=2 then
  begin
    // ShowMessage('Nothing to destroy.');
    Exit;
  end;
  win:=GlWindow[ind];
  GlWindow[ind]:=nil;
  vglDestroyWindow(win);
  win:=GlWindow[(ind+1) mod 2];
  if win <> nil then
  begin
    vglMakeCurrent(win);
    vglSetFocus();
  end;
end;

procedure TMainForm.GLKeyDown(code, ch: Integer);
begin
	StatusBar.Panels[0].Text:='KeyDown';
	StatusBar.Panels[1].Text:=string(keycodeGetName(code));
    if ch<>0 then
		StatusBar.Panels[2].Text:=chr(ch)
    else
		StatusBar.Panels[2].Text:='[unprintable]';
end;

procedure TMainForm.GLKeyUp(code, ch: Integer);
begin
	StatusBar.Panels[0].Text:='KeyUp';
	StatusBar.Panels[1].Text:=string(keycodeGetName(code));
    if ch<>0 then
		StatusBar.Panels[2].Text:=chr(ch)
    else
		StatusBar.Panels[2].Text:='[unprintable]';
end;

procedure TMainForm.GLMouseMove(X, Y: Integer);
begin
	StatusBar.Panels[0].Text:='MouseMove';
	StatusBar.Panels[1].Text:=IntToStr(X);
	StatusBar.Panels[2].Text:=IntToStr(Y);
end;

var
	a, b : vec_t;

procedure	Draw(Bounds:TPaintbox;dc:HDC;br:HBRUSH;orgx,orgy:integer);
var
	rgb : vec3_t;
begin
    if br <> 0 then
    begin
      SelectObject(dc,br);
      SetBrushOrgEx(dc,orgx,orgy,nil);
	    PatBlt(dc,Bounds.Left,Bounds.Top,
        Bounds.Width,Bounds.Height,PATCOPY);
      Exit;
    end;
    glClearColor(0,0,0,0);
    glClearDepth(1);
    glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity;
    glOrtho(0,1,0,1,-1,1);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity;
	a:=a+ANGLE_5;
	b:=b+ANGLE_10;
    rgb[0]:=0.5+0.5*sin(a);
	rgb[1]:=0.5+0.5*cos(a);
	rgb[2]:=0.5+0.5*cos(b);
	glBegin(GL_QUADS);
		glColor3f(rgb[0],rgb[1],rgb[2]);
        glVertex2f(0.1,0.1);
		glColor3f(rgb[2],rgb[1],rgb[0]);
        glVertex2f(0.9,0.1);
		glColor3f(rgb[1],rgb[2],rgb[0]);
        glVertex2f(0.9,0.9);
		glColor3f(1-rgb[2],1-rgb[1],1-rgb[0]);
        glVertex2f(0.1,0.9);
	glEnd;
    vglSwapBuffers;
end;

var
	br : HBRUSH;
	x,y : integer;
    w,h : u32_t;

var
	prev_update_time : integer;

procedure TMainForm.OnIdle;
var
    dc  : HDC;
    time : integer;
    win : glw_t;
begin
    Done:=MenuLoop;
    if Done then
    	Exit;
    DispatchInputEvents;
	win:=vglGetCurrentWindow;
    if ((GlWindow[0] = nil) and (GlWindow[1] = nil)) or (win = nil) then
    begin
    	dc:=GetDC(Panel1.Handle);
        Draw(PaintBox1,dc,br,x,y);
        Draw(PaintBox2,dc,br,127-x,y);
        x:=(x+1) mod w;
        // y:=(y+1) mod h;
    	ReleaseDC(Panel1.Handle,dc);
    	Sleep(50);
		Exit;
    end;
	time:=GetTickCount();
    if (time - prev_update_time) < 10 then
    begin
    	prev_update_time:=time;
        Sleep(1);
        exit;
    end;
    if GlWindow[0] <> nil then
    begin
        vglMakeCurrent(GlWindow[0]);
        Draw(PaintBox1,0,0,0,0);
    end;
    if GlWindow[1] <> nil then
    begin
        vglMakeCurrent(GlWindow[1]);
        Draw(PaintBox2,0,0,0,0);
    end;
    vglMakeCurrent(win);
end;

procedure TMainForm.FormShow(Sender: TObject);
var
	pix : void_p;
    dib	: PBITMAPINFO;
begin
	pix:=jpgLoad('../media/mist.jpg',w,h);
    if pix = nil then
    	exit;
    dib:=bmpCreateDIBObject(pix,w,h,0,0);
    memFree(pix);
    writeln(dib^.bmiHeader.biWidth,' ',dib^.bmiHeader.biHeight);
	br:=CreateDibPatternBrushPt(dib,DIB_RGB_COLORS);
    memFree(dib);
    ToolBar.Brush.Handle:=br;
	pix:=jpgLoad('../media/tentacles.jpg',w,h);
    if pix = nil then
    	exit;
    dib:=bmpCreateDIBObject(pix,w,h,0,0);
    memFree(pix);
	br:=CreateDibPatternBrushPt(dib,DIB_RGB_COLORS);
    memFree(dib);
	Application.OnIdle:=OnIdle;
end;

initialization
finalization
end.

