Your Ad Here

Subscribe
 Post #1
 2nd February 2010 Last edited by garry; 10th February 2010 at 11:51AM..
garry's Avatar
September 2001
10,878 Posts
GWEN is a GUI widget toolkit aimed at building comfortable GUIs. It's like Crazy Eddies GUI thing, except less heavy - without all the XML stuff. It's simply just the base widgets.

There's more info about what it is here

http://www.garry.tv/?p=1389

and download etc are here

http://gwen.facepunchstudios.com/home

It's still a work in progress. It's not perfect right now - but if anyone wants to get involved and make some changes let me know what you're thinking of doing and I'll give you write access..
 Post #2
 2nd February 2010 Last edited by Jallen; 2nd February 2010 at 09:09AM..
Gold Member
Jallen's Avatar
December 2007
6,029 Posts
Downloading right now.
I think I shall make an SFML renderer for it.

Edit:
Uurghshs solution folders what is this I dont even VC++ express does not like.

UnitTest.h isn't in Gwen/UnitTest/ whattt

See: https://facepunch.svn.beanstalkapp.c...gwen/UnitTest/
 Post #3
 2nd February 2010
SaltyPeppr's Avatar
August 2008
438 Posts
holy shit, that looks really good so far
 Post #4
 2nd February 2010 Last edited by AaRoNg11; 2nd February 2010 at 02:30PM..
AaRoNg11's Avatar
May 2005
97 Posts
This really looks pretty nice, what sort of license are you planning on releasing it under? Could really use this in my latest project. I wrote all my current GUI code myself and it's really getting out of hand maintaining it.

[edit]
Oops, sorry just spotted in the code it's under MIT license :)
[/edit]
 Post #5
 2nd February 2010
Darkster's Avatar
July 2009
101 Posts
Downloading right now.
I think I shall make an SFML renderer for it.

Edit:
Uurghshs solution folders what is this I dont even VC++ express does not like.

UnitTest.h isn't in Gwen/UnitTest/ whattt

See: https://facepunch.svn.beanstalkapp.c...gwen/UnitTest/
After a clean checkout, it doesnt compile, failing to find the headers. You need to add $(ProjectDir)\include\ to the additional includes on the projects.
Thats for a debug build at least, havn't tried release yet.

Other than that, looks good. Might try getting it working with Ogre3D later.

That should help. (UnitTest.h is in /include/gwen/unittest/)

I downloaded this last night and played with it. Might make it play with OSW for laughs.
 Post #6
 2nd February 2010
Gold Member
Jallen's Avatar
December 2007
6,029 Posts
That should help. (UnitTest.h is in /include/gwen/unittest/)

I downloaded this last night and played with it. Might make it play with OSW for laughs.
Ah right yeah, looks like it will be what I need to do.

Thanks.
 Post #7
 2nd February 2010
Gold Member
Dennab
July 2008
8,183 Posts
-snip-
 Post #8
 2nd February 2010
implaying8's Avatar
May 2005
431 Posts
Winsauce. Why are you releasing it free though? You could sell it for quite a bit of profit later on!
 Post #9
 2nd February 2010
Dennab
December 2009
260 Posts
Winsauce. Why are you releasing it free though? You could sell it for quite a bit of profit later on!
I dunno what i'm more annoyed at, the use of the word 'Winsauce' or your stupid question.
 Post #10
 3rd February 2010 Last edited by honeybuns; 3rd February 2010 at 12:25AM..
Dennab
December 2009
260 Posts
If you manage to get part of the window outside the canvas, stuff starts to mess up.

First-chance exception at 0x768c42eb in Direct3DSample.exe: Microsoft C++ exception: long at memory location 0x0019efec..
Direct3D9: (ERROR) :DrawPrimitiveUP failed.

Direct3D9: (ERROR) :Scissor rect outside the render target surface

Which is expected but the window should never be able to get outside the canvas if it doesnt go past the canvas rect.

My window is 800x600 (using AjustWindowRect) and the canvas size is 800x600
 Post #11
 3rd February 2010
Dennab
April 2009
831 Posts
I'll get working on a C# wrapper library
 Post #12
 3rd February 2010
OrYgin's Avatar
November 2007
404 Posts
I'll get working on a C# wrapper library
I love you.
 Post #13
 3rd February 2010
voodooattack's Avatar
October 2009
497 Posts
Just finished my SFML renderer.
I'll have to iron out the few glitches left before posting it here.
 Post #14
 4th February 2010
FluD's Avatar
February 2006
646 Posts
that shit only with dx -_- i need openGL
 Post #15
 4th February 2010
Gold Member
nullsquared's Avatar
November 2007
4,353 Posts
that shit only with dx -_- i need openGL
So write an OpenGL renderer?
 Post #16
 4th February 2010
Dennab
December 2009
260 Posts
crashing on the dx renderer for anyone else?

Edited:

was working fine last night and there has been no commits so i must be fucking something up
 Post #17
 4th February 2010
a203xi's Avatar
January 2005
783 Posts
So write an OpenGL renderer?
What's the point of others doing my work for me if I still have to work for myself? D:
 Post #18
 4th February 2010
t0rento's Avatar
September 2006
820 Posts
Had a look at compiling this under Linux with gcc, a preliminary look suggests that there is some non-portable code but it's not in a huge abundance. Obviously the DirectX and GDI renderers wouldn't compile but OpenGL would so there's potential.
 Post #19
 4th February 2010 Last edited by blankthemuffin; 4th February 2010 at 05:37AM..
blankthemuffin's Avatar
July 2009
1,052 Posts
Yeah I got a few files fixed, got to a file where GWEN_CONTROL_INLINE is producing invalid C++ and I couldn't be bothered fixing it.
 Post #20
 4th February 2010
garry's Avatar
September 2001
10,878 Posts
Can you email me your fixes? garrynewman@gmail.com
 Post #21
 4th February 2010
blankthemuffin's Avatar
July 2009
1,052 Posts
I will if I finish them, the stuff I've fixed is just removing stdafx, changing max and min to std::max and std::min (not sure if you're doing some trickery there either didn't look), adding a few headers like algorithm for std::find.

Then I got to
Code:
include/Gwen/Controls/Modal.h:17: error: expected unqualified-id before ‘public’
Which looks like that macro is incorrectly expanding a typedef into
typedef public Controls::Base BaseClass;
Which is not valid C++.

In short the stuff I've fixed is really trivial. And I'm only 12% through the source files anyway.
 Post #22
 4th February 2010
voodooattack's Avatar
October 2009
497 Posts


> Failed to load font "Marlett.ttf" (failed to set the Unicode character set)
Darn you SFML, darn you!

And why does the GUI require that font anyways? isn't that a Windows-only font?
Can't we just draw the UI arrows as vector shapes? A Renderer::DrawTriangle would be sufficient I think.

What to do now? add a special case to RenderText and have it intercept the Marlett font or what?
 Post #23
 4th February 2010
iRzilla's Avatar
August 2008
1,854 Posts
Which DirectX runtime is required for this?
 Post #24
 4th February 2010
TehBigA's Avatar
March 2007
923 Posts
Which DirectX runtime is required for this?
Just get the latest SDK and set the paths.
 Post #25
 5th February 2010
Dennab
April 2009
831 Posts


I accidentally GWEN
 Post #26
 5th February 2010
garry's Avatar
September 2001
10,878 Posts



Darn you SFML, darn you!

And why does the GUI require that font anyways? isn't that a Windows-only font?
Can't we just draw the UI arrows as vector shapes? A Renderer::DrawTriangle would be sufficient I think.

What to do now? add a special case to RenderText and have it intercept the Marlett font or what?
It uses Marlett to draw the arrows and stuff (like the down arrow on the scrollbar etc). I think it's only used in the skin - so it could be fixed with a new skin - which is probably something we should look into doing.
 Post #27
 5th February 2010
Gold Member
arienh4's Avatar
August 2007
4,973 Posts
It uses Marlett to draw the arrows and stuff (like the down arrow on the scrollbar etc). I think it's only used in the skin - so it could be fixed with a new skin - which is probably something we should look into doing.
Why not just render arrows?
 Post #28
 5th February 2010
garry's Avatar
September 2001
10,878 Posts
That's what marlett does

Edited:

By that I mean that's exactly what I'm talking about doing when I mention the skin.
 Post #29
 5th February 2010
Gold Member
arienh4's Avatar
August 2007
4,973 Posts
I meant, why not render an arrow from scratch, rather than relying on a (proprietary, apparently) font?
 Post #30
 5th February 2010
garry's Avatar
September 2001
10,878 Posts
That's what I'm talking about in my last 2 posts
 Post #31
 5th February 2010
Dennab
February 2010
25 Posts
That's what I'm talking about in my last 2 posts
They're illiterate.
 Post #32
 5th February 2010
voodooattack's Avatar
October 2009
497 Posts
Can't we just expand the base renderer interface to make it slightly more advanced?

Oh, and I wanted to ask, isn't there something wrong with StartClip/EndClip? the latter hardly ever gets called unlike the former, and it messed up the OpenGL attribute stack when I tried implement clipping by pushing/popping the GL_SCISSOR_BIT attribute to preserve the current clipping region. (which would've been awesome, since every call to EndClip after painting a child would restore the parent's clipping region automatically)

I resorted to saving all attributes at Renderer::Begin() and then restoring everything back when Renderer::End() gets called, but that simply kills the FPS and ruins clipping at different scales.

To be honest, I think I got clipping working by accident in the first place, the whole thing gets highly inconsistent when scaling is involved.

Anyways, here's my SFML (you'll need a current SVN build) renderer draft as it stands:

Code:
#include "Gwen/Gwen.h"
#include "Gwen/BaseRender.h"
#include "Gwen/Utility.h"
#include "Gwen/Font.h"
#include "Gwen/Texture.h"

#include <math.h>
#include <algorithm>

#include <Windows.h>
#include <gl/GL.h>
#include <SFML/Graphics.hpp>

namespace Gwen 
{
	namespace Renderer 
	{

		class SFML : public Gwen::Renderer::Base
		{
			private:
				
				template<typename T> 
				struct Resource
				{
					private:
						T* m_resource;
						bool m_delete;
					public:
						Resource(T* ptr, bool bDelete = false) : m_resource(ptr), m_delete(bDelete)	{ return; };
						~Resource() { if (m_delete) delete(m_resource); };
						T* Get() const { return m_resource; };
				};

				typedef Resource<sf::Font> ResFont;
				typedef Resource<sf::Image> ResImage;


			public:

				typedef sf::Font* (*fontRequestHandler)(const Gwen::UnicodeString& facename, float size, bool& bDelete);
				typedef sf::Image* (*imageRequestHandler)(const Gwen::UnicodeString& name, bool& bDelete);

				SFML(sf::RenderTarget& target)
					: m_renderTarget(target),
					  m_Color(),
					  m_onImageRequest(NULL),
					  m_onFontRequest(NULL)
				{
					
					// Lazy programmer's approach to vector rendering..
					const static unsigned int missingPixels[] = { 
						0x80FFFFFF, 0x80000000, 0x80FFFFFF, 0x80000000,
						0x80000000, 0x80FFFFFF, 0x80000000, 0x80FFFFFF,
						0x80FFFFFF, 0x80000000, 0x80FFFFFF, 0x80000000,
						0x80000000, 0x80FFFFFF, 0x80000000, 0x80FFFFFF,
					};
					
					m_missingPlaceholder.SetSmooth(false);
					m_missingPlaceholder.LoadFromPixels(4, 4, (sf::Uint8*)&missingPixels);
					
				};

				virtual ~SFML()
				{
				};

				virtual void Begin() 
				{
					m_renderTarget.SaveGLStates();
				};

				virtual void End()
				{
					m_renderTarget.RestoreGLStates();
				};

				virtual void StartClip()
				{
					Gwen::Rect rect = ClipRegion();
					Gwen::Point offset = GetRenderOffset();
					
					float scale = Scale();
					
					//DrawDebugRect(rect);

					GLint viewportData[4];
					glGetIntegerv(GL_VIEWPORT, &viewportData[0]);

					int vx = viewportData[0], vy = viewportData[1], vw = viewportData[2], vh = viewportData[3];

					int x = floor(float(rect.x) * scale),
						y = floor(float(rect.y + rect.h) * scale),
						w = floor(float(rect.w) * scale),
						h = floor(float(rect.h) * scale);
					
					// we must swap the Y axis for glScissor to work.
					glScissor(x, vh - y, w, h);
					glEnable(GL_SCISSOR_TEST);
				};


				virtual void EndClip()
				{
					glDisable(GL_SCISSOR_TEST);
				};

				virtual void SetDrawColor( Gwen::Color color )
				{
					m_Color	= toSfColor(color);
				};

				virtual void DrawLine( int x, int y, int a, int b )
				{
					Translate(x, y);
					Translate(a, b);

					sf::Shape line = sf::Shape::Line(x, y, a, b, 1.0f, m_Color);
					
					m_renderTarget.Draw(line);
				};

				virtual void DrawFilledRect( Gwen::Rect rect )
				{
					Translate(rect);

					sf::Shape shape = sf::Shape::Rectangle(
						0, 
						0, 
						rect.w - 1, 
						rect.h - 1, 
						m_Color
					);

					shape.SetPosition(rect.x, rect.y);					
					m_renderTarget.Draw(shape);
				};

				virtual void DrawPixel( int x, int y )
				{
					Translate(x, y);
					//glPointSize(Scale());
					glBegin(GL_POINTS);
					glColor4f(m_Color.r / 255.0f, m_Color.g / 255.0f, m_Color.b /255.0f, m_Color.a / 255.0f);
					glVertex2f(x, y);
					glEnd();
				};

				virtual void DrawLinedRect( Gwen::Rect rect )
				{
					Translate(rect);
					
					sf::Shape shape = sf::Shape::Rectangle(
						0, 
						0, 
						rect.w-2, 
						rect.h-2,
						m_Color,
						1.0f,
						m_Color
						);

					shape.EnableFill(false);
					shape.EnableOutline(true);
					shape.SetPosition(rect.x+1, rect.y+1);

					m_renderTarget.Draw(shape);

				};

				virtual void DrawShavedCornerRect( Gwen::Rect rect, bool bSlight = false )
				{

					sf::Shape shape;
					float cornerSize = bSlight ? 1.0f : 2.0f;

					Translate(rect);

					rect.x += 1; rect.y += 1;
					rect.w -= 2; rect.h -= 2;

					shape.SetPosition(rect.x, rect.y);
					shape.SetOutlineWidth(1.0f);
					shape.EnableFill(false);
					shape.EnableOutline(true);

					shape.AddPoint(cornerSize,			0,						m_Color, m_Color);
					shape.AddPoint(rect.w - cornerSize, 0,						m_Color, m_Color);
					shape.AddPoint(rect.w,				cornerSize,				m_Color, m_Color); 
					shape.AddPoint(rect.w,				rect.h - cornerSize,	m_Color, m_Color); 
					shape.AddPoint(rect.w - cornerSize, rect.h,					m_Color, m_Color); 
					shape.AddPoint(cornerSize,			rect.h,					m_Color, m_Color);
					shape.AddPoint(0,					rect.h - cornerSize,	m_Color, m_Color); 
					shape.AddPoint(0,					cornerSize,				m_Color, m_Color);

					m_renderTarget.Draw(shape);
				};

				virtual void DrawTexturedRect( Gwen::Texture* pTexture, Gwen::Rect pTargetRect, 
					float u1=0.0f, float v1=0.0f, float u2=1.0f, float v2=1.0f )
				{

					if (!pTexture->data)
						return DrawMissingImage(pTargetRect);

					Translate(pTargetRect);

					ResImage* res = static_cast<ResImage*>(pTexture->data);
					const sf::Image* tex = res->Get();
					
					sf::Sprite sp(*tex);
					sf::IntRect rect = toSfRect(pTargetRect);

					float fW = tex->GetWidth(), fH = tex->GetHeight();
					
					sp.SetSubRect(sf::IntRect(ceil(u1 * fW), ceil(v1 * fH), ceil(u2 * fW), ceil(v2 * fH)));				
					sp.SetPosition(sf::Vector2f(pTargetRect.x, pTargetRect.y));
					sp.Resize(sf::Vector2f(pTargetRect.w, pTargetRect.h));

					m_renderTarget.Draw(sp);
				};

				virtual void DrawMissingImage( Gwen::Rect pTargetRect )
				{
					Translate(pTargetRect);
					
					sf::Sprite missing = sf::Sprite(m_missingPlaceholder);
					
					missing.SetPosition(pTargetRect.x, pTargetRect.y);
					missing.Resize(pTargetRect.w, pTargetRect.h);

					m_renderTarget.Draw(missing);
				}
				
				// Text:

				template<typename T>
				void RenderText( Gwen::Font* pFont, Gwen::Point pos, const T& text )
				{
					if (!pFont)			
						return;
					else if (!pFont->data)
						LoadFont(pFont);					

					Translate(pos.x, pos.y);

					float scale = Scale();
					ResFont* res = static_cast<ResFont*>(pFont->data);

					int realsize = (ceil(pFont->size * scale) / 4 == 1) ? ceil(pFont->size * scale) : floor(pFont->size * scale);

					sf::Text txt(sf::String(text), *res->Get(), realsize);

					txt.SetColor(m_Color);
					txt.SetPosition(toSfVectorF(pos));

					m_renderTarget.Draw(txt);
				};

				template<typename T>
				Gwen::Point MeasureText(Gwen::Font* pFont, const T& text)
				{
					if (!pFont)
						return Gwen::Point();
					else if (!pFont->data)
						LoadFont(pFont);

					float scale = Scale();
					ResFont* res = static_cast<ResFont*>(pFont->data);

					int realsize = (ceil(pFont->size * scale) / 4 == 1) ? ceil(pFont->size * scale) : floor(pFont->size * scale);

					sf::Text txt(sf::String(text), *res->Get(), realsize);

					if (text.empty())
						txt.SetString(" ");

					sf::Vector2f sz = txt.GetRect().GetSize();

					return Gwen::Point(sz.x, sz.y);
				};

				virtual void RenderText( Gwen::Font* pFont, Gwen::Point pos, const Gwen::String& text )
				{ return RenderText<Gwen::String>(pFont, pos, text); };

				virtual void RenderText( Gwen::Font* pFont, Gwen::Point pos, const Gwen::UnicodeString& text )
				{ return RenderText<Gwen::UnicodeString>(pFont, pos, text);	};

				virtual Gwen::Point MeasureText( Gwen::Font* pFont, const Gwen::String& text )
				{ return MeasureText<Gwen::String>(pFont, text); };

				virtual Gwen::Point MeasureText( Gwen::Font* pFont, const Gwen::UnicodeString& text )
				{ return MeasureText<Gwen::UnicodeString>(pFont, text);	};

				// Resource handling

				virtual void LoadTexture( Gwen::Texture* pTexture )
				{
					if (!pTexture)
						return;
					if (pTexture->data)
						FreeTexture(pTexture);

					sf::Image* tex = NULL;
					bool bDelete = false;

					if (m_onImageRequest)
					{
						tex = m_onImageRequest(pTexture->name, bDelete);
					}
					else
					{
						tex = new sf::Image();
						tex->SetSmooth(true);

						if (!tex || !tex->LoadFromFile(Gwen::Utility::UnicodeToString(pTexture->name)))
						{
							if (tex)
								delete(tex);

							pTexture->failed = true;
							return;
						}
						else
						{
							bDelete = true;
						}
					}

					pTexture->height = tex->GetHeight();
					pTexture->width = tex->GetWidth();
					pTexture->data = new ResImage(tex, bDelete);

				};

				virtual void FreeTexture( Gwen::Texture* pTexture )
				{
					if (pTexture->data)
						delete (static_cast<ResImage*>(pTexture->data));

					pTexture->data = NULL;
					return;
				};

				virtual void LoadFont( Gwen::Font* pFont )
				{
					if (!pFont)
						return;

					sf::Font* font = NULL;
					bool bDelete = false;

					if (m_onFontRequest)
					{
						font = m_onFontRequest(pFont->facename, pFont->size, bDelete);
					}
					else
					{
						font = new sf::Font();
						std::string facename(Gwen::Utility::UnicodeToString(pFont->facename));

						if (!font->LoadFromFile(facename))
						{
							font = (sf::Font*)(void*)&sf::Font::GetDefaultFont();
							bDelete = false;
						}
						else
						{
							bDelete = true;
						}
					}

					pFont->data = new ResFont(font, bDelete);
					pFont->realsize = Scale();

				};
				
				virtual void FreeFont( Gwen::Font* pFont )
				{
					if (pFont && pFont->data)
					{
						delete (static_cast<ResFont*>(pFont->data));
						pFont->data = NULL;
					}
				};

				// Request hooks:
				fontRequestHandler FontRequest() const { return m_onFontRequest; }
				void FontRequest(fontRequestHandler val) { m_onFontRequest = val; }

				imageRequestHandler ImageRequest() const { return m_onImageRequest; }
				void ImageRequest(imageRequestHandler val) { m_onImageRequest = val; }

			private:
				
				sf::RenderTarget& m_renderTarget;
				sf::Color m_Color;

				fontRequestHandler m_onFontRequest;
				imageRequestHandler m_onImageRequest;

				// Internal resources:
				sf::Image m_missingPlaceholder;

				// Helpers
				static sf::Color toSfColor(const Gwen::Color& c) 
				{ 
					return sf::Color(c.r,c.g,c.b,c.a);
				};
				
				static sf::IntRect toSfRect(const Gwen::Rect& r) 
				{ 
					return sf::IntRect(r.x, r.y, r.x + r.w, r.y + r.h);
				};

				static sf::FloatRect toSfRectF(const Gwen::Rect& r) 
				{ 
					return sf::FloatRect(r.x, r.y, r.x + r.w, r.y + r.h);
				};

				static sf::Vector2i toSfVector(const Gwen::Point p)
				{
					return sf::Vector2i(p.x, p.y);
				};

				static sf::Vector2f toSfVectorF(const Gwen::Point p)
				{
					return sf::Vector2f(p.x, p.y);
				};

				void DrawDebugRect( Gwen::Rect rect, bool translate = true )
				{
					if (translate)
						Translate(rect);

					sf::Shape shape = sf::Shape::Rectangle(
						0, 
						0, 
						rect.w-2, 
						rect.h-2,
						m_Color,
						1.0f,
						sf::Color::Red
						);

					shape.EnableFill(false);
					shape.EnableOutline(true);
					shape.SetPosition(rect.x+1, rect.y+1);

					m_renderTarget.Draw(shape);

				};
		};

	}
}
And the sample:
Code:
#include <SFML/Graphics.hpp>

#include "Gwen/Gwen.h"
#include "Gwen/Skins/Simple.h"
#include "Gwen/Skins/TexturedBase.h"
#include "Gwen/UnitTest/UnitTest.h"
#include "Gwen/Renderers/SFML.h"
//#include "Gwen/Renderers/SFML_Drawable.h"

#pragma comment( lib, "sfml-window-s-d.lib" )
#pragma comment( lib, "sfml-graphics-s-d.lib" )
#pragma comment( lib, "sfml-system-s-d.lib" )
#pragma comment( lib, "sfml-main-d.lib" )

void ProcessEvent(sf::Event& event);

//sf::Font* fontRequestHandler(const Gwen::UnicodeString& facename, float size, bool& bDelete)
//{
//	sf::Font* font = new sf::Font();
//	std::string name = Gwen::Utility::UnicodeToString(facename);
//	name.append(".ttf");
//
//	if (font->LoadFromFile(name))
//	{
//		bDelete = true;
//		return font;
//	}
//	else
//	{
//		bDelete = false;
//		return (sf::Font*)(void*)&sf::Font::GetDefaultFont();
//	}
//}

int main()
{
	sf::RenderWindow window(sf::VideoMode(1016, 538), "SFML window");

	Gwen::Renderer::SFML render(window);
	//Gwen::Renderer::SFMLDrawable render();
	Gwen::Skin::TexturedBase skin;
	//Gwen::Skin::Simple skin;

	//render.FontRequest(&fontRequestHandler);

	skin.SetRender( &render );
	skin.Init();

	Gwen::Controls::Canvas* pCanvas = new Gwen::Controls::Canvas( &skin );
	pCanvas->SetSize( 1000, 500);

	UnitTest* pUnit = new UnitTest( pCanvas );
	pUnit->SetPos( 10, 10 );

	//Gwen::Controls::Button* x = new Gwen::Controls::Button(pCanvas);
	//x->SetPos(100, 100);
	//x->SetSize(140, 60);
	//x->SetText("Hello world!");

	window.SetActive();

	while (window.IsOpened())
	{
		sf::Event event;

		while (window.GetEvent(event))
		{
			switch (event.Type)
			{
				case sf::Event::Closed:
					window.Close();
					break;
				case sf::Event::Resized:
					pCanvas->SetScale((float)window.GetWidth() / (float)pCanvas->Width());
					break;
				default:
					ProcessEvent(event);
					break;
			}
		}

		window.Clear(sf::Color(150, 170, 170));	 // clear the window

		pCanvas->DoInput();
		pCanvas->RenderCanvas();

		//window.Draw(render);
		
		window.Display(); // swap screen buffers
	}

	return EXIT_SUCCESS;
};

void ProcessEvent(sf::Event& event)
{
	switch(event.Type)
	{
		case sf::Event::MouseMoved:
			Gwen::Input::CursorMoved(event.MouseMove.X, event.MouseMove.Y);
			break;
		case sf::Event::MouseButtonPressed:
			Gwen::Input::MouseButton(event.MouseButton.Button, true);
			break;
		case sf::Event::MouseButtonReleased:
			Gwen::Input::MouseButton(event.MouseButton.Button, false);
		case sf::Event::MouseWheelMoved:
			Gwen::Input::MouseWheel(event.MouseWheel.Delta * 120);
			break;
		case sf::Event::TextEntered:
			Gwen::Input::Character(event.Text.Unicode);
			break;
		case sf::Event::KeyPressed:
		case sf::Event::KeyReleased:
			{					
				bool pressed = (event.Type == sf::Event::KeyPressed);
				int keyCode = event.Key.Code;
				int iKey = -1;

				if (event.Key.Control)
				{
					if (keyCode == sf::Key::C)
					{
						Gwen::Input::ActionMessage(Gwen::Input::Message::Copy);
						break;
					}
					else if (keyCode == sf::Key::V)
					{
						Gwen::Input::ActionMessage(Gwen::Input::Message::Paste);
						break;
					}
					else if (keyCode == sf::Key::X)
					{
						Gwen::Input::ActionMessage(Gwen::Input::Message::Cut);
						break;
					}
					else if (keyCode == sf::Key::A)
					{
						Gwen::Input::ActionMessage(Gwen::Input::Message::SelectAll);
						break;
					}
					else if (keyCode == sf::Key::Z)
					{
						Gwen::Input::ActionMessage(Gwen::Input::Message::Undo);
						break;
					}
					else if (keyCode == sf::Key::Y)
					{
						Gwen::Input::ActionMessage(Gwen::Input::Message::Redo);
						break;
					}

				}

				if (keyCode == sf::Key::Back) iKey = Gwen::Key::Backspace;
				else if (keyCode == sf::Key::Return) iKey = Gwen::Key::Return;
				else if (keyCode == sf::Key::Escape) iKey = Gwen::Key::Escape;
				else if (keyCode == sf::Key::Tab) iKey = Gwen::Key::Tab;
				else if (keyCode == sf::Key::Space) iKey = Gwen::Key::Space;
				else if (keyCode == sf::Key::Up) iKey = Gwen::Key::Up;
				else if (keyCode == sf::Key::Down) iKey = Gwen::Key::Down;
				else if (keyCode == sf::Key::Left) iKey = Gwen::Key::Left;
				else if (keyCode == sf::Key::Right) iKey = Gwen::Key::Right;
				else if (keyCode == sf::Key::Home) iKey = Gwen::Key::Home;
				else if (keyCode == sf::Key::Delete) iKey = Gwen::Key::Delete;
				else if (keyCode == sf::Key::LControl || keyCode == sf::Key::RControl) iKey = Gwen::Key::Control;
				else if (keyCode == sf::Key::LAlt || keyCode == sf::Key::RAlt) iKey = Gwen::Key::Alt;
				else if (keyCode == sf::Key::LShift || keyCode == sf::Key::RShift) iKey = Gwen::Key::Shift;

				if (iKey != -1)
				{
					if (pressed)
						Gwen::Input::KeyPress(iKey);
					else
						Gwen::Input::KeyRelease(iKey);
				}

				break;
			}
		default:
			break;
	}
};
I'm currently rewriting the whole thing as a sf::Drawable with a vertex pipeline, which means that no drawing will take place until window.Draw(render) is called in the main loop, should give a hefty performance boost.
 Post #33
 5th February 2010
garry's Avatar
September 2001
10,878 Posts
Yeah, the usage of StartClip/EndClip is a bit incoherant right now.

It DOES restore clipping back to its parents, but it calls StartClip to do that. EndClip is used to turn clipping off all together.

This is messy, I agree. I think a better approach would be a stack like system, where we push and pop clipping. I'll probably work on this within the next week.

What kind of things were you hoping for in the renderer interface?
 Post #34
 5th February 2010 Last edited by voodooattack; 5th February 2010 at 09:05PM.. (small amendment to code)
voodooattack's Avatar
October 2009
497 Posts
Yeah, the usage of StartClip/EndClip is a bit incoherant right now.

It DOES restore clipping back to its parents, but it calls StartClip to do that. EndClip is used to turn clipping off all together.
I figured that much browsing the source in more depth for the past hour, especially this bit of code:

void Base::DoRender( Gwen::Skin::Base* skin )
{
	// If this control has a different skin, 
	// then so does its children.
	if ( m_Skin ) 
		skin = m_Skin;

	// Do think
	Think();

	Gwen::Renderer::Base* render = skin->GetRender();

	Point pOldRenderOffset = render->GetRenderOffset();

	render->AddRenderOffset( GetBounds() );

	RenderUnder( skin );
	
	Rect rOldRegion = render->ClipRegion();
	render->AddClipRegion( GetBounds() );

	if ( render->ClipRegionVisible() )
	{
		render->StartClip();
		
		//Render myself first
		Render( skin );

		if ( !Children.empty() )
		{
			//Now render my kids
			for (Base::List::iterator iter = Children.begin(); iter != Children.end(); ++iter)
			{
				Base* pChild = *iter;
				if ( pChild->Hidden() ) continue;

				pChild->DoRender( skin );
			}		
		}

		render->SetClipRegion( rOldRegion );
		render->StartClip();
		....

I thought it was a typo at first sight and thought about changing the last "render->StartClip();" to "render->EndClip();" but then I noticed the line before it and realized what was going on.

This is messy, I agree. I think a better approach would be a stack like system, where we push and pop clipping. I'll probably work on this within the next week.
Yeah, that would be much nicer, just let the renderer implement the stack on its own or override the default implementation please.

I also suggest moving the scaling/translation phase away from the renderer and into the library itself, since it means nothing to the renderer anyways; when it paints rectangles/lines/textures, it doesn't care about the scale (which is implicit when rendering textures), all that matters is X/Y, width/height and U/V coords.

The only situation a scale should be passed to the renderer is with fonts, but that's a special situation, in which case the scale should be passed as an argument to MeasureText/RenderText as needed.

Changing it to work that way should ensure that calls to Canvas::SetScale only affect the input translation (for mouse clicks), and that the translation logic doesn't leak into the renderer, since it gets final coordinates that match what's expected on screen.

What kind of things were you hoping for in the renderer interface?
If it was up to me, I'd have two layers of abstraction:

class Device
{
public:

	virtual void Begin() = 0;
	virtual void End() = 0;

	virtual void PushClippingRect(Gwen::Rect clippingRegion) = 0;
	virtual void PopClippingRect() = 0;

	virtual void BeginShape(int x, int y, Gwen::Color color, bool fill = true, Gwen::Texture* pTexture = NULL) = 0;
	virtual void AddVertex(int x, int y) = 0;
	virtual void AddVertex(int x, int y, Gwen::Color color) = 0;
	virtual void AddVertex(int x, int y, Gwen::Point uv) = 0;
	virtual void AddVertex(int x, int y, Gwen::Color color, Gwen::Point uv) = 0;
	virtual void EndShape() = 0;

	virtual void DrawText(Gwen::Font* pFont, Gwen::Point pos, const Gwen::String& text, float scale = 1.0f) = 0;
	virtual void MeasureText(Gwen::Font* pFont, const Gwen::String& text, float scale = 1.0f) = 0;

	virtual void DrawText(Gwen::Font* pFont, Gwen::Point pos, const Gwen::UnicodeString& text, float scale = 1.0f) = 0;
	virtual void MeasureText(Gwen::Font* pFont, const Gwen::UnicodeString& text, float scale = 1.0f) = 0;

	virtual void LoadTexture(Gwen::Texture* pTexture) = 0;
	virtual void FreeTexture(Gwen::Texture* pTexture) = 0;

	virtual void LoadFont(Gwen::Font* pFont) = 0;
	virtual void FreeFont(Gwen::Font* pFont) = 0;
};

class Renderer
{
private:
	
	Device*	myDevice;
	Gwen::Color		myFillColor;
	Gwen::Color		myOutlineColor;

public:

	Renderer(Device* device)
		: myDevice(device)
	{
		return;
	};

	virtual void SetColor(Gwen::Color fillColor)
	{
		myFillColor = fillColor;
	};

	virtual void SetOutlineColor(Gwen::Color outline)
	{
		myOutlineColor = outline;
	};

	virtual void DrawRect(Gwen::Rect rect, bool bFill, bool bOutline)
	{
		if (bOutline)
		{
			myDevice->BeginShape(rect.x, rect.y, myFillColor, bFill);
				myDevice->AddVertex(0, 0, myOutlineColor);
				myDevice->AddVertex(0, rect.w, myOutlineColor);
				myDevice->AddVertex(rect.w, rect.h, myOutlineColor);
				myDevice->AddVertex(0, rect.h, myOutlineColor);
			myDevice->EndShape();
		}
		else
		{
			myDevice->BeginShape(rect.x, rect.y, myFillColor, true);
				myDevice->AddVertex(0, 0);
				myDevice->AddVertex(0, rect.w);
				myDevice->AddVertex(rect.w, rect.h);
				myDevice->AddVertex(0, rect.h);
			myDevice->EndShape();
		}
	};
	
	// etc..
};

Or something like that.

The base renderer (second class) would implement all of the standard shapes given any device (and possibly custom vector shapes); this way, you can either implement the device directly for maximum performance (the case with OpenGL/DirectX), or override the functions in the renderer class and negate the need for a device class (for higher level APIs such as GdiPlus).

I deliberately removed the parameter that specifies the primitive type from BeginShape() since I have no prior experience with DirectX (I have no idea what's supported on both sides), so I'll need input on that.

What do you think of this model?
 Post #35
 6th February 2010
jsharbour's Avatar
February 2010
11 Posts
Thank you for the open source GUI toolkit, Garry. I am trying to build a demo without using UnitTest and finding it very difficult to break down the code due to the convoluted #defines and inheritance in UnitTest which makes the code difficult to read. Is there any chance you have a quick tutorial or test code on how to just create a window and add a couple of controls to it? I'll keep working, but if you happen to have the code it would be a time saver. Thanks.
 Post #36
 6th February 2010
Dennab
April 2009
831 Posts
Thank you for the open source GUI toolkit, Garry. I am trying to build a demo without using UnitTest and finding it very difficult to break down the code due to the convoluted #defines and inheritance in UnitTest which makes the code difficult to read. Is there any chance you have a quick tutorial or test code on how to just create a window and add a couple of controls to it? I'll keep working, but if you happen to have the code it would be a time saver. Thanks.
This is important.

I'm no C++ guru, so I'm finding it a bit difficult to use GWEN. Where do I start? Do I have to create an instance of this or that first?

A bit of sample code would be really helpful.
 Post #37
 6th February 2010
jsharbour's Avatar
February 2010
11 Posts
This is important.

I'm no C++ guru, so I'm finding it a bit difficult to use GWEN. Where do I start? Do I have to create an instance of this or that first?

A bit of sample code would be really helpful.

I've compiled GWEN and the UnitTest libs, set up VS2008 directories, added all the includes & libs to my DX9-based engine, and by following the unit test example project, added all the initialization code to get UnitTest up & running, got the skin in the right place, but it crashes on the UnitTest constructor (debugging reveals the crash occurs on the BaseClass() call). I'm certain it's due to my failure to initialize some component correctly.
 Post #38
 6th February 2010
Dennab
April 2009
831 Posts
A bit of sample code would be really helpful.
My bad.

I just found the Samples directory...
 Post #39
 6th February 2010
Dennab
April 2009
831 Posts
I'll get working on a C# wrapper library
I got around to starting, and I've compiled GWEN as a .net assembly.

There's stuff to fix however, the assembly may be .net, but all the types are native.



The underlined parts are things that I need to fix.
 Post #40
 6th February 2010
garry's Avatar
September 2001
10,878 Posts
All good points. I'll look into the renderer thing soon - we were planning on adding some more functionality to allow the drawing of gradients - so I will look into it when I go to do that.

As for a high level tutorial/example - yeah - that is pretty important I guess.

Basically what you need to do is create a canvas, then you can add controls to it. I should put a tutorial up for this. I'll look into doing that - along with the example app.
Reply

All times are GMT. The time now is 06:16AM.

Facepunch Studios 2010 - Server 'MARGE'