GLICT - Takeoff Snippets
======================

Note: these snippets were not updated for a long time. They were not checked for correctness for 1.1 release. 

Hi there,

thanks for downloading GLICT. This is my first opensourced library, and I see its purpose in implementing in an existing OpenGL program or game that needs get a GUI as quickly as possible, or within new programs for same purpose. It's been designed so it can be used with any approach to creating a window context, however mostly so that it can be used with relatively restrictive APIs such as GLUT.

GLICT has been (hopefully) written in a cross platform compatible way. I have tested it only on Windows, but generally it shouldn't be using anything that's not cross platform compatible. If there are some incompatible chunks of code, they are probably for debugging only and can we wiped out easily.

Unlike some other basic GUI implementations for games or some that you could quickly make, this one clips the UI elements within the boundaries of their parents, using either scissor or stencil test.

This document will tell you how to quickly start with GLICT, and provide you copypasteable chunks of code that are common to applicating GLICT (they're designed for GLUT, but adaptable to other IO systems). 

THIS DOCUMENT IS NOT A TUTORIAL; IT'S A CODECHUNK COLLECTION ALONG WITH SOME EXPLANATIONS. I'M NOT GOOD AT TUTORIAL WRITING (or just too lazy) SO IF ANYONE IS INTERESTED... WELL, I'M WAITING ;)

GLICT WANTS YOU! for a developer. CONTACT ME!

IDEAS BEHIND GLICT
=================
To accomplish this stuff, GLICT actually does not hook itself anywhere, and restores control to the caller whenever possible. So. you only need to insert some chunks of code in some pieces of the code and the thing works! 

You have one widget that I like to call desktop. It's of type glictContainer, and renders nothing, but contains children management code. All other widgets are, by the way, classes derived from glictContainer so they all contain the same children management code. When you want to add a widget of some other type (glictButton, glictPanel, glictWindow...) you simply call the function AddObject() from the glictContainer class. (And because all other classes are derived from the glictContainer class, all of them can contain children.) Then, you adjust the position and size of the widget using calls to it such as SetWidth() and SetHeight() or SetPos(). Refer to Doxygen docs for more functions.

User interacts with GLICT using mouse and keyboard. Currently there's no plans to make the UI keyboard-only. (Tab for switching between widgets and space for selection would be ideal, but we're not there yet.) If you want, you can make yourself some support for keyboard-only tasks, but that's application specific, and GLICT's event system allows you to do so. In fact, you can at any time do anything with GLICT; it doesn't control your application, your application controls GLICT.

Event system has been designed that way. Your IO management system (either GLUT, or Win32, or SDL or anything else) can, whenever it wants cast an event to the desktop class which will make sure the message arrives to the appropriate destination. 

INITIALIZATION
==============
If you want stencil testing to work the glutInitDisplayMode() needs to have the GLUT_STENCIL as one of things you'll be "OR"-ing ("|"-ing). If you'll use scissor test, you don't need to have GLUT_STENCIL. If you'll use scissor test, then just remove the GLUT_STENCIL thing. Depth testing is also not a requirement (actually, it should be off when you do the painting). Nevertheless, here's entire line that works for me:

	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH | GLUT_STENCIL);

For fonts to work (and what's the point of UI if you can't read what it says), you need to have the following chunk of code:

	glictFont* sysfont = glictCreateFont("system");
	sysfont->SetFontParam(GLUT_STROKE_MONO_ROMAN);
	sysfont->SetRenderFunc(glutxStrokeString);
	sysfont->SetSizeFunc(glutxStrokeSize);

You'll need to make your own glutxStrokeString() and glutxStrokeSize() or steal the glut-helper.cpp and glut-helper.h files from GLICT. (Copypaste them to your project dir, add glut-helper.cpp to the project, #include "glut-helper.h").

Of course the font system has been designed modular like this to allow all platforms to use their native fonts. Programmer that uses GLICT is required to write the appropriate functions that'll render and retrieve size of the GLUT.

Now, you also need to tell GL how you will do the testing. Scissor test is faster than stencil test:

	glictGlobals.clippingMode = GLICT_SCISSORTEST;

and if you want stencil test:

	glictGlobals.clippingMode = GLICT_STENCILTEST;

If you don't want either, which is fastest but might produce that widgets fall out of their parents:

	glictGlobals.clippingMode = GLICT_NOCLIP;

RESIZE
======
Upon window resize, it's a good idea to set desktop to new width and height, or you might have trouble. we'll also tell GLICT globally how large the UI is. This is required for scissor test to work; basically you can have more than one desktop, but they all need to know what's the desktop size, and you GLICT cannot know what's the main desktop to tell one of those. That's why we have glictGlobals. If you won't use scissor or stencil test for clipping, feel free to dump the glictGlobals line. Then we'll tell GLUT to re-draw the UI, so we cover new chunks of code.

(I believe you can understand the GL stuff, or else you wouldn't be looking for a UI for GL.)

void reshape(int w, int h) {
	// gl stuff
	glViewport(0,0,w,h);

	// glict stuff
	desktop.SetHeight(h);
	desktop.SetWidth(w);
	glictGlobals.w = w; glictGlobals.h = h;

	// gl stuff again
	glutPostRedisplay();
}

CREATING UI
===========
In next step we'll see something. But if we want to see something, we need to tell desktop what to contain.

Let's first declare desktop globally.

glictContainer desktop;

We'll also declare a window globally.

glictWindow window;

We'll declare a button within a function, and as a pointer. Then we'll add the window to desktop, and then the button to window. Each time we'll configure position and size. Adding a button like this, with dynamic declaration, will make us unable to later remove it or do other operations unless it's passed as callerclass when executing OnClick, or unless we've remembered it somewhere... but you're an advanced programmer and you know how you'll do all this, right? ;)

void glictinit() {
	desktop.Addobject(&window);
	window.SetHeight(200);
	window.SetWidth(300);
	window.SetPos(50, 50);

	glictButton* button = new glictButton;
	window.AddObject(button); // it's already a pointer ... :)
	button.SetWidth(100);
	button.SetHeight(32); // although 32 is default height of window, it might change in future
	button.SetOnClick(onclick); // which f. is done upon click on button; omit if you want to, but there's no sense :/
}

void onclick(glictPos* pos, glictContainer* caller) {
	// this gets executed
}

Pos is the relative position on which the button has received the click on, and caller points to the button itself (if you want to access button-only features, don't forget to cast caller into glictButton*).


PAINTING
========
When painting, you need to have each pixel on same position you'll pass when doing mouseevent casting. This is most easily done by calling gluOrtho2D with same width and height given to glViewport. If you do some other drawing as well then you probably don't do it in space like this, so we'll set it manually.

Because the GL (at least the way I do and I think the way that it must be done) has a flipped coordinate system, relative to most windowing systems of course, starting bottom left being (0,0), glRotatef() and glTranslatef() flip it to right place.

Then we enable the scissor test we'll use (we don't have it elsewhere for speed), we could "remember transformations" and then paint. Remembering transformations means that the GLICT would allow the coordinate system to be rotated a bit in modelview matrix, or translated, or scaled, but currently that part of code is not very functional (float imprecision is something I ... let's just say, dislike).

void display() {
	glClear(GL_COLOR_BUFFER_BIT);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(0,glictGlobals.w,0,glictGlobals.h);
	glRotatef(180.0, 1.0, 0.0, 0.0);
	glTranslatef(0,-glictGlobals.h,0.0);
	
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glPushMatrix();
	glEnable(GL_SCISSOR_TEST);
	//desktop.RememberTransformations();
	desktop.Paint();
	glDisable(GL_SCISSOR_TEST);
	glPopMatrix();

	
}

MOUSE EVENTS
============
Just a few comments:

* pos is necessary because the CastEvent is used for other things too, so if we need to pass more than one number as an argument it's better to pass just a pointer to a structure containing both of them. Mouse events expect glictPos structure.
* TransformScreenCoords would do multiplication by inverse of "remembered" modelview matrix. See PAINTING for more info. If you don't use it, don't call it for extra few FPS 
* GLICT can distinct between a click and drag internally; I've decided that only mousedown and mouseup need to be passed and GLICT can choose what each of them meant (was that mouseup just a mouseup or was it really a click)

void mouse(int mousex, int mousey) {
	glictPos pos;
	pos.x = mousex;
	pos.y = mousey;
	//desktop.TransformScreenCoords(&pos);
	if (state==GLUT_DOWN) desktop.CastEvent(GLICT_MOUSEDOWN, &pos, 0);
	if (state==GLUT_UP) desktop.CastEvent(GLICT_MOUSEUP, &pos, 0);
}

KEYBOARD EVENTS
===============
Although currently used only for textboxes, they are certainly valuable. No much to say...

void keyboard (unsigned char key, int x, int y) {
	desktop.CastEvent(GLICT_KEYPRESS, &key, 0);
	glutPostRedisplay();
}

INCLUDE FILES
=============
In these snippets we used glictContainer, glictButton, glictWindow and glictGlobals. So:

#include <GLICT/container.h>
#include <GLICT/button.h>
#include <GLICT/window.h>
#include <GLICT/globals.h>

belong somewhere on top.

Don't forget to tell your linker to link with GLICT's library. Or add all the .cpp files to your project (GLICT is opensource ;)). For Visual C++ it should be:

#pragma comment (lib, "glict.lib")

For others compilers ... well ya'll figure out ;)

I THINK WE'RE DONE
==================
By now we should have all the basic code we need for GLICT application. This is not from-zero tutorial; you'll need to know where to put each snippet. So take your existing GLUT application and try to put these chunks on appropriate locations.

AUTHOR & LEGAL
==============
Ivan Vucica
(c) 2006-2008 Ivan Vucica
This document is provided for free, without any warranty. You are free to modify and distribute, however you are obligated to keep the History section and add specific date when you started modifications to this file, along with your name on the same location. You also must keep original copyright notice and this notice in place.
Otherwise you are free to do whatever you want with this file. (Note, this rule doesn't apply to rest of GLICT which is given out under GNU LGPL.)

HISTORY
==================
Here's a quick change history of this file.

5.10.2006
Small alterations in init section. (made clear what's not needed in glutInitDisplayMode())
Added author section
One new comment in resizing section
Minifix to include files section

13.9.2006
Written first version
