ENIGMA Forums

Contributing to ENIGMA => Proposals => Topic started by: TheExDeus on July 28, 2013, 08:25:05 am

Title: Vertex color
Post by: TheExDeus on July 28, 2013, 08:25:05 am
Hi. I just noticed that vertex color was not implemented. This effectively broke many model functions and all primitive functions. I then implemented color buffer, but what do we do about these cases:
draw_vertex() - I made it use bound color and alpha.I think that was how GM did it, but now I am not sure. Will check when I have the chance. Confirmed, this is how it's done in GM.
d3d_model_vertex() - Should this also use bound color and alpha? Problem is that default bound color is black. As examples in EDC which run in GM doesn't set any color to white before adding the vertexes, then I belive it doesn't use bound color and alpha and just uses c_white and 1.

1) So should we use bound color and alpha or just set everything to c_white and 1?
2) Should we just not bind color buffer at all if color is not used? It didn't seem to work in draw_primitive() case, but it works in d3d_model case. I made a bool which turns to 1 when color function is used. Otherwise it's 0. Question is also if its faster. We do use less memory and I guess model building is faster as it doesn't send useless data to GPU. So maybe this bool method is better than filling vector with c_white and 1.0 all the time (which is extra 4 gs_scalar's for every vertex).   

edit: I just tested and here are some clarifications:
1) GM uses bound color whenever no color is specified. So draw_vertex(), d3d_vertex(), d3d_model_vertex_texture() and so on just use bound color. It never defaults to 1 or c_white.
2) It uses this color when drawing, not when the vertex is added. So when d3d_model_vertex_color() is used, then it bounds color to that vertex at that point. But if d3d_model_vertex() is used, then it defaults to the set color when d3d_model_draw() is used. We cannot really replicate this behavior if we use VBO, as it would require us to loop vertexes and such. We could maybe use glTexEnvf to achieve this, but it would work on all vertexes and not only the changed ones.
I made changes to replicate the 1. part, but it will break the bool fix that I added now and it would break some compatibility. Like the cel shading example at EDC wouldn't work (as all the models would default to black) and it would have to be modified.

edit2: I can also actually make it work for 2) by using the bool fix differently, but then it would break in another case when vertex functions are used interchangeably like this:
Code: [Select]
draw_set_color(c_red);
draw_set_alpha(0.5);
draw_primitive_begin(pr_trianglelist);
draw_vertex(10,10);
draw_vertex_color(100,10,c_green,1);
draw_vertex(100,100);
draw_primitive_end();
In GM this would draw a red transparent triangle with one solid green corner. In ENIGMA it would do the same, because the model is rebuilt all the time. But if d3d_model's are used like this:
Code: [Select]
//Create
model = d3d_model_create();
d3d_model_primitive_begin(model,pr_trianglelist);
d3d_model_vertex(10,10,0);
d3d_model_vertex_color(100,10,0,c_green,1);
d3d_model_vertex(100,100,0);
d3d_model_primitive_end(model);

//Draw
draw_set_color(c_red);
draw_set_alpha(0.5);
d3d_model_draw(model,0,0,0,-1);
In GM this draws the same as the previous code. In ENIGMA this would break right now. It would break because d3d_model_vertex wouldn't add anything to color vector (and useColorBuffer would be false), but d3d_model_vertex_color would add the color and alpha to the color vector and would set useColorBuffer to true. That means the d3d_model_draw() would bind the color buffer and would think it has 3*4 floats in it (RGBA for every vertex), while in reallity there would be just 1*4.

If I fix this by making d3d_model_vertex add bound color and alpha, then it wouldn't be buggy, but it would draw differently. The code would draw a black solid triangle with one green corner. The bound color and alpha wouldn't change anything at the point d3d_model_draw is called.
I can fix this by using useColorBuffer bool. So make it add bound color and alpha if d3d_model_vertex is used, but don't bind it to VBO if only d3d_model_vertex's are called and no color functions. This would make examples on EDC work (as they only use d3d_model_vertex or d3d_model_vertex_color and not both together), but it wouldn't work like GM in cases where they are both used together.
Title: Re: Vertex color
Post by: forthevin on July 29, 2013, 06:04:57 pm
I like the solution where it draws the same as GM as long as only one of d3d_model_vertex and d3d_model_vertex_color is used. For those cases where the functions are mixed, I think it is fine if we deviate from GM in regards to how it is drawn, as long as it does not crash and we document on the wiki that we don't give any guarantees about the drawing if d3d_model_vertex and d3d_model_vertex_color are mixed. Mixing color and non-color is IMO tricky and unintuitive, and I believe the vast majority of usage do not mix the two functions.
Title: Re: Vertex color
Post by: Goombert on July 29, 2013, 07:03:27 pm
Actually son of a bitch, I never thought about this, yeah I know what you mean now Harri, I was wondering the same thing for multiple texture coordinates with my OpenGL3 mesh class, because we also need to expand on the base model API from game maker to support multitexturing and material surfaces anyway. Now another thing, with Studio adding shaders they are also adding vertex specification functions that allow you to define a custom spec and send it to the shader, idk much about it yet, but its on their technical blog, we need to read up on that some as well.

And Harri, halp me with DX ~ :)
Title: Re: Vertex color
Post by: TheExDeus on July 30, 2013, 04:08:14 am
Ok, then I will just implement it to work if the functions are not mixed. Because I really cannot fathom how GM does it as it's not really possible by using buffered geometry. Maybe it changed in GM:S though and it no longer works like in GM8 I tested. It is possible with shaders though. Adding a shader param to all vertexes which basically tell it if it's bound color or set color. I do like this GM possibility though, because even without using shaders or changing textures you could color units in an RTS by just using:
Code: [Select]
//Draw red tank, but it could have other colored parts and even textures as well
draw_set_color(c_red);
d3d_model_draw(tank,0,0,0,tank_texture);

//Now draw blue tank, but some parts could be the same as the red one
draw_set_color(c_blue);
d3d_model_draw(tank,0,0,0,tank_texture);
Title: Re: Vertex color
Post by: Josh @ Dreamland on July 30, 2013, 05:55:20 am
We need to do something about that. The options are to waste space for each vertex format or to allow specifying vertex formats manually (as Yoyo has already done; didn't think they had it in them).

If the vertex format specifies draw color, and no draw color is supplied to create it, the current draw color should be used. It's that simple.

What we should do is just mimic their vertex format functions and then construct the d3d_model_ API around that. So d3d_model_vertex_color() would just be a wrapper to whatever new primitive function they use. That function would deal with passing the current draw color to the vertex format if not otherwise specified. The only issue with that is the default draw color of black; in general, the color will have to be white if they want their models to look right.
Title: Re: Vertex color
Post by: TheExDeus on July 30, 2013, 06:36:29 am
Quote
We need to do something about that. The options are to waste space for each vertex format or to allow specifying vertex formats manually (as Yoyo has already done; didn't think they had it in them).
How does GM allow specifying vertex formats manually?

Quote
If the vertex format specifies draw color, and no draw color is supplied to create it, the current draw color should be used. It's that simple.
This is what I am going to make it do now. The problem is that it is not how GM does it. GM uses bound color right before the model is drawn, not when it is created. That is a problem for us, as we use buffered geometry. If we don't bind color buffer before drawing the model, then OGL uses immediate mode color (which is set via draw_set_color), but we cannot mix and match them. We cannot bind a color buffer and yet for some vertices make it use bound color outside buffer. That could be possible with shaders by adding a bool to vertex (which I think is possible) that specifies to use bound color or set color. We can still get 95% compatibility which would cover like all cases but the ones where the functions are mixed.
Title: Re: Vertex color
Post by: Josh @ Dreamland on July 30, 2013, 07:02:40 am
Quote
How does GM allow specifying vertex formats manually?
Code: (GML) [Select]
vertex_format_begin()
vertex_format_end()
vertex_format_add_position()
vertex_format_add_position_3d()
vertex_format_add_colour()
vertex_format_add_normal()
vertex_format_add_textcoord()
vertex_format_add_custom()

Notice the UK spelling of color, inconsistent with the other spellings in GM. Can't tell if that's deliberate.

Quote
The problem is that it is not how GM does it.
Originally, it probably used the equivalent to GL lists in DX. Meaning it was purely an accident—the FFP expected everything to be in the format which was not disabled expressly. So it automatically assigned vertices the current color. This is likely not something Mark coded deliberately. You could use drawing color to work around GM6 Lite not having draw_vertex_color, but still having draw_vertex. Quite funny.

To emulate it outside the FFP, use draw_get_color().

EDIT: You seem to be under the impression that the currently bound color affects model vertices. That shouldn't be the case if they're in a VBO. In this case, all points will be blended by the current draw color, regardless of their own color or texture.
Title: Re: Vertex color
Post by: TheExDeus on July 30, 2013, 09:26:13 am
Quote
Notice the UK spelling of color, inconsistent with the other spellings in GM. Can't tell if that's deliberate.
Never knew of such functions. Must be new to GM:S. Will check their docs later.

Quote
EDIT: You seem to be under the impression that the currently bound color affects model vertices. That shouldn't be the case if they're in a VBO. In this case, all points will be blended by the current draw color, regardless of their own color or texture.
In my tests with GM8 it did. And it doesn't really blend the colors, it overwrites them. For example, if you do this:
Code: [Select]
//Create
model = d3d_model_create();
d3d_model_primitive_begin(model,pr_trianglelist);
d3d_model_vertex(model,10,10,0);
d3d_model_vertex_color(model,100,10,0,c_green,1);
d3d_model_vertex(model,100,100,0);
d3d_model_primitive_end(model);

//Draw
draw_set_color(c_red);
draw_set_alpha(0.5);
d3d_model_draw(model,0,0,0,-1);
Then you will see a red transparent triangle (from bound color and alpha) with one green opaque corner (from model_vertex_color). If you do this:
Code: [Select]
draw_set_color(c_blue);
draw_set_alpha(0.25);
//Create
model = d3d_model_create();
d3d_model_primitive_begin(model,pr_trianglelist);
d3d_model_vertex(model,10,10,0);
d3d_model_vertex_color(model,100,10,0,c_green,1);
d3d_model_vertex(model,100,100,0);
d3d_model_primitive_end(model);

//Draw
draw_set_color(c_red);
draw_set_alpha(0.5);
d3d_model_draw(model,0,0,0,-1);
You will see the same thing, even though the bound color (blue) and alpha (0.25) was set before creating the model. So it ignored the blue and 0.25. In ENIGMA it would draw a blue transparent triangle with one solid green color and ignore the red and 0.5. It also never blends the colors if the color is specified. So if you do:
Code: [Select]
//Create
model = d3d_model_create();
d3d_model_primitive_begin(model,pr_trianglelist);
d3d_model_vertex_color(model,10,10,0,c_white,1.0);
d3d_model_vertex_color(model,100,10,0,c_white,1.0);
d3d_model_vertex_color(model,100,100,0,c_white,1.0);
d3d_model_primitive_end(model);

//Draw
draw_set_color(c_red);
draw_set_alpha(0.5);
d3d_model_draw(model,0,0,0,-1);
It will draw a solid white triangle and ignore the red and 0.5. This is the same in ENIGMA and GM.

Quote
The options are to waste space for each vertex format or to allow specifying vertex formats manually (as Yoyo has already done; didn't think they had it in them).
The space wasting is only done until d3d_model_primitive_end() as then all the vectors are destroyed. And I don't know how specifying vertex formats will help here.
Title: Re: Vertex color
Post by: Josh @ Dreamland on July 30, 2013, 10:30:27 am
Quote
The space wasting is only done until d3d_model_primitive_end() as then all the vectors are destroyed. And I don't know how specifying vertex formats will help here.
"Destroyed" and "moved to the GPU" are two very different concepts. They exist *somewhere*.

I'm not sure what to make of that behavior. I guess your boolean idea is acceptable.

As an alternative, we could allow a secondary alpha parameter, which specifies the amount to use of the model color vs the draw color.

Indexed palettes are a third option, but an uglier one.
Title: Re: Vertex color
Post by: TheExDeus on July 30, 2013, 12:04:47 pm
Quote
"Destroyed" and "moved to the GPU" are two very different concepts. They exist *somewhere*.
No, they really are destroyed. My idea was that I keep a bool which tell me if any _color functions are used. If by _end() the bool is still false, then I don't even bind the color buffer (so it is not sent to GPU) and just deleted like the rest. Of course GPU could have some internal color buffer it uses for all vertices if none is provided (and filled with bound color from immediate mode), but I don't think so. I think it just has 1 color value (bound by immediate mode) which is then reused.

Quote
As an alternative, we could allow a secondary alpha parameter, which specifies the amount to use of the model color vs the draw color.
But if we don't use shaders, then that is also not possible. We cannot blend anything to the vertices already in the vbo without manually looping them.

So I think the bool should suffice until we shader the whole thing.
Title: Re: Vertex color
Post by: Josh @ Dreamland on July 30, 2013, 02:50:28 pm
Erm. I was speaking on the pretense that this was for the newer systems with shaders.

I was also working with the pretense that this was to emulate GM's exact behavior when intermixing calls with and without _color. Even with GL lists, if you draw one red vertex, one colorless vertex, one green vertex, and then another colorless vertex, the two colorless vertices will receive, respectively, red and green. Just how the pipeline works. GM's behavior could be simulated by pushing and popping the color in the list where needed. The boolean wouldn't really be required otherwise, as not specifying a color just means not changing the current color.

Now, with shaders, the boolean would need added to the vertex format to simulate GM's behavior. The boolean in RAM could be useful for determining the required vertex format and possibly shader—I actually really like that idea.
Title: Re: Vertex color
Post by: TheExDeus on July 30, 2013, 03:45:23 pm
Quote
GM's behavior could be simulated by pushing and popping the color in the list where needed.
We use VBO's instead of lists as it is just better usually. But even lists cannot be changed. So if you turn this into a list:
Code: [Select]
glBegin(pr_trianglelist);
glColor4f(enigma::current_color[0],enigma::current_color[1],enigma::current_color[2],enigma::current_color[3]);
glVertex2f(10,10);
glColor4f(1.0,0.0,0.0,1.0);
glVertex2f(100,10);
glColor4f(enigma::current_color[0],enigma::current_color[1],enigma::current_color[2],enigma::current_color[3]);
glVertex2f(100,100);
glEnd();
The current_color[] would still be pushed in there at the time it was created, not when it is drawn. At least in VBO's you could loop trough the values and manually change them. In display lists you cannot. The boolean is because if I don't bind the color buffer, then it defaults to bound color during drawing. That is if I don't do this:
Code: [Select]
glEnableClientState(GL_COLOR_ARRAY);
glBindBuffer( GL_ARRAY_BUFFER, colorsVBO );
glColorPointer( 4, GL_FLOAT, 0, (char *) NULL );
Then glDrawArrays() will draw the VBO with the currently bound color (last glColor4f()). If I do bind it then it ignores that and looks for color in the color buffer. And as I cannot have a "don't care" value in the color buffer, then I must fill it during the creation or just before drawing. During creation I cannot know the bound color which will be used while drawing, but if I do it while drawing, then I must loop trough all vertices. I actually don't think that would be that much of a pain if the vertices are not in the thousands.

Anyway, I will then commit the fix with the bool later. After that I will look into sprite batching with VBO (check the other topic) and see maybe if we can switch to shaders in general.
Title: Re: Vertex color
Post by: Goombert on July 30, 2013, 04:14:46 pm
Harri, OpenGL3 uses VBO's, OpenGL 1 still uses call lists, and it is likely to remain that way.
Title: Re: Vertex color
Post by: TheExDeus on July 31, 2013, 04:10:26 am
And that was in no way connected to anything that was said here.
Title: Re: Vertex color
Post by: Goombert on July 31, 2013, 04:42:49 am
Quote
We use VBO's instead of lists as it is just better usually. But even lists cannot be changed. So if you turn this into a list:
It was in response to that :P I was not sure if you were aware that OpenGL 1 still uses call lists.
Title: Re: Vertex color
Post by: TheExDeus on July 31, 2013, 04:49:37 am
I was talking about the VBO implementation on GL3. Either way it changes nothing just as I mentioned.