
Kerran eräänä talvisena päivänä linkkari kertoi toiselle epämiellyttävistä tunteistaan, tässäpä pientä aamuöistä jatketta aiheesta. Tehtävänä on piirtää värikäs kolmio.
GPipe-tulkinta (tyypit piilotettu pelottavuuden vähentämiseksi):
triangle = toGPUStream TriangleStrip $ zip pos color
where
pos = [ sin x:.cos x:.() | x <- map ((pi*2/3) *) [0..2] ]
color = [ x:.0:.(1-x):.() | x <- map (/ 3) [0..2] ]
shade = fmap (RGB . snd) . rasterizeFrontAndBack . fmap vs
where
vs (x:.y:.(),color) = (x:.y:.0:.1:.(), color)
draw size = draw (shade triangle) clear
where
draw = paintColor NoBlending (RGB $ vec True)
clear = newFrameBufferColor (RGB $ vec 0)
Ja sitten likimain sama käyttäen modernia OpenGL:ää.
Verteksivarjostin:
in vec2 pos;
in vec3 color;
out Fragment {
vec3 color;
} frag;
void main() {
gl_Position = vec4(pos, 0, 1);
frag.color = color;
}
Pikselivarjostin:
in Fragment {
vec3 color;
} frag;
out vec4 color;
void main() {
color = vec4(frag.color, 1);
}
Ja ohjelmakoodi:
static void compile_shader(GLuint prog, GLenum type, const GLchar *src) {
GLuint s = glCreateShader(type);
glShaderSource(s, 1, &src, NULL);
glCompileShader(s);
glAttachShader(prog, s);
}
static void init_shader(const GLchar *vs, const GLchar *fs, GLuint *p) {
*p = glCreateProgram();
compile_shader(*p, GL_VERTEX_SHADER, vs);
compile_shader(*p, GL_FRAGMENT_SHADER, fs);
glLinkProgram(*p);
}
static void init_vbo(GLuint n, GLuint size, GLuint *vbo) {
glGenBuffers(1, vbo);
glBindBuffer(GL_ARRAY_BUFFER, *vbo);
glBufferData(GL_ARRAY_BUFFER, size*n*sizeof(float), NULL, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
static void init_attrib(
GLuint vbo,
GLuint prog,
GLuint size,
GLuint offset,
GLuint stride,
const char *name) {
glBindBuffer(GL_ARRAY_BUFFER, vbo);
GLuint attrib = glGetAttribLocation(prog, name);
glVertexAttribPointer(attrib, size, GL_FLOAT, GL_FALSE,
stride*sizeof(float), (GLvoid*)(offset*sizeof(float)));
glEnableVertexAttribArray(attrib);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
typedef struct {
float pos[2];
float color[3];
} vertex_t;
void init() {
GLuint prog;
GLuint vbo;
init_shader(vertex_shader, fragment_shader, &prog);
init_vbo(3, 5, &vbo);
init_attrib(vbo, prog, 2, 0, 5, "pos");
init_attrib(vbo, prog, 3, 2, 5, "color");
glBindBuffer(GL_ARRAY_BUFFER, vbo);
vertex_t* vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
if (vertices) {
for (int i = 0; i < 3; ++i) {
vertex_t *v = &vertices[i];
float c = i / 3.0f;
v->pos[0] = sinf(i*M_PI*2.0f/3.0f);
v->pos[1] = cosf(i*M_PI*2.0f/3.0f);
v->color[0] = c;
v->color[1] = 0.0f;
v->color[2] = 1.0f - c;
}
glUnmapBuffer(GL_ARRAY_BUFFER);
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void draw() {
glUseProgram(prog);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glClearColor(0,0,0,0);
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
}









