Monday, January 2, 2012

Enesim does OpenGL

Finally I got some time to start implementing the OpenGL backend interface on the renderer side. On the surface side, it was already possible to create surfaces with a GL texture associated using the OpenGL Enesim's pool but we were missing renderers.

Right now only simple renderers are implemented through fragment shaders. Mainly: stripes, checker and background. The approach is to always use shaders, being it geometric, fragment or vertex, I'm working on implementing geometric shaders for the different shapes but I don't have the hardware that supports it, so I suppose it will have to wait .... but good things will come in the future, like having a full GUI (Eon) done on OpenGL or rendering SVG files (ESVG) with full hardware acceleration

Anyway, here is a screenshot, everyone loves screenshots! Here is a simple GLX window displaying a surface which was previously rendered with a stripes renderer which is  rotated.


Tuesday, December 13, 2011

Esvg, Ecss

Sometime ago I started creating a library for SVG parsing and rendering. It was called Esvg. The initial version didn't do much, it was just using cairo to actually draw the different SVG tags. Now, a new version of Esvg has arrived into Enesim's repository, thanks to Vincent and his great effort to make this library a success.

The main ideas we had in mind for this library were:

  1. We should not only parse the SVG tags and render them, but create a fully statefull scene of SVG elements where you can manipulate each element by a C API, change the properties, make an element be a child of another, etc.
  2. Make every SVG element an Enesim Renderer, this way we can use all the already available stack (Escen, Ender, Emage ...) to interact and manipulate such elements.
  3. Create a simple parser for the SVG tags but make it optional in a sense that the rendering elements can be created without the need of an existing XML file.
So far all our goals have been achieved, even if the results are not graphically perfect it should be straightforward to fine tune it. This also helps the Enesim project reach its final 1.0 release.

In the process of building this library we required a CSS parser too, the options out there did not satisfied us, we needed a CSS parser which will let us (from the library's user point of view) provide an implementation of the DOM interface. That is, a way to traverse the tree: getting a tag's parent, its childs, its sibling, etc to match the CSS rules easily and be able to apply this library not only for SVG based XML but for any other tree based library as long as it provides such interface.
Another requirement was that the CSS library must not assume that every tag or property is HTML only, but any kind of tag name or attribute definition. I mean, the library should be DOCTYPE agnostic.

Sadly the above requirements were not met by any library, so we decided to create our own: Ecss, which of course has all the above features.

As a simple example of what the library can do, check out this SVG example parsed by our library and rendered using Emage into a PNG (the rendering is not perfect but is a very good start):


Sunday, August 14, 2011

Evoak?

About 6 years ago I wrote a post about Evoak, reading it I noticed how bad my posting abilities are (not that Im good now either) because there was no exaplanation on what my goal was, it was a post of about the status of something and I suppose is difficult to valorate a milestone whenever you dont know the final goal. On that time I was really fascinated about the evoak concept but was scared of the amount of work it was needed given the Evas unstability and Edje emerge. How to code such a great idea when you know your work will be uselss two months later?

I used Evoak on my final project on the univserity, it was a real success and for me it was enviosining a different approach to the classic server-client we had on that time (and still now), X11. This topic might be taken care off on another post.

Six years later and a complete different set of libraries and tools I'm able to code again that idea. The responsible of such possibility is Ender. When I started creating Enesim, Emage and several other libraries my main goal was to actually replace some of the bits of the current EFL stack specially Evas, to be able to improve and advance with new and good technical ideas. From the current state of EFL I would say that both projects are riding its own road for now, who knows later ... The situation was that I was trying to create some kind of object system or better, a description system which will allow me to serialize properties and values easily, if I were able to create a toolkit/canvas library using only properties and values then the next step, that is, send those properties through the network, would be easy and the Evoak concept could rise again.

That moment has arrived. Everything is still on an alpha status (everything is just a proof of concept) but the idea is working. Right now, with Eon being a toolkit system with objects I can create and manipulate on a generic way (through properties, values and events) I was able to create such network bridge to serialize the widgets data through the network and create a server which shows those applications without any change. If you take a look on the ecore_remote backend of Eon and the eon_server application on the Enesim repository you'll see the actual implementation. This is a very good milestone on the idea I wanted to accomplish: bring Evoak back! :)

Friday, August 12, 2011

Enesim Renderer Compound Tutorial

Now that you know how to create renderers and draw them into a surface as seen on the previous post, now we will see how to achieve the image below only using Enesim renderers, no images are allowed! Thanks Jose for the example code.



I'll update this post as soon as I have time ...

The complete code can be found here

Enesim Tutorials

This is the first post in a series of tutorial posts for every component on the Enesim project. From Enesim itself to Eon. On this first tutorial we'll learn how to draw this sample image:



The first step is to create the renderer we want to draw. A renderer is just an abstraction of something that draws, nothing else. It can be a rectangle, a circle a gradient or even a bubble, as long as it draws something we are fine. This is the main difference between Enesim and other graphics libraries, on Enesim there's no concept of graphics primitives or texturizing, every renderer is both a primitive and a texture.

Let's begin by creating our rectangle renderer

Enesim_Renderer *r;

r = enesim_renderer_rectangle_new();

The Enesim_Renderer design in a way has an object oriented approach. Every renderer inherits from the base Enesim_Renderer type and so, you can use the generic renderer API to set generic renderer properties. Also note that a rectangle renderer also inherits from a shape and again you can use all the shape API. More on this later.

Now let's set some common properties

enesim_renderer_origin_set(r, 15.0, 15.0);
enesim_renderer_rop_set(r, ENESIM_BLEND);

In the above code we are setting the renderer origin to 15 on the X axis and 15 on the Y axis. The important thing here is to understand that every renderer has it's own coordinate system and by setting its origin you are actually translating its center by 15 units.

The rop property is the raster operation. Setting it, informs the system how it should be drawn on a target surface. In this case we are waying that we want to blend the renderer with what is already on the surface.

Now lets set some rectangle properties

enesim_renderer_rectangle_width_set(r, 128);
enesim_renderer_rectangle_height_set(r, 128);
enesim_renderer_rectangle_corner_radius_set(r, 15);
enesim_renderer_rectangle_corners_set(r, EINA_TRUE, EINA_FALSE, EINA_FALSE, EINA_TRUE);

The rectangle renderer can have rounded corners, with the above code we are setting the top left corner and bottom right corner to be rounded with a radius of 15. Note that the rectangle renderer uses the origin property as the start of the rectangle, that means that right now we will draw a rectangle of with 128 and height 128 starting at 15 on the X axis and 15 on the Y axis. But what about filling? and stroking?

Given that a rectangle inhertis from a shape, you can use all the shape API to set more properties.

enesim_renderer_shape_fill_color_set(r, 0xff00ffff);
enesim_renderer_shape_stroke_color_set(r, 0xffff0000);
enesim_renderer_shape_stroke_weight_set(r, 3.0);
enesim_renderer_shape_draw_mode_set(r, ENESIM_SHAPE_DRAW_MODE_STROKE_FILL);

So now we are setting the fill color to ARGB(255, 0, 255, 255) the stroke to ARGB(255, 255, 0, 0) and the width or weight of the stroke to 3. Even if those properties are set, it does not mean that we will actually draw with such fill/stroke configuration. We need to set the drawing mode we are going to use, being it fill only, stroke only or both. For this case we will use stroke and fill. Note that we are not using any alpha different than 255 (i.e full opaque) to simplify this description. Every color used on Enesim has to be premultiplied by its alpha, but no worries about that, we do have some helper functions that transform an ARGB value to a premultiplied ARGB value.

Now that we have all the renderer set up, we want to actually draw it. For that we create an Enesim_Surface. A surface is just a pixel area where you can actually draw your renderer. On some systems this is called Drawable, on other Pixmaps or Textures.


Enesim_Surface *s

s = enesim_surface_new(ENESIM_FORMAT_ARGB8888, 256, 256);


So, you have created an ARGB surface with 8 bits per component of size 256 x 256. Now the real drawing


enesim_renderer_draw(r, s, NULL, 0, 0);

Note that we haven't set all the parameters for simplicity. But I will explain them too. The first argument of course is the renderer you want to draw and the second one the target surface you want to draw, those were easy. The third one defines the clipping area you want to draw on the destination surface and the last two is the origin of the destination surface. Remember that every renderer has it's own coordinate space? in this case a surface does have it too. It is always from 0 on the X axis and 0 on the Y axis and the width and height are the same as the surface width and height. With the two last arguments you can translate the surface origin, but to make this initial tutorial simple we wont describe the whole functionality, yet! :)

The complete code can be found here

Saturday, August 6, 2011

Enesim does OpenCL

This was something I had in mind for a long time, not neccessary OpenCL but an usable way to make a "backend" system for renderers and surfaces/buffers. That moment has arrived. Right now the enesim code has a well defined backend system and an incipient OpenCL support. Given the nature of a renderer each one should provide each own OpenCL algorithm but at least Enesim provides a good abstraction to define such algorithms and interact with them.

The pool subsytem has been refactored in a way that a pool should create surfaces or buffers and define its backend type. Given that, once a renderer element wants to draw into a surface, we can call the correct functions based on the backend and the associated data of a surface.

Still there are things to do on Enesim and specifically on other subsystems of the library (like being able to make converters use also the backend system, like having a YUV422 -> ARGB converter on OpenCL or stuff like that), but is a very good step on the road of the 1.0 release. The only implementation of an OpenCL renderer is done on the "background" renderer given its simpleness, but is a good start to understand how OpenCL works and what common arguments are needed for every renderer.

Later, with this approach, we can easily add an OpenGL shader approach for renderers and a texture based software pool :)

Tuesday, July 19, 2011

Threaded rendering

The enesim stack has been actively developed on the past months, we have lots of new features and new design concepts but this post is about threaded rendering. Recently a threaded rendering path has been committed into enesim given outstanding results, for examlple running the benchmark application with the circle.escen example we have:

Without threaded rendering

./benchmark -f ../../examples/circle01.escen -d -t 10000
../../examples/circle01.escen [15.375 sec]


And with threaded rendering

./benchmark -f ../../examples/circle01.escen -d -t 10000
../../examples/circle01.escen [4.948 sec]


This test was done on a quad core CPU and the gain is around 3x, of course the gain depends on the actual renderer to draw, the more complex the better.