paeryn / openvg

Tools for exploring OpenVG
Other
11 stars 2 forks source link

extension request: Pixel(x,y) or Dot(x,y) API function #8

Open tofrnr opened 8 years ago

tofrnr commented 8 years ago

hello, it would be very wishful to have also a Pixel(x,y) or Dot(x,y) API function (draw a dot at (x,y) by StrokeWidth() ), will that be possible ?

paeryn commented 8 years ago

It is sort of possible to draw a single pixel by drawing a circle of width 1 with it's centre offset by (+0.5,+0.5) but make sure you have stroke width set to 0 (stroking will cause extra pixels to be filled). The downside is that drawing circles is expensive (it takes time to tessellate the 2 arcs used). This can be reduced by giving the driver the chance to cache a tessellated circle using the CirclePath() function to generate a circle only once (the normal Circle() function has to regenerate the path each time).

The offset is needed because openvg works on pixel centres, and when you give a position of say (10,10) you are actually referencing the bottom left corner of that pixel. So if you don't draw the circle from the centre of the pixel then you end up with the circle extents from (9.5,9.5) -> (10.5,10.5) which is why it draws 2x2 pixels, (9,9), (9,10) and (10,9) as well as the intended (10,10)

I did a bit of testing for this last night, I haven't checked how well it handles scaling but if it doesn't work as expected you could always create separate paths for various dot sizes. (Needs the later versions of my fork (V1.3, newfonts, windowsave), not the earlier ones).

// Declare pixel_dot to be a single pixel circle path
// already offset by (0.5,0.5) so you don't have to when drawing it.
VGPath pixel_dot = CirclePath(0.5f, 0.5f, 1.0f);

// Draw the dot at (xpos, ypos)
StrokeWidth(0); // Make sure stroke is off
DrawPathAt(xpos, ypos, pixel_dot);

// Delete path when no longer needed
DeletePath(pixel_dot);

I'll look into it more when I have time and try and make a tidy version that handles all cases.

tofrnr commented 8 years ago

thank you, I already was thinking about Line(x,y, x,y) as a workaround but didn't test it so far. I thought it must be quicker to just put a single pixel nevertheless.

paeryn commented 8 years ago

Line(x, y, x, y) won't work, it sees that as a zero length line and doesn't draw it.

Single pixels are awkward as things change when you translate/scale the coordinate system.

tofrnr commented 8 years ago

re: "Single pixels are awkward as things change when you translate/scale the coordinate system." more akward than e.g., Line(x, y, x, y+0.5) perhaps? That's awkward ;)

paeryn commented 8 years ago

You could try it, last time I played around with it it went from drawing nothing to a 1x2. But then my circles didn't work then either (I probably forgot to switch the stroke off back then). I won't have chance to play with it until late tonight at the earliest. It depends on what you want your dot to look like scaled up, a nice circular dot or a rectangle?

tofrnr commented 8 years ago

if round or rectangle doesn't matter, main thing is: coding as simple as possible providing a dot painting performance as fast as possible. But it's finally by far not an urgent thing, I just came upon this missing feature randomly. Probably in a few weeks, after the summer vacations, it would be useful if the dot function will be available then. Thank you very much for your answeres!

paeryn commented 8 years ago

Just checked, it was stoking that was messing up my previous attempts at single pixel drawing (at least for non-transformed drawing - i.e. no scaling/transforming). Although normal drawing with a stroke width of 1 extends shapes by a pixel left or down (due to the centre offset) you can sort of bypass it by adding 0.5 (a horizontal line gets drawn 2 pixels high if given integer coordinates, but adding 0.5 to it's y coordinates will make it 1 pixel high).

So to draw a single pixel at (10,10) you could use Line(10,10.5, 10.5, 10.5) with a stroke width of 1 Or you could use a rectangle Rect(10, 10, 1, 1) with a stroke width of 0 (if you have stroke width set to 1 and draw a 1x1 rectangle you'll get a 3x3 or 2x2 if you offset the x & y by 0.5).

These should give you square points when scaled up rather than the round points of using circles. I'd prefer the rectangle method as it's less of a hack but it means dots would be subject to the fill paint rather than the stroke paint.

tofrnr commented 8 years ago

re: "Or you could use a rectangle Rect(10, 10, 1, 1) with a stroke width of 0" thank you, I think I'll take that for a workaround then. A little complicated is to have to set and reset the strokewidth, i.e. one has to intermediatly store the current one, set it to 0, then reset it to the previous again, but anyway, perhaps you might wish to make that clean one day in the future... ;) thanks for your replies!

paeryn commented 8 years ago

I've updated the windowsave branch with a few typos fixed (there was an error in RoundRect) and a new function

void Dot(VGfloat x, VGfloat y, bool smooth);

This should draw a 1 unit dot with it's lower-left extent at (x,y). smooth determines if it draws it as a circle or a rectangle. If you use Scale() it will zoom in properly (if you keep to the default scale then there's no visible difference between smooth and non-smooth), Note that the (x,y) position is after any transforms you have made so is equivalent to Circle(x+0.5, y+0.5, 1) or Rect(x, y, 1, 1)

This should be faster than using Circle() or Rect() directly, and equivalent to the CirclePath() or RectPath() method I said above (which is what it basically does). It also doesn't use stroke, it only fills so you don't need to do a StrokeWidth(0) before drawing it.

tofrnr commented 8 years ago

that's great, thank you very much for your efforts! How can I uninstall my old version before I install the most updated openVG version l to avoid competing installation paths and folders?

paeryn commented 8 years ago

From which version are you coming from? If from ajstarks' original (and what my master is based on) then it's a little tricky. The new version installs over the top, it should leave the old libshapes.so.1 library for use by old programs compiled against it, but unfortunately programs that were compiled against it aren't told to use .1 specifically (ajstarks' original doesn't set the soname in the library) so they will always try to link to the latest installed. Plus the header files will be overwritten with the new ones so you won't be able to directly compile against the old version without keeping a copy somewhere.

There are a few slight changes which make my version incompatible (some internal changes especially to how Font data is passed), which means code compiled for the original will fail without being re-compiled against my new versions (V1.2, V1.3, newfonts, windowsave).

If you need to keep the old version you can always just not do the final make install step and point the compiler to the headers and object files directly (that's how all the demo files in client/ are compiled). I really must get around to handling it better.

tofrnr commented 8 years ago

I have your version, it's a few months old, how can I get my current version number?

paeryn commented 8 years ago

It gives instructions at the bottom of the README shown on the main page under the section Buid and Run. Just substitute git checkout windowsave where it says git checkout newfonts for the current latest. Or if you just want to download the zip file select the windowsave branch from the button on the top left of the home page and then select download zip from the botton on the right.

tofrnr commented 8 years ago

the current instructions to install are very complicated and hard to understand - I prefer a completely uninstall and a completely new installation. And all the steps are not described clearly enough in build and run - far too many words which muddle up the pure instructions which are actually needed, which is the same as ajstarks once wrote.

I did it that way:

sudo apt-get install libjpeg8-dev indent libfreetype6-dev ttf-dejavu-core libfontconfig1-dev

git clone git://github.com/paeryn/openvg

# git checkout newfonts
# now, updated: 
git checkout windowsave

cd openvg
make
./shapedemo demo 10             
make library
sudo make install

# cd openvg
cd client
make test    

Is that still correct? I have absolutely no idea what all these git and make thinks do, I just follow them step by step and hope they'll work as expected in that entire "installation black box". (I actually love the Windows idea of having just a single "setup.exe" which does all the magic things, all at once.)

But first of all I want to erase the old installation completely ("uninstall.exe") - so how to do that? And: how can I get my current version number?

paeryn commented 8 years ago

If you've already cloned the repo beforehand then you should be able to do a git fetch origin (I think) to sync your local version with the repo rather than cloning it again. Then do the checkout to make that branch current.

You can uninstall the old version first it you want with make uninstall But it doesn't matter if you don't as the new version will overwrite the old installation.

git branch Should show you which branch you are on (I think it lists all but the current one is starred).

Other than that the build instructions are the same (although you listed ./shapedemo in the wrong place, that's available after doing make in client/ )

tofrnr commented 8 years ago

thank you, but I don't know waht that means and what I have to do then:

git fetch origin => what is this? checkout to make that branch current => => how? make uninstall => => called in which directory? git branch - what is a branch? /shapedemo in the wrong place, that's available after doing make in client/ => => so how shall I do that?

which is the complete and correct list of commands like?

paeryn commented 8 years ago

git fetch origin should update your local copy of the repo with the latest that I uploaded (call it from the main directory). Only works if you have already cloned the repo.

make uninstall from the main directory that you would have done make install from.

git branch call that from the main directory and it will show you which branch you currently have checked out (which version of the code the files belong to, when you checkout a branch all the code updates to that version).

You showed running ./shapedemo right after running make in the main directory but ./shapedemo isn't in that directory and won't be made by that make. When you cd client and run make from there then ./shapedemo is available in that directory.

tofrnr commented 8 years ago

i don't know what I have or have not. github is really weird and my English is very shaky. Google translate don't help neither. Is there no simple sudo apt-get install?

I also don't know from which directory I have once installed. I just opend the LX Teriminal and typed one command after the other, I didn't look at main directory names. Perhaps pi or so.

As I still don't understand what I have to do in detail, could you please correct and update just this list?

Now the first step should be uninstall all about the current version:

sudo apt-get install libjpeg8-dev indent libfreetype6-dev ttf-dejavu-core libfontconfig1-dev

git clone git://github.com/paeryn/openvg
git checkout windowsave

cd openvg
make
./shapedemo demo 10             
make library
sudo make install

cd client
make test
paeryn commented 8 years ago

If you want to do a total clean install... (I just noticed I forgot to add to the README about needing to install libpng12-dev as well as libfontconfig1-dev, the others should already have been installed from previous)

Uninstall current version (renaming the openvg directory so you can keep it just in case)

cd openvg
sudo make uninstall
cd ..
mv openvg openvg_old

sudo apt-get install libjpeg8-dev indent libfreetype6-dev ttf-dejavu-core libpng12-dev libfontconfig1-dev
git clone git://github.com/paeryn/openvg
git checkout windowsave
cd openvg
make
sudo make install

make library isn't needed as make install will do it automatically anyway. If you want to compile the demo programs then after the above

cd client
make all
make test

**make test** will compile the **./shapedemo** program and run it.
tofrnr commented 8 years ago

thank you, that's much more clear now. Why do I have to rename mv openvg openvg_old ? Why is there a need to keep it? Which important things are stored in there which cannot be provided by the new version? (I actually just want 1 single version which works reliably) So why shouldn't it be deleted?

another question: has it changed what a progam has to include

#include "VG/openvg.h"
#include "VG/vgu.h"
#include "fontinfo.h"
#include "shapes.h"

and because including font types into programs has changed to dynamical including, is it still the same for writing text by fonts, e.g., Text( x, y, strbuf, SerifTypeface, 10);

tofrnr commented 8 years ago

so I would assume: old openVG can be deleted and all the rest stays as it was before.