Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » A5 - how do I render a quad with a gradient?

Credits go to Arthur Kalliokoski and jmasterx for helping out!
This thread is locked; no one can reply to it. rss feed Print
 1   2 
A5 - how do I render a quad with a gradient?
Edgar Reynaldo
Major Reynaldo
May 2007
avatar

jmasterx
Member #11,410
October 2009

I'm not sure but I think https://www.allegro.cc/manual/5/al_draw_prim . I think each vertex defines a color and I think they are linearly interpolated by the graphics card.

I have old code to make gradients in GL:

#SelectExpand
1 2GLuint CGlShape::CreateTexture(std::vector<GLubyte> &pixelData, int width, int height) 3{ 4 GLuint texName; 5 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 6 7 glGenTextures(1, &texName); 8 glBindTexture(GL_TEXTURE_2D, texName); 9 10 11 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, 12 GL_LINEAR); 13 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, 14 GL_LINEAR); 15 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, 16 height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 17 &pixelData[0]); 18 19 return texName; 20} 21 22 23GLuint CGlShape::CreateTextureFromBitmap(wchar_t* filename) 24{ 25 Bitmap *b = new Bitmap(filename); 26 if(b == NULL) 27 { 28 return 0; 29 } 30 31 UINT w,h; 32 w = b->GetWidth(); 33 h = b->GetHeight(); 34 Rect *r = new Rect(0,0,w,h); 35 36 37 38 if(w == 0 && h == 0) 39 { 40 delete(b); 41 return 0; 42 } 43 44 Color c; 45 46 BitmapData bits; 47 b->LockBits(r,ImageLockModeRead,PixelFormat32bppARGB,&bits); 48 delete(r); 49 std::vector<GLubyte> pdata(w * h * 4,0); 50 51 unsigned char *scn; 52 scn = reinterpret_cast<unsigned char*>(bits.Scan0); 53 54 for (unsigned int i = 0; i < h; i++) { 55 for (unsigned int j = 0; j < w; j++) { 56 pdata[i * 4 * w + j * 4 + 0] = (GLubyte) scn[i * 4 * w + j * 4 + 2]; 57 pdata[i * 4 * w + j * 4 + 1] = (GLubyte) scn[i * 4 * w + j * 4 + 1]; 58 pdata[i * 4 * w + j * 4 + 2] = (GLubyte) scn[i * 4 * w + j * 4 + 0]; 59 pdata[i * 4 * w + j * 4 + 3] = (GLubyte) scn[i * 4 * w + j * 4 + 3]; 60 } 61 } 62 b->UnlockBits(&bits); 63 delete(b); 64 65 return CreateTexture(pdata,w,h); 66 67} 68 69 70 71 72GLuint CGlShape::CreateGradient(const std::vector<ArgbColorF> &input,vector2f start, vector2f end, size_t width, size_t height,bool radial ) 73{ 74 std::vector<GLubyte> pdata(width * height * 4); 75 vector2f p0; 76 vector2f p1; 77 vector2f v; 78 vector2f v0; 79 80 float d; 81 float t; 82 p0 = start; 83 84 p1 = end; 85 86 v = p1 - p0; 87 88 float ko = (v.x * v.x) + (v.y * v.y); 89 90 d = sqrt(ko); 91 92 ArgbColorF color; 93 float p; 94 if(!radial) //Linear 95 { 96 v *= (1 / (d * d)); 97 98 99 100 for(size_t i = 0; i < height; i++) { 101 for(size_t j = 0; j < width; j++) { 102 103 104 v0.x = j - p0.x; 105 v0.y = i - p0.y; 106 107 t = (v0.x * v.x) + (v0.y * v.y); 108 109 if ((t) < 0) 110 { 111 t = 0; 112 } 113 else if((t) > 1) 114 { 115 t = 1; 116 } 117 118 119 120 //end + start 121 122 for(unsigned int n = 0; n < input.size() - 1; ++n) 123 { 124 if(input[n].percent <= t && input[n + 1].percent >= t) 125 { 126 p = 1 / ((input[n+1].percent - input[n].percent) / (t - input[n].percent)); 127 128 color.r = (input[n + 1].r * p) + (input[n].r * (1 - p)); 129 color.g = (input[n + 1].g * p) + (input[n].g * (1 - p)); 130 color.b = (input[n + 1].b * p) + (input[n].b * (1 - p)); 131 color.a = (input[n + 1].a * p) + (input[n].a * (1 - p)); 132 } 133 } 134 135 136 pdata[i * 4 * width + j * 4 + 0] = (GLubyte) static_cast<GLubyte>(color.r * 255); 137 pdata[i * 4 * width + j * 4 + 1] = (GLubyte) static_cast<GLubyte>(color.g * 255); 138 pdata[i * 4 * width + j * 4 + 2] = (GLubyte) static_cast<GLubyte>(color.b * 255); 139 pdata[i * 4 * width + j * 4 + 3] = (GLubyte) static_cast<GLubyte>(color.a * 255); 140 } 141 } 142 } 143 else //Radial 144 { 145 for(size_t i = 0; i < height; i++) { 146 for(size_t j = 0; j < width; j++) { 147 148 v0.x = j - p0.x; 149 v0.y = i - p0.y; 150 151 t = (v0.x * v0.x) + (v0.y * v0.y); 152 t = sqrt(t); 153 154 if ((t/d) < 0) 155 { 156 t = 0; 157 } 158 else if((t/d) > 1) 159 { 160 t = 1; 161 } 162 else 163 { 164 t = t/d; 165 } 166 167 168 169 //end + start 170 for(unsigned int n = 0; n < input.size() - 1; ++n) 171 { 172 if(input[n].percent <= t && input[n + 1].percent >= t) 173 { 174 p = 1 / ((input[n+1].percent - input[n].percent) / (t - input[n].percent)); 175 176 color.r = (input[n + 1].r * p) + (input[n].r * (1 - p)); 177 color.g = (input[n + 1].g * p) + (input[n].g * (1 - p)); 178 color.b = (input[n + 1].b * p) + (input[n].b * (1 - p)); 179 color.a = (input[n + 1].a * p) + (input[n].a * (1 - p)); 180 } 181 } 182 pdata[i * 4 * width + j * 4 + 0] = (GLubyte) static_cast<GLubyte>(color.r * 255); 183 pdata[i * 4 * width + j * 4 + 1] = (GLubyte) static_cast<GLubyte>(color.g * 255); 184 pdata[i * 4 * width + j * 4 + 2] = (GLubyte) static_cast<GLubyte>(color.b * 255); 185 pdata[i * 4 * width + j * 4 + 3] = (GLubyte) static_cast<GLubyte>(color.a * 255); 186 } 187 } 188 189 } 190 191 return CreateTexture(pdata,width,height); 192} 193 194 195 196 197 198 199 200 201GLuint CGlShape::CreateAngularGradient(const std::vector<ArgbColorF> &input,vector2f start, vector2f end, size_t width, size_t height ) 202{ 203 std::vector<GLubyte> pdata(width * height * 4); 204 205 float cx; 206 float cy; 207 208 float r1; 209 float r2; 210 float ang; 211 212 float t; 213 float p; 214 215 cx = start.x; 216 cy = start.y; 217 end -= 500; 218 219 r1 = 0; 220 r2 = GetDistance(static_cast<float>(cx),static_cast<float>(cy), 221 static_cast<float>(width * height) 222 ,static_cast<float>(width * height)); 223 224 ang = atan2(-end.y - start.y,end.x - start.x) + pi; 225 226 ArgbColorF color; 227 228 for(size_t i = 0; i < height; i++) { 229 for(size_t j = 0; j < width; j++) { 230 231 t= atan2(i-cy,j-cx) + ang; 232 t= t+ pi; 233 if (t > 2* pi) 234 { 235 t=t-2*pi; 236 237 } 238 239 t=t/(2*pi); 240 241 //end + start 242 for(unsigned int n = 0; n < input.size() - 1; ++n) 243 { 244 if(input[n].percent <= t && input[n + 1].percent >= t) 245 { 246 p = 1 / ((input[n+1].percent - input[n].percent) / (t - input[n].percent)); 247 248 color.r = (input[n + 1].r * p) + (input[n].r * (1 - p)); 249 color.g = (input[n + 1].g * p) + (input[n].g * (1 - p)); 250 color.b = (input[n + 1].b * p) + (input[n].b * (1 - p)); 251 color.a = (input[n + 1].a * p) + (input[n].a * (1 - p)); 252 } 253 } 254 255 pdata[i * 4 * width + j * 4 + 0] = (GLubyte) static_cast<GLubyte>(color.r * 255); 256 pdata[i * 4 * width + j * 4 + 1] = (GLubyte) static_cast<GLubyte>(color.g * 255); 257 pdata[i * 4 * width + j * 4 + 2] = (GLubyte) static_cast<GLubyte>(color.b * 255); 258 pdata[i * 4 * width + j * 4 + 3] = (GLubyte) static_cast<GLubyte>(color.a * 255); 259 } 260 } 261 262 return CreateTexture(pdata,width,height); 263}

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

A5 doesn't support QUADS directly with al_draw_prim yet... hence the question, do I render two primitive triangles? The opposing corners of the quad won't be interpolated correctly because not all 4 corners is being taken into account at a time for mixing the color. :( IDK what to do...

jmasterx
Member #11,410
October 2009

Then the only thing I can think of is to generate the gradients using something like the code above and texture map the UVs yourself.

Arthur Kalliokoski
Second in Command
February 2005
avatar

I'm pretty sure video drivers break the quads down into triangles anyway, so yeah, use a texture.

They all watch too much MSNBC... they get ideas.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

jmasterx
Member #11,410
October 2009

int al_draw_prim(const void* vtxs, const ALLEGRO_VERTEX_DECL* decl,
ALLEGRO_BITMAP* texture, int start, int end, int type)

It has a texture parameter.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Arg, you guys don't get it. I don't want to use a texture, I want to render a gradient quad. I know al_draw_prim can take a texture and map it to a triangle.

I need to be able to draw gradient rectangles on the fly, for several reasons. If I have to I can emulate it all with a bunch of filled rectangles but that sucks.

Arthur Kalliokoski
Second in Command
February 2005
avatar

Colored triangles normally use Goraud shading, which won't draw evenly across the long leg of a pair of triangles. Maybe you could use a shader program?

They all watch too much MSNBC... they get ideas.

jmasterx
Member #11,410
October 2009

Yeah, a fragment shader should consider a trapezoid or quad as a single fragment and from there you have per-pixel freedom to do any kind of gradient rather easily.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Hmm, had not planned on doing this with shaders - it's just supposed to be part of the basic graphics api.

Well here's what it looks like - can't really tell it is two triangles.
{"name":"607128","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/a\/0\/a0a1dc9fd2b263a0f9dff5334048fa4f.png","w":812,"h":632,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/a\/0\/a0a1dc9fd2b263a0f9dff5334048fa4f"}607128
{"name":"607129","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/8\/5\/85ad7624e3030df9a052efbbf7f031de.png","w":812,"h":632,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/8\/5\/85ad7624e3030df9a052efbbf7f031de"}607129

Get's all funky when you try to vary the vertex colors though :
{"name":"607130","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/6\/c\/6c6826d72c582b0e34fd04bf4d378ee9.png","w":812,"h":632,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/6\/c\/6c6826d72c582b0e34fd04bf4d378ee9"}607130

Trent Gamblin
Member #261
April 2000
avatar

I don't get it. Why can't two triangles be drawn with a gradient? You give 6 vertices a color in all, 2 pairs share the same color.

kazzmir
Member #1,786
December 2001
avatar

Can you just copy the primitive code for drawing a rectangle and changing the colors for the verticies?

#SelectExpand
1void al_draw_filled_rectangle(float x1, float y1, float x2, float y2, 2 ALLEGRO_COLOR color) 3{ 4 ALLEGRO_VERTEX vtx[4]; 5 int ii; 6 7 vtx[0].x = x1; vtx[0].y = y1; 8 vtx[1].x = x1; vtx[1].y = y2; 9 vtx[2].x = x2; vtx[2].y = y2; 10 vtx[3].x = x2; vtx[3].y = y1; 11 12 for (ii = 0; ii < 4; ii++) { 13 vtx[ii].color = color; 14 vtx[ii].z = 0; 15 } 16 17 al_draw_prim(vtx, 0, 0, 0, 4, ALLEGRO_PRIM_TRIANGLE_FAN); 18}

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

I don't get it. Why can't two triangles be drawn with a gradient? You give 6 vertices a color in all, 2 pairs share the same color.

That's what I did though, and those are the results in the third picture. I need it to draw evenly between the four corners, but what it is doing now works for strictly horizontal and vertical gradients so I don't really care.

@Kazzmir
This is what I ended up using in the example :

      ALLEGRO_VERTEX t1[3] = {vtx[0] , vtx[1] , vtx[2]};
      ALLEGRO_VERTEX t2[3] = {vtx[0] , vtx[2] , vtx[3]};
      
      al_draw_prim(t1 , 0 , 0 , 0 , 3 , ALLEGRO_PRIM_TRIANGLE_LIST);
      al_draw_prim(t2 , 0 , 0 , 0 , 3 , ALLEGRO_PRIM_TRIANGLE_LIST);

But yeah, maybe a TRIANGLE_FAN would work too.

Trent Gamblin
Member #261
April 2000
avatar

Can you show a picture of how it's supposed to look?

kazzmir
Member #1,786
December 2001
avatar

Should it look something like this?

{"name":"607131","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/a\/c\/ac53c813f678eaf9b1a3ee6aed22a218.png","w":640,"h":480,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/a\/c\/ac53c813f678eaf9b1a3ee6aed22a218"}607131

#SelectExpand
1void shaded(float x1, float y1, float x2, float y2, 2 ALLEGRO_COLOR color1, ALLEGRO_COLOR color2, 3 ALLEGRO_COLOR color3, ALLEGRO_COLOR color4){ 4 ALLEGRO_VERTEX vtx[4]; 5 int ii; 6 7 vtx[0].x = x1; vtx[0].y = y1; 8 vtx[1].x = x1; vtx[1].y = y2; 9 vtx[2].x = x2; vtx[2].y = y2; 10 vtx[3].x = x2; vtx[3].y = y1; 11 12 for (ii = 0; ii < 4; ii++) { 13 vtx[ii].z = 0; 14 } 15 vtx[0].color = color1; 16 vtx[1].color = color2; 17 vtx[2].color = color3; 18 vtx[3].color = color4; 19 20 al_draw_prim(vtx, 0, 0, 0, 4, ALLEGRO_PRIM_TRIANGLE_FAN); 21} 22 23shaded(100, 100, 400, 400, 24 al_map_rgb(255, 0, 0), 25 al_map_rgb(128, 128, 0), 26 al_map_rgb(0, 255, 0), 27 al_map_rgb(128, 128, 0));

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

{"name":"607132","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/9\/2\/924e92393b84f843790638562d63c808.png","w":812,"h":632,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/9\/2\/924e92393b84f843790638562d63c808"}607132
This is what I'm talking about. Had to bust out A4 and render a quad3d_f. It looks like _soft_polygon3d_f (which is called by quad3d_f) does triangles too but I can't tell where the seam is. So this is more of what I was looking for. Probably have to learn some OpenGL and try rendering a quad with that.

#SelectExpand
1 2 3 4#include <allegro.h> 5 6 7//void quad3d_f(BITMAP *bmp, int type, BITMAP *tex, V3D_f *v1, *v2, *v3, *v4); 8 9 10V3D_f MakeVertex(float x , float y , float z , float u , float v , int c) { 11 V3D_f vtx; 12 vtx.x = x; 13 vtx.y = y; 14 vtx.z = z; 15 vtx.u = u; 16 vtx.v = v; 17 vtx.c = c; 18 return vtx; 19} 20 21void quad(BITMAP* bmp , float x1 , float y1 , int c1 , 22 float x2 , float y2 , int c2 , 23 float x3 , float y3 , int c3 , 24 float x4 , float y4 , int c4) { 25 V3D_f v3d[4] = { 26 MakeVertex(x1 , y1 , 0.0 , 0.0 , 0.0 , c1), 27 MakeVertex(x2 , y2 , 0.0 , 0.0 , 0.0 , c2), 28 MakeVertex(x3 , y3 , 0.0 , 0.0 , 0.0 , c3), 29 MakeVertex(x4 , y4 , 0.0 , 0.0 , 0.0 , c4) 30 }; 31 32 quad3d_f(bmp , POLYTYPE_GCOL , 0 , &v3d[0] , &v3d[1] , &v3d[2] , &v3d[3]); 33} 34 35int main(int argc , char** argv) { 36 37 if (allegro_init() != 0) { 38 return 1; 39 } 40 install_keyboard(); 41 42 set_color_depth(desktop_color_depth()); 43 if (set_gfx_mode(GFX_AUTODETECT_WINDOWED , 800 , 600 , 0 , 0) != 0) { 44 return 1; 45 } 46 47 48 int blue = makecol(0,0,255); 49 int black = makecol(0,0,0); 50 int white = makecol(255,255,255); 51 int red = makecol(255,0,0); 52 int green = makecol(0,255,0); 53 54 clear_to_color(screen , blue); 55 quad(screen , 150 , 150 , black , 56 800 , 150 , white , 57 600 , 450 , black , 58 0 , 450 , white); 59 readkey(); 60 61 return 0; 62} 63END_OF_MAIN()

Ah, this one looks good too. If I was doing this with two triangle primitives it would have a seam in it I think. Test that tomorrow. :P
{"name":"607134","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/5\/f\/5f5a18c6d0fddf16ba3c3acd5e2e3a5c.jpg","w":812,"h":632,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/5\/f\/5f5a18c6d0fddf16ba3c3acd5e2e3a5c"}607134

Trent Gamblin
Member #261
April 2000
avatar

The opengl spec specifies that if two triangles share vertices there will be no seem. I don't see a seam in the picture you say is wrong either. If you want non-linear shading you'll have to use shaders, simple as that.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Look at the difference between these two.

A5 with al_draw_prim :
{"name":"607130","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/6\/c\/6c6826d72c582b0e34fd04bf4d378ee9.png","w":812,"h":632,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/6\/c\/6c6826d72c582b0e34fd04bf4d378ee9"}607130

A4 with quad3d_f :
{"name":"607132","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/9\/2\/924e92393b84f843790638562d63c808.png","w":812,"h":632,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/9\/2\/924e92393b84f843790638562d63c808"}607132

In the first there is a very bright white seam. In the second the middle is gray. The second is what I want. Is that possible with A5? I used POLYTYPE_GCOL for gouraud shading on the a4 polygon.

Arthur Kalliokoski
Second in Command
February 2005
avatar

Look at your quad_3df image and draw an imaginary line between two opposing vertices, and tell me how Goraud interpolation is supposed to handle going brighter to dimmer to brighter or vice versa. I still say use a texture, GPU's have enough hardware to handle it in parallel so no slowdown should be apparent.

They all watch too much MSNBC... they get ideas.

SiegeLord
Member #7,827
October 2006
avatar

Is that possible with A5?

If you want non-linear shading you'll have to use shaders, simple as that.

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

EWClay
Member #14,750
December 2012

How about an extra vertex at the centre of the quad, using a colour which is the average of the four corners?

Can't guarantee it won't still show seams, but it should be closer to what you want.

Elias
Member #358
May 2000

Would have a cross-shaped seam then.

The solution should be to write a shader which does what A4 does, which probably is this: [1]

--
"Either help out or stop whining" - Evert

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

tell me how Goraud interpolation is supposed to handle going brighter to dimmer to brighter or vice versa.

I don't even know what gouraud means. All I'm looking for is an even distribution between the four corners somehow. :/

EWClay said:

How about an extra vertex at the centre of the quad, using a colour which is the average of the four corners?

Elias said:

Would have a cross-shaped seam then.

I was thinking of that idea as well. Perhaps A4 is merely rendering 4 triangles instead of the two I was thinking of. I will look at this later.

Elias said:

The solution should be to write a shader which does what A4 does, which probably is this: [1]

Not sure what I'm looking at there. What does it do different than A5?

SiegeLord said:

Use shaders...

Are there shader tutorials out there somewhere? Because I don't really know how to use them right or at all. :/

jmasterx
Member #11,410
October 2009

Fragment shaders are pretty straight forward, especially for your needs.

The way they work is that the shader is called per-fragment, so for example, a quad might be a fragment.

The fragment will get rasterized into pixels. The shader will run for each pixel.

You will also get information like relatively where you are on the bitmap. The values are either -1.0 to 1.0 or 0.0 to 1.0 I forget. But essentially by knowing that, you can linearly interpolate 2 colors or more.

Shaders also need a vertex component. Which is pretty straight forward. Just multiply the view matrix by the vertex position in the 2D case.

Here is my class for wrapping the shader addon.

HPP

#SelectExpand
1#ifndef CGE_SHADER_HPP 2#define CGE_SHADER_HPP 3#include <string> 4#include "Game/platform.hpp" 5#include "Agui/Image.hpp" 6#include "Game/Resource/Sprite.hpp" 7namespace cge 8{ 9 class Shader 10 { 11 public: 12 ~Shader(); 13 Shader(); 14 Shader( const std::string & vtxsrcpath, const std::string & pxsrcpath); 15 bool load( const std::string & vtxsrcpath, const std::string & pxsrcpath); 16 void use(); 17 void stop(); 18 bool setSampler(agui::Image* img, const std::string& name, int unit = 0); 19 bool setSampler(Sprite* img, const std::string& name, int unit = 0); 20 bool setSampler(ALLEGRO_BITMAP* img, const std::string& name, int unit = 0); 21 void destroy(); 22 void printLog(); 23 ALLEGRO_SHADER* getShader(); 24 void setVal(const std::string& name, float val); 25 void setVal(const std::string& name, int val); 26 void setVal(const std::string& name, bool val); 27 static Shader& getDefaultShader(); 28 bool isDefaultShader(); 29 void mountShader(); 30 static void setGlsl(bool glsl); 31 static bool isGlsl(); 32 static bool isHlsl(); 33 private: 34 void create(); 35 bool loadSource(const std::string & srcpath, bool pixelShader); 36 bool link(); 37 static bool m_glsl; 38 ALLEGRO_SHADER* m_shader; 39 std::string m_src; 40 static Shader m_default; 41 bool m_inUse; 42 }; 43} 44 45#endif

CPP

#SelectExpand
1#include "Game/Shader/Shader.hpp" 2#include "Agui/Backends/Allegro5/Allegro5Image.hpp" 3#include <allegro5/allegro_shader_hlsl.h> 4#include <allegro5/allegro_shader_glsl.h> 5#include <iostream> 6#ifdef _WIN32 7#include <allegro5/allegro_windows.h> 8#include <allegro5/allegro_direct3d.h> 9#include <allegro5/allegro_shader_hlsl.h> 10#endif 11 12namespace cge 13{ 14 15 void Shader::destroy() 16 { 17 if(m_shader) 18 { 19 if(!isDefaultShader() && m_inUse) 20 { 21 stop(); 22 } 23 al_destroy_shader(m_shader); 24 m_shader = NULL; 25 } 26 } 27 28 void Shader::create() 29 { 30 destroy(); 31 m_shader = al_create_shader(isGlsl() ? ALLEGRO_SHADER_GLSL : ALLEGRO_SHADER_HLSL); 32 33 } 34 35 bool Shader::loadSource( const std::string & srcpath, bool pixelShader ) 36 { 37 return al_attach_shader_source_file(m_shader, 38 pixelShader ? ALLEGRO_PIXEL_SHADER : ALLEGRO_VERTEX_SHADER,srcpath.c_str()); 39 } 40 41 Shader::Shader() 42 : m_shader(NULL),m_inUse(false) 43 { 44 45 } 46 47 Shader::Shader( const std::string & vtxsrcpath, const std::string & pxsrcpath) 48 : m_shader(NULL),m_inUse(false) 49 { 50 load(vtxsrcpath,pxsrcpath); 51 } 52 53 bool Shader::link() 54 { 55 return al_link_shader(m_shader); 56 } 57 58 bool Shader::load( const std::string & vtxsrcpath, const std::string & pxsrcpath) 59 { 60 std::string appendV = isHlsl() ? ".hlslv" : ".glslv"; 61 std::string appendP = isHlsl() ? ".hlslp" : ".glslp"; 62 63 create(); 64 if(!m_shader) 65 { 66 std::cout << "create fail\n"; 67 return false; 68 } 69 70 if(vtxsrcpath != "") 71 { 72 if(!loadSource(vtxsrcpath + appendV,false)) 73 { 74 std::cout << "vtx src load fail\n"; 75 fprintf(stderr, "%s\n", al_get_shader_log(m_shader)); 76 return false; 77 } 78 } 79 80 if(pxsrcpath != "") 81 { 82 if(!loadSource(pxsrcpath + appendP,true)) 83 { 84 std::cout << "px src load fail\n"; 85 fprintf(stderr, "%s\n", al_get_shader_log(m_shader)); 86 return false; 87 } 88 } 89 90 if(!link()) 91 { 92 std::cout << "link fail\n"; 93 return false; 94 } 95 96 std::cout << "success\n"; 97 98 if(isDefaultShader()) 99 { 100 use(); 101 } 102 return true; 103 } 104 105 void Shader::use() 106 { 107 m_inUse = true; 108 mountShader(); 109 al_use_shader(m_shader,true); 110 } 111 112 void Shader::stop() 113 { 114 al_use_shader(m_shader,false); 115 if(!isDefaultShader()) 116 { 117 getDefaultShader().use(); 118 } 119 } 120 121 bool Shader::setSampler( agui::Image* img, const std::string& name, int unit /*= 0*/ ) 122 { 123 return al_set_shader_sampler(m_shader,name.c_str(),((agui::Allegro5Image*)img)->getBitmap(),unit); 124 } 125 126 bool Shader::setSampler( Sprite* img, const std::string& name, int unit /*= 0*/ ) 127 { 128 return al_set_shader_sampler(m_shader,name.c_str(),img->getBitmap(),unit); 129 } 130 131 bool Shader::setSampler( ALLEGRO_BITMAP* img, const std::string& name, int unit /*= 0*/ ) 132 { 133 return al_set_shader_sampler(m_shader,name.c_str(),img,unit); 134 } 135 136 Shader::~Shader() 137 { 138 139 destroy(); 140 141 } 142 143 ALLEGRO_SHADER* Shader::getShader() 144 { 145 return m_shader; 146 } 147 148 void Shader::setVal( const std::string& name, float val ) 149 { 150 al_set_shader_float(m_shader,name.c_str(),val); 151 } 152 153 void Shader::setVal( const std::string& name, int val ) 154 { 155 al_set_shader_int(m_shader,name.c_str(),val); 156 } 157 158 void Shader::setVal( const std::string& name, bool val ) 159 { 160 al_set_shader_bool(m_shader,name.c_str(),val); 161 } 162 163 void Shader::printLog() 164 { 165 std::cout << al_get_shader_log(m_shader) << "\n"; 166 } 167 168 Shader& Shader::getDefaultShader() 169 { 170 return m_default; 171 } 172 173 bool Shader::isDefaultShader() 174 { 175 return this == &getDefaultShader(); 176 } 177 178 void Shader::mountShader() 179 { 180 if(isHlsl()) 181 al_set_direct3d_effect(al_get_current_display(), al_get_direct3d_effect(getShader())); 182 else 183 al_set_opengl_program_object(al_get_current_display(), al_get_opengl_program_object(getShader())); 184 } 185 186 void Shader::setGlsl( bool glsl ) 187 { 188 m_glsl = glsl; 189 } 190 191 bool Shader::isGlsl() 192 { 193 return m_glsl; 194 } 195 196 bool Shader::isHlsl() 197 { 198 return !isGlsl(); 199 } 200 201 bool Shader::m_glsl(false); 202 203 cge::Shader Shader::m_default; 204 205}

Here is the vertex shader I use (hlsl):

#SelectExpand
1 struct VS_INPUT 2 { 3 float4 Position : POSITION0; 4 float2 TexCoord : TEXCOORD0; 5 float4 Color : TEXCOORD1; 6 }; 7 struct VS_OUTPUT 8 { 9 float4 Position : POSITION0; 10 float4 Color : COLOR0; 11 float2 TexCoord : TEXCOORD0; 12 }; 13 14 float4x4 projview_matrix; 15 16 VS_OUTPUT vs_main(VS_INPUT Input) 17 { 18 VS_OUTPUT Output; 19 Output.Position = mul(Input.Position, projview_matrix); 20 Output.Color = Input.Color; 21 Output.TexCoord = Input.TexCoord; 22 return Output; 23 }

 1   2 


Go to: