how can I set the color for the lines I draw using openGL3 ?
the rendering function I'm using is the following
void renderVertex(std::vector<doubleVertex> &Poly, int32_t iniBound, int32_t endBound, int32_t Type){
for (int32_t i = iniBound; i < endBound; i++) {
GLfloat *ptr_polygonVertices;
ptr_polygonVertices = createPolygonVertices(Poly[i]);
// render OpenGL here
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, ptr_polygonVertices);
glDrawArrays(Type, 0, Poly[i].x.size() - 1);
glDisableClientState(GL_VERTEX_ARRAY);
delete[] ptr_polygonVertices;
}
}
Inside this loop
while (!glfwWindowShouldClose(window)) {
glClear(GL_COLOR_BUFFER_BIT);
renderVertex(Poly, 0, nBound, GL_LINE_LOOP);
// Swap front and back buffers
glfwSwapBuffers(window);
// Poll for and process events
glfwPollEvents();
}
If necessary, the complete code is the listed here:
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <math.h>
#include <stdlib.h>
#include "Globals.h"
GLfloat* createPolygonVertices(doubleVertex &Poly);
doubleVertex createCircle(double x, double y, double radius, int numberOfSides);
void windowInit(GLFWwindow *window);
void renderVertex(std::vector<doubleVertex> &Poly, int32_t iniBound, int32_t endBound, int32_t Type);
int main(void)
{
GLFWwindow *window;
// Initialize the library
if (!glfwInit())
exit(0);
// Create a windowed mode window and its OpenGL context
window = glfwCreateWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Polygon Linear Infill", NULL, NULL);
windowInit(window);
////////////////////////////////////// Polygon Example //////////////////////////////////////////
std::vector<doubleVertex> Poly{
{
{ 0, 23.37, 50.24, 31.26, 34.57, 1.46, 4.69, 0 },
{ 0, 11.91, 0, -21.39, -32.22, -26.31, -13.17, 0 }
},
{
{ 42.19, 35.69, 29.76, 34.46, 42.19 },
{ -4.26, 2.34, -5.2, -11.87, -4.26 }
},
{
{ 23.57, 26.29, 11.94, 23.57 },
{ -26.73, -17.39, -18.38, -26.73 }
}
};
double x = 14.97, y = -5.28, r = 7.33;
Poly.push_back(createCircle(x, y, r, 37));
uint32_t i, nBound = Poly.size();
while (!glfwWindowShouldClose(window)) {
glClear(GL_COLOR_BUFFER_BIT);
renderVertex(Poly, 0, nBound, GL_LINE_LOOP);
// Swap front and back buffers
glfwSwapBuffers(window);
// Poll for and process events
glfwPollEvents();
}
glfwTerminate();
return 0;
}
GLfloat* createPolygonVertices(doubleVertex &Poly){
int32_t j, n_Vertex, cnt_polygonVertices=0;
n_Vertex = Poly.x.size();
GLfloat *polygonVertices;
polygonVertices = new GLfloat[(n_Vertex-1) * 2];
for (j = 0; j < n_Vertex-1; j++) {
polygonVertices[cnt_polygonVertices] = Poly.x[j];
cnt_polygonVertices++;
polygonVertices[cnt_polygonVertices] = Poly.y[j];
cnt_polygonVertices++;
}
return polygonVertices;
}
doubleVertex createCircle(double x, double y, double radius, int numberOfSides){
int numberOfVertices = numberOfSides + 2;
double twicePi = 2.0f * M_PI;
doubleVertex Poly;
for (int i = 0; i < numberOfVertices; i++)
{
Poly.x.push_back(x + (radius * cos(i * twicePi / numberOfSides)));
Poly.y.push_back(y + (radius * sin(i * twicePi / numberOfSides)));
}
return Poly;
}
void windowInit(GLFWwindow *window){
if (!window) {
glfwTerminate();
exit(0);
}
// Make the window's context current
glfwMakeContextCurrent(window);
glViewport(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT); // specifies the part of the window to which OpenGL will draw (in pixels), convert from normalised to pixels
glMatrixMode(GL_PROJECTION); // projection matrix defines the properties of the camera that views the objects in the world coordinate frame. Here you typically set the zoom factor, aspect ratio and the near and far clipping planes
glLoadIdentity(); // replace the current matrix with the identity matrix and starts us a fresh because matrix transforms such as glOrpho and glRotate cumulate, basically puts us at (0, 0, 0)
glOrtho(0, 51, -33, 12, 0, 1); // essentially set coordinate system
glMatrixMode(GL_MODELVIEW); // (default matrix mode) modelview matrix defines how your objects are transformed (meaning translation, rotation and scaling) in your world
glLoadIdentity(); // same as above comment
}
void renderVertex(std::vector<doubleVertex> &Poly, int32_t iniBound, int32_t endBound, int32_t Type){
for (int32_t i = iniBound; i < endBound; i++) {
GLfloat *ptr_polygonVertices;
ptr_polygonVertices = createPolygonVertices(Poly[i]);
// render OpenGL here
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, ptr_polygonVertices);
glDrawArrays(Type, 0, Poly[i].x.size() - 1);
glDisableClientState(GL_VERTEX_ARRAY);
delete[] ptr_polygonVertices;
}
}
Thanks in advance!
Related
I'm trying to make a color swatch tool, where you give it n colors and it makes a n-gon with those colors merging at the center.
So far it just makes an n-gon(without specifying colors, it randomly generates them for now).
However the colors don't merge at the center but rather a single vertex.
Is there any fix to this?
#include <GLFW/glfw3.h>
#include <iostream>
#include <cmath>
float randfloat(){
float r = ((float)(rand() % 10))/10;
return r;
}
int main() {
int side_count;
std::cout<<"Type the no. of sides: "<<std::endl;
std::cin>>side_count;
srand(time(NULL));
std::cout<<randfloat()<<std::endl;
std::cout<<randfloat()<<std::endl;
float rs[side_count];
float gs[side_count];
float bs[side_count];
for (int i=0;i<side_count;i++)
{
rs[i] = randfloat();
gs[i] = randfloat();
bs[i] = randfloat();
}
GLFWwindow* window;
if (!glfwInit())
return 1;
window = glfwCreateWindow(800, 800, "Window", NULL, NULL);
if (!window) {
glfwTerminate();
return 1;
}
glfwMakeContextCurrent(window);
if(glewInit()!=GLEW_OK)
std::cout<<"Error"<<std::endl;
while(!glfwWindowShouldClose(window)) {
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0.11f,0.15f,0.17f,1.0f);
glBegin(GL_POLYGON);
//glColor3f(1.0f,0.0f,0.0f);glVertex3f(-0.5f,0.0f,0.0f);
for(int i=0; i<side_count;i++)
{
float r = rs[i];
float g = gs[i];
float b = bs[i];
float x = 0.5f * sin(2.0*M_PI*i/side_count);
float y = 0.5f * cos(2.0*M_PI*i/side_count);
glColor3f(r,g,b);glVertex2f(x,y);
}
glEnd();
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
All you've to do is to add a new point to the GL_POLYGON primitive, in the center of the circular shape:
glBegin(GL_TRIANGLE_FAN);
glColor3f(0.5f, 0.5f, 0.5f);
glVertex2f(0, 0);
for(int i=0; i <= side_count; i++)
{
float r = rs[i % side_count];
float g = gs[i % side_count];
float b = bs[i % side_count];
float x = 0.5f * sin(2.0*M_PI*i/side_count);
float y = 0.5f * cos(2.0*M_PI*i/side_count);
glColor3f(r, g, b);
glVertex2f(x, y);
}
glEnd();
Note, you've to define the color for the center point. In the code snippet, I've chosen (0.5, 0.5, 0.5).
Instead of GL_POLYGON, GL_TRIANGLE_FAN can be used, too.
I am attempting to translate one circle independent of a separate, stationary circle, utilizing glTranslatef();. However, with my current, full code, each of my circles remains immobile. To investigate why this may be so, I have researched several answers, each comparable to those found here and here. Additionally, I read up on glLoadIdentity as well as the differences between GL_MODELVIEW and GL_PROJECTION, just to see if their details would offer any further clarification. I've also consulted the OpenGL API for the proper definitions of each of the above.
In the style of these solutions, I produced the following do...while loop:
do{
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, fb_width, fb_height, 0, 0, 1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glTranslatef(0,1,0);
drawCircle(1280 * 0.50, 720 * 0.25,e[2]);
glPopMatrix();
glPushMatrix();
glTranslatef(0,0,0);
drawTarget(1280 * 0.50, 720 * 0.75,50);
glPopMatrix();
glfwSwapBuffers(w);
glfwPollEvents();
}
while (!glfwWindowShouldClose(w));
In this snippet, the drawCircle drawing remains stationary, but I would like for it to follow the written glTranslatef(0,1,0) instead. Is the stationary nature of the circle due to misplaced a glMatrixMode or glLoadIdentity, or perhaps due to the fact that they are being called within the do...while loop and the proper matrix is never really being utilized? I would appreciate any guidance you may have as to why the aforementioned and accepted answers are not functioning quite as well within my program.
For the sake of full transparency, here is the entirety of my code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdint.h>
#include <math.h>
#include <stddef.h>
#include <stdbool.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
GLFWwindow *w;
int fb_width, fb_height;
static void error(int error, const char *desc)
{
fputs(desc, stderr);
}
static void key_callback(GLFWwindow *w, int key, int scancode, int action, int mods)
{
if ((key == GLFW_KEY_ESCAPE || key == GLFW_KEY_Q) && action == GLFW_PRESS)
glfwSetWindowShouldClose(w, GL_TRUE);
}
void drawCircle(float cx, float cy, float radius)
{
float num_segments = 360;
float theta = 2 * 3.1415926 / num_segments;
float c = cosf(theta);//precalculate the sine and cosine
float s = sinf(theta);
float t;
float x = radius;//we start at angle = 0
float y = 0;
glBegin(GL_TRIANGLE_FAN);
glColor3f(1, 0, 1);
for(int ii = 0; ii < num_segments; ii++)
{
glVertex2f(x + cx, y + cy);//output vertex
//apply the rotation matrix
t = x;
x = c * x - s * y;
y = s * t + c * y;
}
glEnd();
}
void drawTarget(float cx, float cy, float radius)
{
float num_segments = 360;
float theta = 2 * 3.1415926 / num_segments;
float c = cosf(theta);//precalculate the sine and cosine
float s = sinf(theta);
float t;
float x = radius;//we start at angle = 0
float y = 0;
glBegin(GL_LINE_LOOP);
glColor3f(1, 1, 1);
for(int ii = 0; ii < num_segments; ii++)
{
glVertex2f(x + cx, y + cy);//output vertex
//apply the rotation matrix
t = x;
x = c * x - s * y;
y = s * t + c * y;
}
glEnd();
}
int main(void)
{
int i;
float e[3] = {140,120,100};
float m[3] = {90,80,70};
float h[3] = {60,50,40};
glfwSetErrorCallback(error);
if (!glfwInit())
exit(EXIT_FAILURE);
w = glfwCreateWindow(1280, 720, "AxTest", NULL, NULL);
if (!w)
{
glfwTerminate();
return 1;
}
glfwMakeContextCurrent(w);
glfwSetKeyCallback(w, key_callback);
glfwGetFramebufferSize(w, &fb_width, &fb_height);
do{
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, fb_width, fb_height, 0, 0, 1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glTranslatef(0,1,0);
drawCircle(1280 * 0.50, 720 * 0.25,e[2]);
glPopMatrix();
glPushMatrix();
glTranslatef(0,0,0);
drawTarget(1280 * 0.50, 720 * 0.75,50);
glPopMatrix();
glfwSwapBuffers(w);
glfwPollEvents();
}
while (!glfwWindowShouldClose(w));
glfwDestroyWindow(w);
glfwTerminate();
exit(EXIT_SUCCESS);
return 0;
}
The values for the vertex positions with which you draw your circles are in the order of hundreds (likely, because you want to address pixels as indicated by the values for the projection matrix). But glTranslates sees only a small number, so the shift is miniscule (one pixel) and hence you think nothing did happen. If you rewrite your code so that you don't specify the circle/target center by explicit modification of the vertex position offset it'd be clearer.
void drawCircle(float radius)
{
/* ... */
for(int ii = 0; ii < num_segments; ii++)
{
glVertex2f(x, y); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
/* ... */
}
void drawTarget(float radius)
{
/* ... */
for(int ii = 0; ii < num_segments; ii++)
{
glVertex2f(x, y); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
/* ... */
}
int main(void)
{
/* ... */
glPushMatrix();
glTranslatef(1280*0.50, 720*0.25, 0);
drawCircle(e[2]);
glPopMatrix();
glPushMatrix();
glTranslatef(1280 * 0.50, 720 * 0.25, 0);
drawTarget(50);
glPopMatrix();
/* ... */
}
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, fb_width, fb_height, 0, 0, 1);
You don't have to make the projection matrix at every loop, put it before the loop.
Then the error you have is surely due to :
glMatrixMode(GL_MODELVIEW);
// it miss glLoadIdentity() here
glPushMatrix();
glTranslatef(0,1,0);
I want to rotate my triangle in OpenGL, and running program on Raspberry Pi.
I can draw triangle and move it.
But I have no idea to rotate it..
Nothing rotates.
#include <cstdio>
#include <ctime>
#include <cmath>
#include <string>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
#include <GLES/gl.h>
#include <bcm_host.h>
EGLDisplay Disp;
EGLSurface Surface;
EGLContext Context;
int ScrWidth, ScrHeight;
float MVPMatrix[16];
float ProjectionMatrix[16];
float ViewMatrix[16];
using namespace std;
class Shader
{
private:
string VertexShaderFile;
string FragmentShaderFile;
GLuint Load(GLenum type, string FileName)
{
(Compile shader)
}
GLuint Program;
bool Linked;
public:
Shader(string FileNameV, string FileNameF)
{
Linked = false;
VertexShaderFile = FileNameV;
FragmentShaderFile = FileNameF;
}
bool Load()
{
(Link vertex/fragment shader)
}
void Use()
{
glUseProgram(Program);
}
int GetAttrLoc(const char *Name)
{
glGetAttribLocation(Program, Name);
}
int GetUniformLoc(const char *Name)
{
return glGetUniformLocation(Program, Name);
}
~Shader()
{
if(Linked)
{
Linked = false;
glDeleteProgram(Program);
}
}
};
class Triangle
{
private:
const int COORDS_PER_VERTEX = 3;
const int vertexCount = 9 / COORDS_PER_VERTEX; //9: Length of triangleCoords
const int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
static float TriangleCoords [];
float Color[4];
float XOff;
float YOff;
float ZOff;
Shader *S;
public:
Triangle()
{
XOff = YOff = ZOff = 0;
S = new Shader("Shaders/test.vsh", "Shaders/test.fsh");
if (!S->Load())
{
delete S;
S = NULL;
}
}
void SetColor(int R, int G, int B, int A)
{
Color[0] = R / 255.0;
Color[1] = G / 255.0;
Color[2] = B / 255.0;
Color[3] = A / 255.0;
}
void SetXYZ(int X, int Y, int Z)
{
(Sets position)
}
bool Draw()
{
float TriangleCoords[] = { // in counterclockwise order:
-0.0 + XOff, 0.622008459 + YOff, 0.0 + ZOff, // top
-0.5 + XOff, -0.311004243 + YOff, 0.0 + ZOff, // bottom left
0.5 + XOff, -0.311004243 + YOff, 0.0 + ZOff // bottom right
};
printf("%f\n", TriangleCoords[1]);
//glMatrixMode(GL_PROJECTION);
if (S == NULL)
return false;
S->Use();
// Load the vertex data
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, TriangleCoords);
// get handle to shape's transformation matrix
// Pass the projection and view transformation to the shader
//UniformMatrix4fv(S->GetUniformLoc("uMVPMatrix"), 1, false, MVPMatrix);
glUniform4fv(S->GetUniformLoc("vColor"), 1, Color);
glEnableVertexAttribArray(0);
//glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
float X = LocalTime->tm_hour / 23.0;
float Y = LocalTime->tm_min / 59.0;
float Z = LocalTime->tm_sec / 59.0;
glTranslatef(0, 0, 1);
glRotatef(60, 1.f, 0.f, 0.f);
glRotatef(30, 0.f, 1.f, 0.f);
glRotatef(30, 0.f, 0.f, 1.f);
glDrawArrays(GL_TRIANGLES, 0, 3);
//glPopMatrix();
return true;
}
};
bool InitDisplay()
{
bcm_host_init();
Disp = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if(eglInitialize(Disp, NULL, NULL) != EGL_TRUE)
{
printf("Display initialize error.\n");
return false;
}
printf("Display initialized.\n");
static const EGLint AttrList[] =
{
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_NONE
};
EGLConfig Config;
int ConfigCount;
if(eglChooseConfig(Disp, AttrList, &Config, 1, &ConfigCount) != EGL_TRUE)
{
printf("Display choose config error.\n");
return false;
}
printf("Display config chosen. %d configs.\n", ConfigCount);
//if(eglBindAPI(EGL_OPENGL_ES_API) != EGL_TRUE)
//{
// printf("Bind API error.\n");
// return false;
//}
//printf("API bound.\n");
static const EGLint ContextAttr[] =
{
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
if((Context = eglCreateContext(Disp, Config, EGL_NO_CONTEXT, ContextAttr)) == EGL_NO_CONTEXT)
{
printf("Create context error.\n");
return false;
}
printf("Context created.\n");
if(graphics_get_display_size(0 /* LCD */, &ScrWidth, &ScrHeight) < 0)
{
printf("Get screen size error.\n");
return false;
}
printf("Got screen size. %dx%d\n", ScrWidth, ScrHeight);
DISPMANX_DISPLAY_HANDLE_T DispmanDisp;
DispmanDisp = vc_dispmanx_display_open(0 /* LCD */);
printf("Dispmanx - Display opened.\n");
DISPMANX_UPDATE_HANDLE_T DispmanUpdate;
DispmanUpdate = vc_dispmanx_update_start(0);
printf("Dispmanx - Update started.\n");
DISPMANX_ELEMENT_HANDLE_T DispmanElement;
VC_RECT_T DestRect;
VC_RECT_T SrcRect;
DestRect.x = 0;
DestRect.y = 0;
DestRect.width = ScrWidth;
DestRect.height = ScrHeight;
SrcRect.x = 0;
SrcRect.y = 0;
SrcRect.width = ScrWidth << 16;
SrcRect.height = ScrHeight << 16;
DispmanElement= vc_dispmanx_element_add(
DispmanUpdate,
DispmanDisp,
0/*layer*/,
&DestRect,
0/*src*/,
&SrcRect,
DISPMANX_PROTECTION_NONE,
0 /*alpha*/,
0/*clamp*/,
0/*transform*/
);
printf("Dispmanx - Element added.\n");
static EGL_DISPMANX_WINDOW_T NativeWindow;
NativeWindow.element = DispmanElement;
NativeWindow.width = ScrWidth;
NativeWindow.height = ScrHeight;
vc_dispmanx_update_submit_sync(DispmanUpdate);
printf("Dispmanx - Sync submited.\n");
if((Surface = eglCreateWindowSurface(Disp, Config, &NativeWindow, NULL)) == EGL_NO_SURFACE)
{
printf("Create surface error.\n");
return false;
}
printf("Surface created\n");
if(eglMakeCurrent(Disp, Surface, Surface, Context) != EGL_TRUE)
{
printf("Make onnection between context and surface error.\n");
return false;
}
printf("Connection made between context and surface.\n");
glEnable(GL_CULL_FACE);
glMatrixMode(GL_MODELVIEW);
printf("Graphics system ready.\n");
return true;
}
void makeFrustum(float fovY, float aspectRatio, float front, float back)
{
const float DEG2RAD = 3.14159265 / 180;
float tangent = tan(fovY / 2 * DEG2RAD); // tangent of half fovY
float height = front * tangent; // half height of near plane
float width = height * aspectRatio; // half width of near plane
// params: left, right, bottom, top, near, far
glFrustumf(-width, width, -height, height, front, back);
}
void DrawLoop()
{
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
glViewport(0, 0, ScrWidth, ScrHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
makeFrustum(45.0, ScrWidth / (float)ScrHeight, 1, 500);
glEnableClientState(GL_VERTEX_ARRAY);
Triangle T1;
Triangle T2;
Triangle T3;
Triangle T4;
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.f, 0.f, -50.f);
while (1)
{
time_t Time;
time(&Time);
tm *LocalTime = localtime(&Time);
printf("%d:%d:%d\n", LocalTime->tm_hour, LocalTime->tm_min, LocalTime->tm_sec);
float R = LocalTime->tm_hour / 23.0;
float G = LocalTime->tm_min / 59.0;
float B = LocalTime->tm_sec / 59.0;
T1.SetColor(255, 0, 0, 255);
T1.SetXYZ(B * ScrWidth, B * ScrHeight, 0);
//glClearColor(0, 0, 0, 1.0);
//glClear(GL_COLOR_BUFFER_BIT);
if (!T1.Draw() || !T2.Draw() || !T3.Draw() || !T4.Draw())
{
return;
}
glFlush();
eglSwapBuffers(Disp, Surface);
}
}
int main()
{
if(!InitDisplay())
{
printf("Display initialize error.\n");
return false;
}
DrawLoop();
return 0;
}
What should I do to rotate triangle?
I referenced working code, but it still doesn't rotates.
You're trying to use OpenGL ES 1.1 functions (glLoadIdentity, glMatrixMode, glTranslatef, glRotatef, etc) in an OpenGL ES 2.0 context - this won't work. You can use either OpenGL ES 1.1 OR OpenGL ES 2.0, but you can't use both at the same time from the same context.
I would suggest sticking with OpenGL ES 2.0 using shaders, and learning the OpenGL ES 2.0 way of doing things, as this is how all of the newer APIs work.
To do translation and rotation you need to encode it into an MVP matrix and pass this as a uniform to the vertex shader which you use when calculating gl_Position. Some examples here:
https://open.gl/transformations
I am making changes in the code from this article, to acomplish the same result without need the methods specific for Windows and be able to run the programa in other platforms. I can compile and run the program without errors (with the Main and Render functions listed below), but the result is a blank screen. Someone can find some reason in the code for this issue happen?
Main:
int main(int argc, char **argv)
{
// temp var's
int width = 800;
int height = 600;
int bits = 32;
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(width,height);
glutInit(&argc, argv);
glutCreateWindow("Terrain");
glutDisplayFunc(Render);
glutReshapeFunc(AlteraTamanhoJanela);
glutKeyboardFunc(GerenciaTeclado);
glutMouseFunc(GerenciaMouse);
Initialize();
glutMainLoop();
}
Render:
void Render()
{
radians = float(PI*(angle-90.0f)/180.0f);
// calculate the camera's position
cameraX = lookX + sin(radians)*mouseY; // multiplying by mouseY makes the
cameraZ = lookZ + cos(radians)*mouseY; // camera get closer/farther away with mouseY
cameraY = lookY + mouseY / 2.0f;
// calculate the camera look-at coordinates as the center of the terrain map
lookX = (MAP_X*MAP_SCALE)/2.0f;
lookY = 150.0f;
lookZ = -(MAP_Z*MAP_SCALE)/2.0f;
// clear screen and depth buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
// set the camera position
gluLookAt(cameraX, cameraY, cameraZ, lookX, lookY, lookZ, 0.0, 1.0, 0.0);
// set the current texture to the land texture
glBindTexture(GL_TEXTURE_2D, land);
// we are going to loop through all of our terrain's data points,
// but we only want to draw one triangle strip for each set along the x-axis.
for (int z = 0; z < MAP_Z-1; z++)
{
//printf("%s %d\n","Loop FOR para Z = ",z);
glBegin(GL_TRIANGLE_STRIP);
for (int x = 0; x < MAP_X-1; x++)
{
//printf("%s %d\n","Loop FOR para X = ",x);
// for each vertex, we calculate the grayscale shade color,
// we set the texture coordinate, and we draw the vertex.
/*
the vertices are drawn in this order:
0 ---> 1
/
/
|/
2 ---> 3
*/
// draw vertex 0
//printf("%s\n","Primeiro");
glColor3f(terrain[x][z][1]/255.0f, terrain[x][z][1]/255.0f, terrain[x][z][1]/255.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(terrain[x][z][0], terrain[x][z][1], terrain[x][z][2]);
// draw vertex 1
//printf("%s\n","Segundo");
glTexCoord2f(1.0f, 0.0f);
glColor3f(terrain[x+1][z][1]/255.0f, terrain[x+1][z][1]/255.0f, terrain[x+1][z][1]/255.0f);
glVertex3f(terrain[x+1][z][0], terrain[x+1][z][1], terrain[x+1][z][2]);
// draw vertex 2
//printf("%s\n","Terceiro");
glTexCoord2f(0.0f, 1.0f);
glColor3f(terrain[x][z+1][1]/255.0f, terrain[x][z+1][1]/255.0f, terrain[x][z+1][1]/255.0f);
glVertex3f(terrain[x][z+1][0], terrain[x][z+1][1], terrain[x][z+1][2]);
// draw vertex 3
//printf("%s\n","Quarto");
glColor3f(terrain[x+1][z+1][1]/255.0f, terrain[x+1][z+1][1]/255.0f, terrain[x+1][z+1][1]/255.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(terrain[x+1][z+1][0], terrain[x+1][z+1][1], terrain[x+1][z+1][2]);
}
glEnd();
}
// enable blending
glEnable(GL_BLEND);
// enable read-only depth buffer
glDepthMask(GL_FALSE);
// set the blend function to what we use for transparency
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
// set back to normal depth buffer mode (writable)
glDepthMask(GL_TRUE);
// disable blending
glDisable(GL_BLEND);
glFlush();
//SwapBuffers(g_HDC); // bring backbuffer to foreground
}
Update: As requested, here is the other functions from my code.
void InitializeTerrain()
{
// loop through all of the heightfield points, calculating
// the coordinates for each point
for (int z = 0; z < MAP_Z; z++)
{
for (int x = 0; x < MAP_X; x++)
{
terrain[x][z][0] = float(x)*MAP_SCALE;
terrain[x][z][1] = (float)imageData[(z*MAP_Z+x)*3];
terrain[x][z][2] = -float(z)*MAP_SCALE;
}
}
}
void CleanUp()
{
free(imageData);
free(landTexture);
}
// Initialize
// desc: initializes OpenGL
void Initialize()
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // clear to black
glShadeModel(GL_SMOOTH); // use smooth shading
glEnable(GL_DEPTH_TEST); // hidden surface removal
glEnable(GL_CULL_FACE); // do not calculate inside of poly's
glFrontFace(GL_CCW); // counter clock-wise polygons are out
glEnable(GL_TEXTURE_2D); // enable 2D texturing
imageData = LoadBitmapFile("terrain2.bmp", &bitmapInfoHeader);
// initialize the terrain data and load the textures
InitializeTerrain();
LoadTextures();
}
// Função callback chamada quando o tamanho da janela é alterado
void AlteraTamanhoJanela(GLsizei w, GLsizei h)
{
int width, height;
height = h; // retrieve width and height
width = w;
if (height==0) // don't want a divide by zero
{
height=1;
}
glViewport(0, 0, width, height); // reset the viewport to new dimensions
glMatrixMode(GL_PROJECTION); // set projection matrix current matrix
glLoadIdentity(); // reset projection matrix
// calculate aspect ratio of window
gluPerspective(54.0f,(GLfloat)width/(GLfloat)height,1.0f,1000.0f);
glMatrixMode(GL_MODELVIEW); // set modelview matrix
glLoadIdentity(); // reset modelview matrix
}
// Função callback chamada para gerenciar eventos do mouse
void GerenciaMouse(int button, int state, int x, int y)
{
int oldMouseX, oldMouseY;
// save old mouse coordinates
oldMouseX = mouseX;
oldMouseY = mouseY;
// get mouse coordinates from Windows
mouseX = x;
mouseY = y;
// these lines limit the camera's range
if (mouseY < 200)
mouseY = 200;
if (mouseY > 450)
mouseY = 450;
if ((mouseX - oldMouseX) > 0) // mouse moved to the right
angle += 3.0f;
else if ((mouseX - oldMouseX) < 0) // mouse moved to the left
angle -= 3.0f;
glutPostRedisplay();
}
/* Key press processing */
void GerenciaTeclado(unsigned char c, int x, int y)
{
if(c == 27) exit(0);
}
And, finally, the content from file vkgllib.h, included by source code file above:
#include <iostream>
#include <fstream>
#include <math.h>
#include <stdlib.h>
using namespace std;
#define WINDOW_WIDTH 640 // Window Width Default
#define WINDOW_HEIGHT 480 // Window Height Default
// definition of PI
#define PI 3.14159265
// Used to defien the title of the window
#define WINDOW_TITLE "OpenGL Terrain Generation"
// A simple structure to define a point whose coordinates are integers
/*typedef struct { GLint x, y; } GLintPoint;
// This structure is used to store the vertices of a polyline
typedef struct { int num; GLintPoint pt[100]; } GLintPointArray;
// Data for an Icosahedron
#define ICO_X 0.525731112119133606
#define ICO_Z 0.850650808352039932*/
/*static GLfloat vdataICO[12][3] =
{
{ -ICO_X, 0.0, ICO_Z }, { ICO_X, 0.0, ICO_Z }, { -ICO_X, 0.0, -ICO_Z }, { ICO_X, 0.0, -ICO_Z },
{ 0.0, ICO_Z, ICO_X }, { 0.0, ICO_Z, -ICO_X }, { 0.0, -ICO_Z, ICO_X }, { 0.0, -ICO_Z, -ICO_X },
{ ICO_Z, ICO_X, 0.0 }, { -ICO_Z, ICO_X, 0.0 }, { ICO_Z, -ICO_X, 0.0 }, { -ICO_Z, -ICO_X, 0.0 }
};
static GLuint tindicesICO[20][3] =
{
{ 1, 4, 0 }, { 4, 9, 0 }, { 4, 5, 9 }, { 8, 5, 4 }, { 1, 8, 4 },
{ 1, 10, 8 }, { 10, 3, 8 }, { 8, 3, 5 }, { 3, 2, 5 }, { 3, 7, 2 },
{ 3, 10, 7 }, { 10, 6, 7 }, { 6, 11, 7 }, { 6, 0, 11 }, {6, 1, 0 },
{ 10, 1, 6 }, { 11, 0, 9 }, { 2, 11, 9 }, { 5, 2, 9 }, { 11, 2, 7 }
};*/
// Data for Tetrahedron
static GLfloat P1T[3] = { -2, 3, 0 };
static GLfloat P2T[3] = { -3, 0, 0 };
static GLfloat P3T[3] = { -1, 0, 3 };
static GLfloat P4T[3] = { -4, 0, 0 };
// Calculating the Normalized Cross Product of Two Vectors
void normalize( float v[3] )
{
GLfloat d = sqrt( float(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]) );
if( d==0.0 )
{
cerr<<"zero length vector"<<endl;
return;
}
v[0] /= d;
v[1] /= d;
v[2] /= d;
}
void normcrossprod( float v1[3], float v2[3], float out[3] )
{
out[0] = v1[1]*v2[2] - v1[2]*v2[1];
out[1] = v1[2]*v2[0] - v1[0]*v2[2];
out[2] = v1[0]*v2[1] - v1[1]*v2[0];
normalize( out );
}
////// Defines
#define BITMAP_ID 0x4D42 // the universal bitmap ID
#define MAP_X 32 // size of map along x-axis
#define MAP_Z 32 // size of map along z-axis
#define MAP_SCALE 20.0f // the scale of the terrain map
////// Texture Information
BITMAPINFOHEADER bitmapInfoHeader; // temp bitmap info header
BITMAPINFOHEADER landInfo; // land texture info header
BITMAPINFOHEADER waterInfo; // water texture info header
//AUX_RGBImageRec
unsigned char* imageData; // the map image data
unsigned char* landTexture; // land texture data
unsigned int land; // the land texture object
////// Terrain Data
float terrain[MAP_X][MAP_Z][3]; // heightfield terrain data (0-255); 256x256
// LoadBitmapFile
// desc: Returns a pointer to the bitmap image of the bitmap specified
// by filename. Also returns the bitmap header information.
// No support for 8-bit bitmaps.
unsigned char *LoadBitmapFile(char *filename, BITMAPINFOHEADER *bitmapInfoHeader)
{
FILE *filePtr; // the file pointer
BITMAPFILEHEADER bitmapFileHeader; // bitmap file header
unsigned char *bitmapImage; // bitmap image data
int imageIdx = 0; // image index counter
unsigned char tempRGB; // swap variable
// open filename in "read binary" mode
filePtr = fopen(filename, "rb");
if (filePtr == NULL)
return NULL;
// read the bitmap file header
fread(&bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, filePtr);
// verify that this is a bitmap by checking for the universal bitmap id
if (bitmapFileHeader.bfType != BITMAP_ID)
{
fclose(filePtr);
return NULL;
}
// read the bitmap information header
fread(bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, filePtr);
// move file pointer to beginning of bitmap data
fseek(filePtr, bitmapFileHeader.bfOffBits, SEEK_SET);
// allocate enough memory for the bitmap image data
bitmapImage = (unsigned char*)malloc(bitmapInfoHeader->biSizeImage);
// verify memory allocation
if (!bitmapImage)
{
free(bitmapImage);
fclose(filePtr);
return NULL;
}
// read in the bitmap image data
fread(bitmapImage, 1, bitmapInfoHeader->biSizeImage, filePtr);
// make sure bitmap image data was read
if (bitmapImage == NULL)
{
fclose(filePtr);
return NULL;
}
// swap the R and B values to get RGB since the bitmap color format is in BGR
for (imageIdx = 0; imageIdx < bitmapInfoHeader->biSizeImage; imageIdx+=3)
{
tempRGB = bitmapImage[imageIdx];
bitmapImage[imageIdx] = bitmapImage[imageIdx + 2];
bitmapImage[imageIdx + 2] = tempRGB;
}
// close the file and return the bitmap image data
fclose(filePtr);
return bitmapImage;
}
bool LoadTextures()
{
// load the land texture data
landTexture = LoadBitmapFile("green.bmp", &landInfo);
if (!landTexture)
return false;
// generate the land texture as a mipmap
glGenTextures(1, &land);
glBindTexture(GL_TEXTURE_2D, land);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, landInfo.biHeight, landInfo.biWidth, GL_RGB, GL_UNSIGNED_BYTE, landTexture);
return true;
}
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
^^^^^^^^^^^
You've asked for double-buffering.
And yet your Render() function seems to assume you're using single-buffering:
void Render()
{
...
glFlush();
}
Either switch to GLUT_SINGLE or use glutSwapBuffers() instead of glFlush().
I'm taking the first step into OpenCL coding. I have a framework that I know can at least take an array from the CPU, do an operation in OpenCL, then read back the array (with the right answer). I'm currently trying to improve this by adding a displaced mesh as found in this OpenCL example (slides 18-23; only significant improvement is I changed the VBO to a float3 instead of a float4).
I have set up a shared context as per earlier in those slides and this resource. I tested the VBO with CPU input data (so I know it draws correctly). Also, I create the context before the VBO (as motivated by this thread). Finally, I tried reworking the kernel into the following [edited]:
__kernel void sine_wave(__global float3* pos, int width, int height, float time) {
uint x = get_global_id(0); uint y = get_global_id(1);
pos[y*width+x] = (float3)(1.0f,1.0f,1.0f);
}
Yet, no matter what I do, I cannot get the OpenCL program to update anything. There are no errors, nothing, yet the VBO remains the same as the input data. If I do not specify input data, the points all render at (0,0,0). I can't figure out what could cause this.
Ideas? Thanks,
Ian
PS #1: current system is NVIDIA GTX 580M, on Windows 7 x64, though the code written is intended to be portable.
PS #2: I can provide code if no one has any clues . . .
Well, I figured it out. After further hours of searching, I downloaded NVIDIA's GPU computing toolkit, which appears to be where the linked demo derives from. I then reduced their code down immensely to the following ~220 line source (may it help ye future coders):
#pragma comment(lib,"Opengl32.lib")
#pragma comment(lib,"glu32.lib")
#pragma comment(lib,"OpenCL.lib")
#pragma comment(lib,"glew32.lib")
#pragma comment(lib,"glut32.lib")
// OpenGL Graphics Includes
#include <GL/glew.h>
#if defined (__APPLE__) || defined(MACOSX)
#include <OpenGL/OpenGL.h>
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#ifdef UNIX
#include <GL/glx.h>
#endif
#endif
#include <CL/opencl.h>
// Rendering window vars
const unsigned int window_width = 512;
const unsigned int window_height = 512;
const unsigned int mesh_width = 256;
const unsigned int mesh_height = 256;
// OpenCL vars
cl_context cxGPUContext;
cl_device_id* cdDevices;
cl_command_queue cqCommandQueue;
cl_kernel ckKernel;
cl_mem vbo_cl;
cl_program cpProgram;
size_t szGlobalWorkSize[] = {mesh_width, mesh_height};
// vbo variables
GLuint vbo;
int mouse_old_x, mouse_old_y;
int mouse_buttons = 0;
float rotate_x = 0.0, rotate_y = 0.0;
float translate_z = -3.0;
void mouse(int button, int state, int x, int y) {
if (state == GLUT_DOWN) {
mouse_buttons |= 1<<button;
} else if (state == GLUT_UP) {
mouse_buttons = 0;
}
mouse_old_x = x;
mouse_old_y = y;
}
void motion(int x, int y) {
float dx, dy;
dx = (float)(x - mouse_old_x);
dy = (float)(y - mouse_old_y);
if (mouse_buttons & 1) {
rotate_x += dy * 0.2f;
rotate_y += dx * 0.2f;
} else if (mouse_buttons & 4) {
translate_z += dy * 0.01f;
}
mouse_old_x = x;
mouse_old_y = y;
}
void DisplayGL(void) {
static float anim = 0.0f;
// run OpenCL kernel to generate vertex positions
glFinish();
clEnqueueAcquireGLObjects(cqCommandQueue, 1, &vbo_cl, 0,0,0);
clSetKernelArg(ckKernel, 3, sizeof(float), &anim);
clEnqueueNDRangeKernel(cqCommandQueue, ckKernel, 2, NULL, szGlobalWorkSize, NULL, 0,0,0 );
clEnqueueReleaseGLObjects(cqCommandQueue, 1, &vbo_cl, 0,0,0);
clFinish(cqCommandQueue);
// set view matrix
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0.0, 0.0, translate_z);
glRotatef(rotate_x, 1.0, 0.0, 0.0);
glRotatef(rotate_y, 0.0, 1.0, 0.0);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexPointer(4, GL_FLOAT, 0, 0);
glEnableClientState(GL_VERTEX_ARRAY);
glColor3f(1.0, 0.0, 0.0);
glDrawArrays(GL_POINTS, 0, mesh_width * mesh_height);
glDisableClientState(GL_VERTEX_ARRAY);
// flip backbuffer to screen
glutSwapBuffers();
anim += 0.01f;
}
void timerEvent(int value) {
glutPostRedisplay();
glutTimerFunc(10, timerEvent,0);
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
glutInitWindowPosition (glutGet(GLUT_SCREEN_WIDTH)/2 - window_width/2, glutGet(GLUT_SCREEN_HEIGHT)/2 - window_height/2);
glutInitWindowSize(window_width, window_height);
glutCreateWindow("OpenCL/GL Interop (VBO)");
glutDisplayFunc(DisplayGL);
glutMouseFunc(mouse);
glutMotionFunc(motion);
glutTimerFunc(10, timerEvent,0);
glewInit();
glClearColor(0.0, 0.0, 0.0, 1.0);
glDisable(GL_DEPTH_TEST);
glViewport(0, 0, window_width, window_height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (GLfloat)window_width / (GLfloat) window_height, 0.1, 10.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//Get the NVIDIA platform
cl_platform_id cpPlatform;
clGetPlatformIDs(1,&cpPlatform,NULL);
// Get the number of GPU devices available to the platform
cl_uint uiDevCount;
clGetDeviceIDs(cpPlatform, CL_DEVICE_TYPE_GPU, 0, NULL, &uiDevCount);
// Create the device list
cdDevices = new cl_device_id [uiDevCount];
clGetDeviceIDs(cpPlatform, CL_DEVICE_TYPE_GPU, uiDevCount, cdDevices, NULL);
// Define OS-specific context properties and create the OpenCL context
#if defined (__APPLE__)
CGLContextObj kCGLContext = CGLGetCurrentContext();
CGLShareGroupObj kCGLShareGroup = CGLGetShareGroup(kCGLContext);
cl_context_properties props[] =
{
CL_CONTEXT_PROPERTY_USE_CGL_SHAREGROUP_APPLE, (cl_context_properties)kCGLShareGroup,
0
};
cxGPUContext = clCreateContext(props, 0,0, NULL, NULL, &ciErrNum);
#else
#ifdef UNIX
cl_context_properties props[] =
{
CL_GL_CONTEXT_KHR, (cl_context_properties)glXGetCurrentContext(),
CL_GLX_DISPLAY_KHR, (cl_context_properties)glXGetCurrentDisplay(),
CL_CONTEXT_PLATFORM, (cl_context_properties)cpPlatform,
0
};
cxGPUContext = clCreateContext(props, 1, &cdDevices[uiDeviceUsed], NULL, NULL, &ciErrNum);
#else // Win32
cl_context_properties props[] =
{
CL_GL_CONTEXT_KHR, (cl_context_properties)wglGetCurrentContext(),
CL_WGL_HDC_KHR, (cl_context_properties)wglGetCurrentDC(),
CL_CONTEXT_PLATFORM, (cl_context_properties)cpPlatform,
0
};
cxGPUContext = clCreateContext(props, 1, &cdDevices[0], NULL, NULL, NULL);
#endif
#endif
// create a command-queue
cqCommandQueue = clCreateCommandQueue(cxGPUContext, cdDevices[0], 0, NULL);
const char* cSourceCL = "__kernel void sine_wave(__global float4* pos, unsigned int width, unsigned int height, float time)\n"
"{\n"
" unsigned int x = get_global_id(0);\n"
" unsigned int y = get_global_id(1);\n"
"\n"
" // calculate uv coordinates\n"
" float u = x / (float) width;\n"
" float v = y / (float) height;\n"
" u = u*2.0f - 1.0f;\n"
" v = v*2.0f - 1.0f;\n"
"\n"
" // calculate simple sine wave pattern\n"
" float freq = 4.0f;\n"
" float w = sin(u*freq + time) * cos(v*freq + time) * 0.5f;\n"
"\n"
" // write output vertex\n"
" pos[y*width+x] = (float4)(u, w, v, 1.0f);\n"
"}\n";
cpProgram = clCreateProgramWithSource(cxGPUContext, 1, (const char **) &cSourceCL, NULL, NULL);
clBuildProgram(cpProgram, 0, NULL, "-cl-fast-relaxed-math", NULL, NULL);
// create the kernel
ckKernel = clCreateKernel(cpProgram, "sine_wave", NULL);
// create VBO (if using standard GL or CL-GL interop), otherwise create Cl buffer
unsigned int size = mesh_width * mesh_height * 4 * sizeof(float);
glGenBuffers(1,&vbo);
glBindBuffer(GL_ARRAY_BUFFER,vbo);
// initialize buffer object
glBufferData(GL_ARRAY_BUFFER, size, 0, GL_DYNAMIC_DRAW);
// create OpenCL buffer from GL VBO
vbo_cl = clCreateFromGLBuffer(cxGPUContext, CL_MEM_WRITE_ONLY, vbo, NULL);
// set the args values
clSetKernelArg(ckKernel, 0, sizeof(cl_mem), (void *) &vbo_cl);
clSetKernelArg(ckKernel, 1, sizeof(unsigned int), &mesh_width);
clSetKernelArg(ckKernel, 2, sizeof(unsigned int), &mesh_height);
glutMainLoop();
}
After comparison with my original code, I (eventually) found the key difference.
Right:
clEnqueueNDRangeKernel(context->command_queue, kernel->kernel, 2, NULL, global,NULL, 0,0,0 );
Wrong:
clEnqueueNDRangeKernel(context->command_queue, kernel->kernel, 2, NULL, global,local, 0,0,0 );
It turns out that the grid size I was using, 10x10, was smaller than the examples I had seen elsewhere, which told me to use 16x16 for "local". Because "global" is the grid size, "global" was smaller than "local".
For some reason this didn't cause any errors, though at this point I honestly can't say I understand these variables' purposes completely.
Ian