Canvas

A place to show off your latest screenshots and for people to comment on them. Only start a new thread here if you have some nice images to show off!
User avatar
Praetor
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 3335
Joined: Tue Jun 21, 2005 8:26 pm
Location: Rochester, New York, US
x 3
Contact:

Post by Praetor »

Perhaps a two-tiered system would work best. The core imaging functionality so it can be reused easily, and a set of 2D widgets built on top of it.
User avatar
ajs15822
OGRE Expert User
OGRE Expert User
Posts: 570
Joined: Mon Jan 02, 2006 2:05 am
Location: Texas
x 2
Contact:

Post by ajs15822 »

Frenetic wrote:s... so a feature for general texture-size constraints, maybe an error-check or something, would be nice.
Sure, I'll add that in.
And maybe the ability to "reserve()" a certain size ala std::vector.
... Oh, and the fonts in my app are (supposed to be) user-customizable. Dynamically regenerating the fonts shouldn't be too hard, right? (This feature does not need real-time performance, of course)
Atlas is not dynamic because re-packing potentially invalidates the UV coords within the GlyphInfo/TextureInfo instances. If you *really* need to change your assets, you will need to create new instances of Atlas/Canvas and clear out any GlyphInfo/TextureInfo instances you have accumulated (like in a text-layout cache, for example).
I suppose I can use several Canvas+Atlases if I expect to be using a crap-ton of textures? I'll probably replace my own GUI-drawing code with this (improving my own code would be re-inventing the wheel now) and I have lots of fonts and text, lots of background images, lots of icons, etc. so going beyond the max texture size my card supports is almost certain.
Yes, you could use several Canvas+Atlas instances in the same viewport-- just be aware that the z-order of each layer within a Canvas is independent of the z-ordering of another Canvas.

Also, I really recommend attempting to minimize your texture assets by taking advantage of Canvas's tiling capabilities. Any textured fill that is smaller than the rectangle it fills will be tiled. For example, say you had a fancy little dialog box with rounded corners:

Image

Instead of slapping the entire background into Atlas as one texture, you could slice the unique parts up. (This comes with the added bonus of dialog resizability)

Slicing it up gives us eight unique images. The images outlined in red would be tiled horizontally/vertically, depending on the size of the content area. Oh, and as a sidenote: when creating tiling images, try not to make them single-pixel widths/heights because the textures are tiled geometrically-- each new tile means an extra quad. (One of the limitations of texture atlases is that you can't use the videocard's native texture-wrapping/tiling)
Lastly, it bugs me that you don't use the mWhatever member-variable convention... everything else is so far above my highest standards, that this tiny issue stands out... ;)
Sorry about that, it's just my style. ^^;
various ogre users wrote:Thanks.
Y'all are welcome. ;)
scriptkid wrote:As you mention, you wrote it to power simple HUD elements. Does that mean that users should combine your system with a more full-blown system in order to create an options screen or an inventory, for example? Or are you going to add more widget types?
The former is correct-- Atlas/Canvas is simply a tool that Ogre3D developers can use to help create their own custom GUI/HUD/Interface/2D solutions. It is not meant to be an all-in-one HUD/GUI library because I can't predict nor accommodate what everyone wishes to achieve in their own games/applications.
Lord LoriK wrote:Wow, ajs15822! Very good job. Well done, as always.

Suggestions:
* I think quite a lot of the "demo" source should go into the main library. The Document, Element, ImageElement, Parser and TextFlowElement feel like "core" classes, IMO.

* Add text justification to TextFlowElement.

* Add serialization support. Creating an editor with that would be a piece of cake.
I'm glad that you and others like the demo, but I really only designed it as an example of what is possible. (Hence the rather random, 'DancingGraphElement')

If I ever were to create a full GUI library, you'll know. :twisted:
* Multitexture support. Even if this increases the batch count, is the only way to provide nearly limitless flexibility.

* AnimatedImageElement. 'Nuff said.
Could you give a little more detail about what you mean?
* Primitive drawing: point, line, circle, square, polyline. Maybe a fill function, too.
All of these were originally in Canvas in the beginning but I faced a few problems:

* Because the texture-atlas has no padding between elements (for maximum efficiency), aliased geometry bleeds at the edges (regardless of clamp mode).
* I wanted to support clipping but couldn't use the render-system to do it (otherwise, extra batch call). Clipping aligned rectangles (and their complex fills) programmatically is the best I can do. (Otherwise, I'd have to introduce a tessellation dependency)
* Confining the geometry to quads allows me to fully optimize the index buffer and minimize the amount of vertices that need to be updated per render-operation.

I debated with myself for a long while over Spring Break about which direction to take Canvas (performance versus feature-support) and decided to go with performance.
I had to reinstall my system a few days ago, but if I manage to set my development environment soon enough, I'll gladly help with these.
Cool, I'm always looking for more brains.
User avatar
Frenetic
Bugbear
Posts: 806
Joined: Fri Feb 03, 2006 7:08 am

Post by Frenetic »

ajs15822 wrote:Atlas is not dynamic because re-packing potentially invalidates the UV coords within the GlyphInfo/TextureInfo instances.
Hmm. One thing that worries me is that I need to show different icons in my GUI. Because there could be potentially thousands of icons, loading them all at the same time is probably not a good idea. The icons, combined with all the other assets and fonts, means I'll probably want to do something to avoid running out of the 2048x2048 max texture space...
ajs15822 wrote:Yes, you could use several Canvas+Atlas instances in the same viewport-- just be aware that the z-order of each layer within a Canvas is independent of the z-ordering of another Canvas.
Aye. I mitigate the z-ordering problem in my existing code by rendering potentially overlapping things (like draggable windows) in separate batches.

I'm not sure how I'm going to tackle this issue if I use Canvas.
ajs15822 wrote:Instead of slapping the entire background into Atlas as one texture, you could slice the unique parts up. (This comes with the added bonus of dialog resizability)
I already do this. ;)
freegamerblog
Kobold
Posts: 36
Joined: Sun Feb 24, 2008 2:39 pm

Post by freegamerblog »

You might be interested my own 'labour of love' - Vexi. It uses a box model layout to create user interfaces although it's currently Java only. I would like to, eventually, get it running as a library on top of SDL or even one day Ogre (at one point Vexi was compiled to native binaries using GCJ).
User avatar
altren
Gnome
Posts: 329
Joined: Tue Oct 24, 2006 9:02 am
Location: Moscow, Russa
x 24
Contact:

Post by altren »

Really interesting work. I want to talk about Canvas used as GUI basis. I think you can't create fully functional GUI because it can use many different textures (for example lots of icons as Frenetic want) and you can't use it in one batch because you'll need very large textures. Anyway it will be best solution if GUI don't need to show any images and have only it's own skin and fonts.

I realized it when I was thinking about integration your technique in MyGUI. Anyway I like your text formatting and I'm thinking about including it as separate widget (kind of RichText). Just one question: am I right that you generate only used glyphs for different fonts? So it can be used only for infrequently changing text. Otherwise it'll need all possible glyphs packed into Atlas texture.
Image
Lord LoriK
Goblin
Posts: 254
Joined: Tue Feb 13, 2007 5:33 am

Post by Lord LoriK »

ajs15822 wrote:
* Multitexture support. Even if this increases the batch count, is the only way to provide nearly limitless flexibility.

* AnimatedImageElement. 'Nuff said.
Could you give a little more detail about what you mean?
I basically meant to suggest a way to provide a bigger "atlas" (many atlases, if this was done) keeping the texture size limited to 1024x1024 or 2048x2048 to make it compatible. Using many textures automatically would provide extra space to cache fonts, images, etc. The animated element needs no explanation, I guess...
ajs15822 wrote:
* Primitive drawing: point, line, circle, square, polyline. Maybe a fill function, too.
All of these were originally in Canvas in the beginning but I faced a few problems:

* Because the texture-atlas has no padding between elements (for maximum efficiency), aliased geometry bleeds at the edges (regardless of clamp mode).
* I wanted to support clipping but couldn't use the render-system to do it (otherwise, extra batch call). Clipping aligned rectangles (and their complex fills) programmatically is the best I can do. (Otherwise, I'd have to introduce a tessellation dependency)
* Confining the geometry to quads allows me to fully optimize the index buffer and minimize the amount of vertices that need to be updated per render-operation.

I debated with myself for a long while over Spring Break about which direction to take Canvas (performance versus feature-support) and decided to go with performance.
Understood. Maybe the performance versus more features should be selected by the user at creation time, so more complex effects could be achieved only on the more GPU-demanding Canvas?

EDIT: typos in quote tags... D'oh!
Murphy
Greenskin
Posts: 102
Joined: Tue May 10, 2005 11:42 pm
Location: SF, California
Contact:

Post by Murphy »

This is looking great aj!

I have some text rendering I am going to be needing to do soon and this is looking like a nice solution...
xkp
Kobold
Posts: 33
Joined: Thu Aug 18, 2005 12:20 am

Post by xkp »

Very nice work, I develop my own UI http://developers.xkpmedia.com/wiki/doku.php?id=ui and have recently came up with the canvas concept. I have actually designed and implemented using cairo and it doesn't seem crazily difficult to adapt your canvas.
Also, I really recommend attempting to minimize your texture assets by taking advantage of Canvas's tiling capabilities. Any textured fill that is smaller than the rectangle it fills will be tiled. For example, say you had a fancy little dialog box with rounded corners:


This is mst def the way to go, I render my whole UI easily with a 256x256 map.
when creating tiling images, try not to make them single-pixel widths/heights because the textures are tiled geometrically-- each new tile means an extra quad. (One of the limitations of texture atlases is that you can't use the videocard's native texture-wrapping/tiling)
I'll somehow disagree with this one, In order to use the card's tilng I used to keep my tilables in separate textures (horizontal and vertical) but then tried th estretching capanilites (ie drawing a big quad) and works perfectly. Of course only in cases when there is not detail to repeat (like in your fancy dialog)
I'm glad that you and others like the demo, but I really only designed it as an example of what is possible. (Hence the rather random, 'DancingGraphElement')

If I ever were to create a full GUI library, you'll know.
Wonder if may I interest you in joining a mature one :lol:
All of these were originally in Canvas in the beginning but I faced a few problems:

* Because the texture-atlas has no padding between elements (for maximum efficiency), aliased geometry bleeds at the edges (regardless of clamp mode).
* I wanted to support clipping but couldn't use the render-system to do it (otherwise, extra batch call). Clipping aligned rectangles (and their complex fills) programmatically is the best I can do. (Otherwise, I'd have to introduce a tessellation dependency)
* Confining the geometry to quads allows me to fully optimize the index buffer and minimize the amount of vertices that need to be updated per render-operation.
The easiest solutions for the bleeding is to add a pixel on the borders (I don't think 4 pixels are going to kill nobody), as for the tesselation, true is a dependency, but the feature set and possibilities will skyrocket.

I would have to admit it will allow my cairo based interface to be fully implemented :)

Now a few observations of mine:

* wouldn't it make sense to provide custumers with a reference to a specific primitive? it would make sense when you need to update.
* I don't see the need to keep a 1-to-1 relationship between the Canvas and the Atlas, multile atlases will do wonders for many of the problems stated and going from one batch to a few shouldn't hurt performance too much.

Hope that helped a little bit.
db123
Halfling
Posts: 78
Joined: Wed May 21, 2008 5:55 am

Post by db123 »

Hey,Thank you very much,3QY

谢谢您ï¼
Yacoby
Halfling
Posts: 85
Joined: Sun Sep 23, 2007 7:58 pm

Post by Yacoby »

Nice library, I managed to implement it fast and easy into my app :D


(I did steal most of the demo code though)
BloodyFanatic
Kobold
Posts: 26
Joined: Sun Sep 24, 2006 3:41 pm
Contact:

Post by BloodyFanatic »

hi,
one quick question:

is it possible to draw a texture from the atlas rotated? because i'll need it for a speedometer. currently i use ogre's overlays which i want to avoid ;)

thanks in advance
bloodyfanatic
C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do, it blows away your whole leg. (Bjarne Stroustrup)
BloodyFanatic
Kobold
Posts: 26
Joined: Sun Sep 24, 2006 3:41 pm
Contact:

Post by BloodyFanatic »

*bump*

anyone?
C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do, it blows away your whole leg. (Bjarne Stroustrup)
User avatar
ajs15822
OGRE Expert User
OGRE Expert User
Posts: 570
Joined: Mon Jan 02, 2006 2:05 am
Location: Texas
x 2
Contact:

Post by ajs15822 »

BloodyFanatic wrote:hi,
one quick question:

is it possible to draw a texture from the atlas rotated? because i'll need it for a speedometer. currently i use ogre's overlays which i want to avoid ;)

thanks in advance
bloodyfanatic
Currently it is not possible to rotate any element (or draw any non-screen-aligned quad) because of two reasons:
-- texture filtering is disabled to allow the texels to be perfectly aligned with the screen; your rotated texture wouldn't look very nice
-- we use a non-padded texture atlas and so when any non-screen-aligned fragment attempts to sample adjacent texels, we get edge bleeding


If you need true graphic transformations, I would recommend using Hikari instead.
User avatar
Curtaoa
Gnoblar
Posts: 15
Joined: Thu Jan 08, 2009 8:50 pm

Re: Canvas

Post by Curtaoa »

Funny you should mention HIkari, I'm trying to get canvas to play nice with it--

I have only one issue right now and that's getting canvas first in the Z-order. Since Hikari renders to an overlay and Canvas does not, is there even a way to do it at all? Will I have to do something underhanded like render canvas to a different viewport then snapshot its texture and create a 2D overlay with it to accomplish this? or am I completely out in the weeds..
User avatar
ajs15822
OGRE Expert User
OGRE Expert User
Posts: 570
Joined: Mon Jan 02, 2006 2:05 am
Location: Texas
x 2
Contact:

Re: Canvas

Post by ajs15822 »

Curtaoa wrote:Funny you should mention HIkari, I'm trying to get canvas to play nice with it--

I have only one issue right now and that's getting canvas first in the Z-order. Since Hikari renders to an overlay and Canvas does not, is there even a way to do it at all? Will I have to do something underhanded like render canvas to a different viewport then snapshot its texture and create a 2D overlay with it to accomplish this? or am I completely out in the weeds..
Hmm, you could try changing the render queue ID of Canvas to be something higher than the Overlay render queue.

In Canvas.cpp, go to the Canvas constructor definition (should be around line 82), and change it from this:

Code: Select all

Canvas::Canvas(Atlas* atlas, Ogre::Viewport* viewport) : atlas(atlas), viewport(viewport), vertexData(0), indexData(0), 
	bufferSize(100), renderQueueID(Ogre::RENDER_QUEUE_OVERLAY), isDirty(false), visibility(true)
To this:

Code: Select all

Canvas::Canvas(Atlas* atlas, Ogre::Viewport* viewport) : atlas(atlas), viewport(viewport), vertexData(0), indexData(0), 
	bufferSize(100), renderQueueID(Ogre::RENDER_QUEUE_OVERLAY + 1), isDirty(false), visibility(true)
User avatar
Curtaoa
Gnoblar
Posts: 15
Joined: Thu Jan 08, 2009 8:50 pm

Re: Canvas

Post by Curtaoa »

ajs15822 wrote:Hmm, you could try changing the render queue ID of Canvas to be something higher than the Overlay render queue. <snip>
This does indeed do the trick, knew it had to be something simple. Still learning Ogre, thx for the quick answer.
mr_mocap
Gnoblar
Posts: 6
Joined: Tue Apr 10, 2007 6:46 pm

Re: Linux port

Post by mr_mocap »

Fuinelen wrote:First of all, thanks a lot for sharing :)

I'm trying to port it to linux right now (using code::blocks) and I got so far as to only receive this lonely error :

Code: Select all

Canvas - May 12th 2008/Canvas/Source/Atlas.cpp||In member function ‘void Atlas::pack(ComputationVector&)’:|
Canvas - May 12th 2008/Canvas/Source/Atlas.cpp|385|error: no matching function for call to ‘sort(__gnu_cxx::__normal_iterator<ComputationRect**, std::vector<ComputationRect*, std::allocator<ComputationRect*> > >, __gnu_cxx::__normal_iterator<ComputationRect**, std::vector<ComputationRect*, std::allocator<ComputationRect*> > >, Atlas::pack(ComputationVector&)::compare)’|
any ideas what I missed?
Yes. I've run into this before, as I code for both Windows AND Linux. Just add this to the top of Atlas.cpp:

Code: Select all

#include <functional>

namespace std {
template<>
  struct greater<ComputationRect *> : public binary_function<ComputationRect *, ComputationRect *, bool>
  {
    bool operator()(ComputationRect *a, ComputationRect *b)
    {
      return (a->area > b->area);
    }
  };
}

/************************
* TextureInfo
************************/
and change Atlas::pack(ComputationVector& rectangles) to have this first line (and get rid of the struct compare):

Code: Select all

        std::sort(rectangles.begin(), rectangles.end(), std::greater<ComputationRect *>());
I personally prefer to extend the already existing std::greater template to handle things like this. Now you know how. :)

Also, I have attached my Makefile that I created to create Canvas.a. Just put it into the Canvas subdirectory and type "make".

Enjoy!

Code: Select all

# Project
PROJECT_DIR  = .
PROJECT_NAME = Canvas
SOURCE_DIR   = $(PROJECT_DIR)/Source
INCLUDE_DIR   = $(PROJECT_DIR)/Include
OUTPUT_DIR   = $(PROJECT_DIR)/Lib
OBJECT_FILE_DIR = $(PROJECT_DIR)/Objects
OGRE_HOME    = /usr/include

ADDITIONAL_INCLUDE_DIRECTORIES = -I$(PROJECT_DIR)/Include -I$(OGRE_HOME)/include -I$(OGRE_HOME)/include/OGRE -I/usr/include/freetype2

HEADER_FILES = $(INCLUDE_DIR)/Atlas.h $(INCLUDE_DIR)/Canvas.h
SOURCE_FILES = $(SOURCE_DIR)/Atlas.cpp $(SOURCE_DIR)/Canvas.cpp
OBJECT_FILES = $(OBJECT_FILE_DIR)/Atlas.o $(OBJECT_FILE_DIR)/Canvas.o
LIBRARY      = $(OUTPUT_DIR)/$(PROJECT_NAME).a

USER_C++FLAGS = $(ADDITIONAL_INCLUDE_DIRECTORIES)
#

# System
C++                  = g++
C++_ENABLE_FULL_WARN = -Wall -Wno-reorder
PREPROCESS_FLAGS = -I/usr/X11R6/include -I/usr/include/X11 $(STL_INC) -D_LINUX -DFUNCPROTO
C++FLAGS             = -pipe -march=pentium4 $(USER_C++FLAGS) $(PREPROCESS_FLAGS) $(C++_ENABLE_FULL_WARN)
C++COMPFLAGS         = $(USER_C++COMPFLAGS) $(C++FLAGS)
#


all: $(LIBRARY)
        ar -ru $(LIBRARY) $(OBJECT_FILES)
        ranlib $(LIBRARY)

$(LIBRARY): $(HEADER_FILES) $(OBJECT_FILES)

$(OBJECT_FILE_DIR)/Atlas.o: $(SOURCE_DIR)/Atlas.cpp
        $(C++) -c $(C++COMPFLAGS) -o $(OBJECT_FILE_DIR)/Atlas.o $(SOURCE_DIR)/Atlas.cpp

$(SOURCE_DIR)/Atlas.cpp: $(INCLUDE_DIR)/Atlas.h

$(OBJECT_FILE_DIR)/Canvas.o: $(SOURCE_DIR)/Canvas.cpp
        $(C++) -c $(C++COMPFLAGS) -o $(OBJECT_FILE_DIR)/Canvas.o $(SOURCE_DIR)/Canvas.cpp

$(SOURCE_DIR)/Canvas.cpp: $(INCLUDE_DIR)/Canvas.h
mickeyren
Greenskin
Posts: 142
Joined: Thu Dec 18, 2008 11:32 am

Re: Canvas

Post by mickeyren »

Oh wow... I got 6000+ Fps.

Say do you think you can write a wiki on how to use your library so everyone can get a quick start and overview of using your library?

Otherwise awesome work!
User avatar
AshMcConnell
Silver Sponsor
Silver Sponsor
Posts: 605
Joined: Fri Dec 14, 2007 11:44 am
Location: Northern Ireland
x 16
Contact:

Re: Canvas

Post by AshMcConnell »

Hi Folks,

Just wondering if anyone else is getting spikes in performance with canvas?

I have some debug that i output onscreen showing the time different sub-sections of the code is taking, it usually takes 200-300 microsecs, but occasionally it jumps to 20000-40000. Any ideas what could be causing it? Perhaps it could be switching to another process on the PC but it seems to be consistently the canvas update that jumps in time.

Thanks!
All the best,
Ash
mickeyren
Greenskin
Posts: 142
Joined: Thu Dec 18, 2008 11:32 am

Re: Canvas

Post by mickeyren »

Actually Im curious why Canvas can reach Fps as high as 6000 whereas my empty Ogre release build can only reach 3000?
User avatar
ajs15822
OGRE Expert User
OGRE Expert User
Posts: 570
Joined: Mon Jan 02, 2006 2:05 am
Location: Texas
x 2
Contact:

Re: Canvas

Post by ajs15822 »

@mr_mocap:

Thanks a lot for the Linux port!

@mickeyren:

If I find the time, I might write something up-- but for now the documentation in the headers and the demo application should suffice.

By the way, I've also been working on an extensible, data-driven UI library that's totally powered by Canvas. More details about it later! ;)

@AshMcConnell:

By the 'canvas update', do you mean 'Canvas::updateGeometry'? If so, the 'performance spike' you are seeing may be when Canvas rebuilds the vertex buffer due to new draw/clear calls or, more probably, it might be the delay it takes Ogre to lock the vertex buffer from the videocard.
User avatar
AshMcConnell
Silver Sponsor
Silver Sponsor
Posts: 605
Joined: Fri Dec 14, 2007 11:44 am
Location: Northern Ireland
x 16
Contact:

Re: Canvas

Post by AshMcConnell »

First of all, wow, a UI driven from Canvas will be awesome! :)

I should have been more specific, I am calling Document::update() each frame, every so often (from a few secs to 20 secs perhaps - i can't quite see a regular pattern) the time taken to execute shoots up quite a lot. It probably isn't a problem, but if I am doing something silly i'd like to avoid it :)

Thanks again for the hard work :)
All the best,
Ash
Penguin
Halfling
Posts: 83
Joined: Fri Feb 15, 2008 6:39 pm

Re: Canvas

Post by Penguin »

LGPL would mean I'd have to release my source code if I statically linked to canvas? That's pretty much the only reason I probably won't be able to use Canvas. I'd love to be able to use it.
User avatar
KungFooMasta
OGRE Contributor
OGRE Contributor
Posts: 2087
Joined: Thu Mar 03, 2005 7:11 am
Location: WA, USA
x 16
Contact:

Re: Canvas

Post by KungFooMasta »

ajs15822 wrote:@mr_mocap:
By the way, I've also been working on an extensible, data-driven UI library that's totally powered by Canvas. More details about it later! ;)
:shock: :!:
Creator of QuickGUI!
User avatar
ajs15822
OGRE Expert User
OGRE Expert User
Posts: 570
Joined: Mon Jan 02, 2006 2:05 am
Location: Texas
x 2
Contact:

Re: Canvas

Post by ajs15822 »

AshMcConnell wrote:First of all, wow, a UI driven from Canvas will be awesome! :)

I should have been more specific, I am calling Document::update() each frame, every so often (from a few secs to 20 secs perhaps - i can't quite see a regular pattern) the time taken to execute shoots up quite a lot. It probably isn't a problem, but if I am doing something silly i'd like to avoid it :)

Thanks again for the hard work :)
All the best,
Ash
Ah, okay-- I haven't done too much profiling on the Demo code and so there's probably room for optimization with the text-flow algorithm. I'll look into it.
Penguin wrote:LGPL would mean I'd have to release my source code if I statically linked to canvas? That's pretty much the only reason I probably won't be able to use Canvas. I'd love to be able to use it.
Well don't statically link to it then-- just wrap it up in a DLL. ;)
Post Reply