Not logged inGosu Forums
Forum back to libgosu.org Help Search Register Login
Up Topic Gosu / Gosu Exchange / colour, zpos and alphamode
- - By oli.obk Date 2013-03-21 15:54
Hi,

there are Gosu::Graphics::pushTransform for translation, rotation and scaling. Which are the 1st, 2nd, 4th, 5th, 6th, 7th and  8th parameter of Gosu::Image::drawRot.
I have many places where I use these transformations and then end up with several draw calls containing x=0, y=0, scale_x=0, scale_y=0 and only zpos, colour and alphamode.
I'd like to propose severals things:
1. more draw functions with small sets of parameters and all other parameters defaulting
2. Graphics::pushZPos, causing all draw calls until popZPos to use that ZPos (except for draw calls containing a not defaulting zpos)
3. Graphics::pushAlphaMode, causing all draw calls until popAlphaMode to use that alphamode (except for draw calls containing a not defaulting alphamode parameter)
4. same for colour

I'm sure there are many reasons against this idea, but the only ones I can come up with is, that it'll create confusion (imo the current draw calls are unreadable in c++ anyway) and complicate the rendering code (benchmarks should be done to test whether these features would cause a slowdown even if not used)

please discuss :)
Parent - By BlueScope Date 2013-03-21 18:04
I feel that the current way of handling things is, while at points redundant, differentiated enough for the moment. More functions would require more knowledge on the programmer's side, and one thing about Gosu I really apprechiate is the lightweight amount of stuff you ned to learn to get started if you're already with Gosu.
Also, you'd need the current function on top anyways, in case you really do want to use all values at once at some point (backwards compatibility would be a side effect, too).

Instead, if there will ever be a Ruby 2.x release of Gosu, I'd really like to see keyword arguments implemented here instead. This would be even easier in use, as well as not redundant whatsoever.
Parent - - By jlnr (dev) Date 2013-03-22 01:50 Edited 2013-03-22 01:57
scale(5) { img.draw 0, 0, 0  } has completely different performance characteristics than img.draw 0, 0, 0, 5, 5. Transforms work best if they contain a lot of (Z-adjacent) operations as they push and pop OpenGL matrices. The draw parameters work best to draw lots of images with different sets of parameters. The way they are currently being used is just right IMHO (on this board, anyway), and I'd like the keep the separation in principle.

That said...I agree that all the draw parameters are terrible :( I've always wanted to come up with a very lightweight interface like image.rotate(5).scale(2).draw(x, y[, z]), and I think it can be implemented at negligible overhead in C++. Ruby could use keyword args instead.

These solutions as well as the one you are proposing can be implemented 100% on top of Gosu, so considering how distracted I've been in the last months, it's likely that someone else would have time for experimentations and benchmarks before I do... :)

Interface nitpick - pushZPos/popZPos are error prone IMHO, I'm planning to change the Gosu calls to something like scale(5, []{ ... } soon, in beautiful symmetry with Ruby. Yay C++0x!
Parent - - By oli.obk Date 2013-03-22 08:36 Edited 2013-03-22 08:42
I'm using the transforms for rendering a grid.
grid translation and scaling is done with 2 transforms
then every field in the grid gets a transform
inside that i draw the field's background image and all the objects that are inside that field.

>I've always wanted to come up with a very lightweight interface like image.rotate(5).scale(2).draw(x, y[, z]), and I think it can be implemented at negligible overhead in C++. Ruby could use keyword args instead.


such an interface would require every image instance to have it's own member values for rotation and scale and either the rotate/scale functions would modify the original image object or create shallow copies with changed member values.

if you want to do c++11 magic, I have an idea:
image.draw(Rotated(5), Scaled(3,7), LowerLeftCorner(x, y), ZPos(z));
where all the parameters are in fact objects and a variadic template member function Image::draw does some magic.
This will all be done during compile time. if properly done, i'm guessing no overhead to current draw calls (if the compiler optimizes temporary objects properly).
And it would allow cool stuff like ScaleAbsolute(100, 100) making the image exactly 100,100 pixels, no matter what dimensions it has (instead of currently 100/double(image.width()))

>These solutions as well as the one you are proposing can be implemented 100% on top of Gosu, so considering how distracted I've been in the last months, it's likely that someone else would have time for experimentations and benchmarks before I do... :)


I had planned on implementing something myself, I just wanted to figure out what to implement ;) As my original idea now seems stupid to me, too.
Parent - - By jlnr (dev) Date 2013-03-22 10:35

> such an interface would require every image instance to have it's own member values for rotation and scale


image.rotate(5) would not modify the image (immutability ftw) - it would create something like an ImageDrawParameters that might consist of a 2x2 matrix or four points, four colour values and an ImageData pointer. Each method call on ImageDrawParameters would create a new temporary object, and ideally this could also be optimised away, until it is only image.drawWithImageDrawParameters(...).

This only works in C++ because it relies on cheap/free stack objects, whereas Ruby only allocates objects on the heap _and_ has a terrible garbage collector :)

ScaleAbsolute would be great though. For some reason I've never thought about writing a wrapper for that operation.

Your variadic template solution has the advantage that it could be made extensible. The extensible variant of my code would be draw(rotate(scale(image, ...), ...)), yuck! :(
Parent - - By oli.obk Date 2013-03-22 11:15
i just tried something.
i wanted image.draw("scale_x"_fpar = 1.5);, but sadly c++11 doesn't allow templates to process string literals, only numeric literals are allowed :(

the following would have given you compile time string parameters like in ruby.
well… it's still possible at runtime though :P



#include <iostream>
#include <type_traits>

template<typename T>
struct Par
{
    T val;
    Par& operator=(T& v)
    {
        val = v;
        return *this;
    }
};

template<typename T, typename T2>
constexpr bool isOneOf(T t, T2 first)
{
    return (t == first);
}

template<typename T, typename T2, typename... Args>
constexpr bool isOneOf(T t, T2 first, Args... rest)
{
    return (t == first) || isOneOf(t, rest...);
}

template<char c, char... rest> Par<double> operator "" _fpar()
{
    static_assert(isOneOf(c, 's', 'a'), "invalid parameter name");
    switch (c) {
        case 's':
            return Par<double>();
            break;
        case 'a':
            return Par<double>();
            break;
    }
}

int main()
{
    std::cout << ("angle"_fpar = 46.3).val << std::endl;
  return 0;
}
Parent - - By jlnr (dev) Date 2013-03-22 11:40
At that point you could probably just use C99 struct literals :) draw((DrawArgs){ .angle = 5 })

But why not the other way around? image.draw(5_angle) (omg the namespace pollution...)
Parent - By oli.obk Date 2013-03-22 12:05
oh ^^ right forgot about structs

hmm… that would work. the question then is, whether
image.draw(90_degrees, 1.3_scale_x, 100y, 50x, 10z, 0xFF0000_col)
is more readable than
image.draw(Angle(90_deg), Scale(1.3, 1), Pos(100, 50, 10), Color(0xFF0000))

i'm voting for the 2nd.
Also, if duplicate arguments exist, the last one counts, all others are ignored:

image.draw(Pos(100, 50, 10), ZPos(30)) will draw at 100,50 with zpos 30

one more thing:
image.draw<Angle(90_deg), Scale(1.3, 1), Pos(100, 50, 10), Color(0xFF0000)>()
can be guaranteed to be solved at compile time
while
image.draw(Angle(90_deg), Scale(1.3, 1), Pos(100, 50, 10), Color(0xFF0000))
depends on the compiler's abilities
Parent - - By oli.obk Date 2013-03-29 18:12
are you going to force c++11 or will those features be there if c++11 is enabled, and else not?
Parent - - By jlnr (dev) Date 2013-03-30 00:01
It would be good if everything still worked on MSVC2010, and if everything that is necessary for the Ruby port would work on gcc4.0+ (that was the OS X 10.4 compiler - I'd like to target OS X 10.5+ but I'm not sure if that was gcc4.0 or 4.2 or whatever - I'll receive my 10.5 oldtimer machine in May :))
Parent - - By oli.obk Date 2013-03-30 18:10
a quick search turned up that it's nearly impossible from inside a c++ file to detect c++11 support in a portable way.
so there's gonna be some magic in Gosu/Platform.hpp that checks compiler versions and compiler specific defines.
Parent - By jlnr (dev) Date 2013-03-31 02:14
...not much worse than what I have to do in TR1.hpp already :)
Parent - By oli.obk Date 2013-04-01 19:18
ok, this got a little out of hand, but here's my c++11 branch on github.

everything still works when you disable c++11 on gcc. the changes I made in parts that are not wrapped in #ifdef GOSU_CPP11_ENABLED all seem very harmless to me when considering old compilers or msvc.
the c++11 features I added *should* work on msvc2012 (the msvc version is checked before deciding whether to enable c++11 features, but msvc has some trouble with variadic templates)
some things I changed are not really c++11 issues, but things that suddenly are warned about or don't compile with c++11's c++ std lib.

i added Image::draw(x, y, z, …). Image::draw(...) now simply calls Image::draw(0, 0, 0, ...)
"..." may be either an AlphaMode, a Color or anything that inherits DrawModifier, but currently the possible classes are hardcoded

the extensible version I can think of would still inherit from DrawModifier, but supply a function taking x, y, z, c1, c2, c3, c4, scalex, scaley, offsetx, offsety, rotation, alphamode as reference parameters and changing one or more of them.
the following would be a DrawModifier that would keep all previous modifiers but shift the object 10 pixels to the right

class Test : public DrawModifier
{
public:
    void apply(double&x, double&y, double&z, Color& c1, Color& c2, Color& c3, Color& c4, double& factorX, double& factorY, double& angle, double& centerX, double& centerY, AlphaMode& am)
    {
        x+=10;
    }
};


other user-extensible ideas?
Up Topic Gosu / Gosu Exchange / colour, zpos and alphamode

Powered by mwForum 2.29.7 © 1999-2015 Markus Wichitill