How do you draw the following dynamic 3D array with OpenGL glDrawPixels()?
You can find the documentation here: http://opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/drawpixels.html
float ***array3d;
void InitScreenArray()
{
int i, j;
int screenX = scene.camera.vres;
int screenY = scene.camera.hres;
array3d = (float ***)malloc(sizeof(float **) * screenX);
for (i = 0 ; i < screenX; i++) {
array3d[i] = (float **)malloc(sizeof(float *) * screenY);
for (j = 0; j < screenY; j++)
array3d[i][j] = (float *)malloc(sizeof(float) * /*Z_SIZE*/ 3);
}
}
I can use only the following header files:
#include <math.h>
#include <stdlib.h>
#include <windows.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
Uh ... Since you're allocating each single pixel with a separate malloc(), you will have to draw each pixel with a separate call to glDrawPixels(), too. This is (obviously) insane; the idea of bitmapped graphics is that the pixels are stored in an adjacent, compact, format, so that it is quick and fast (O(1)) to move from one pixel to another. This looks very confused to me.
A more sensible approach would be to allocate the "3D array" (which is often referred to as a 2D array of pixels, where each pixel happens to consist of a red, green and blue component) with a single call to malloc(), like so (in C):
float *array3d;
array3d = malloc(scene.camera.hres * scene.camera.vres * 3 * sizeof *array3d);
Thanks unwind. I got the same advice on gamedev.net so I have implemented the following algorithm:
typedef struct
{
GLfloat R, G, B;
} color_t;
color_t *array1d;
void InitScreenArray()
{
long screenX = scene.camera.vres;
long screenY = scene.camera.hres;
array1d = (color_t *)malloc(screenX * screenY * sizeof(color_t));
}
void SetScreenColor(int x, int y, float red, float green, float blue)
{
int screenX = scene.camera.vres;
int screenY = scene.camera.hres;
array1d[x + y*screenY].R = red;
array1d[x + y*screenY].G = green;
array1d[x + y*screenY].B = blue;
}
void onDisplay( )
{
glClearColor(0.1f, 0.2f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glRasterPos2i(0,0);
glDrawPixels(scene.camera.hres, scene.camera.vres, GL_RGB, GL_FLOAT, array1d);
glFinish();
glutSwapBuffers();
}
My application doesn't work yet (nothing appears on screen), but I think it's my fault and this code will work.
wouldn't you want to use glTexImage2D() instead: see here
Related
I tried to scroll text horizontally in a OpenGL app. The text comes perfect and smooth part by part at the screen when starting from the right side. When the first letter then touches the side of the window at the left side, the whole text disappears. I want that the text goes over the border, so that it vanished smoothly and start again from the right side. It's a sort of banner i try to make. Someone who knows how to solve this problem?
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <iostream>
#ifdef WIN32
#include <windows.h>
#endif
#include <GL/gl.h>
#include <GL/glut.h>
using namespace std;
//static int font_index = 0;
int state = 1;
float xsize = 800;
float ysize = 300;
void print_bitmap_string(/*void* font,*/ const char* s)
{
while (*s) {
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, *s);
s++;
}
}
void reshape(int w, int h)
{
GLdouble size;
GLdouble aspect;
/* Use the whole window. */
glViewport(0, 0, w, h);
/* We are going to do some 2-D orthographic drawing. */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
size = (GLdouble)((w >= h) ? w : h) / 2.0;
if (w <= h) {
aspect = (GLdouble)h / (GLdouble)w;
glOrtho(-size, size, -size * aspect, size * aspect, -100000.0, 100000.0);
}
else {
aspect = (GLdouble)w / (GLdouble)h;
glOrtho(-size * aspect, size * aspect, -size, size, -100000.0, 100000.0);
}
/* Make the world and window coordinates coincide so that 1.0 in */
/* model space equals one pixel in window space. */
glScaled(aspect, aspect, 1.0);
/* Now determine where to draw things. */
//glMatrixMode(GL_MODELVIEW);
//glLoadIdentity();
}
float yild;
float ystep;
float x_pos = xsize/2;
float y_pos = 70;
void draw()
{
const char* bitmap_font_names[7] = { "Testing train application for windows!!##" };
glPushMatrix();
/* Draw the strings, according to the current mode and font. */
glTranslatef(0.5, -100, 0);
//set the text color
glColor4f(0.0f, 173.0f, 115.0f, 1.0f);
//ystep = 100.0;
//yild = 20.0;
glRasterPos2f(x_pos, y_pos /* + 1.25 * yild*/);
print_bitmap_string(bitmap_font_names[0]);
glPopMatrix();
}
void display(void)
{
//change background color
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
draw();
glColor3f(0.0, 255.0, 0.0);
/*glBegin(GL_TRIANGLES);
glVertex2f(20 + x_pos, 0 + y_pos);
glVertex2f(50 + x_pos, 10 + y_pos);
glVertex2f(20 + x_pos, 20 + y_pos);
glEnd();*/
glutSwapBuffers();
}
void timer(int) {
glutPostRedisplay();
glutTimerFunc(1000 / 90, timer, 0);
switch (state) {
case 1:
if (x_pos > (-xsize / 2) - 200) {
x_pos -= 1;
}
else {
state = -1;
}
break;
case -1:
x_pos = (xsize / 2);
state = 1;
break;
}
cout << x_pos << endl;
}
int main(int argc, char** argv)
{
glutInitWindowSize(xsize, ysize);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
glutCreateWindow("Train Display");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutTimerFunc(1000, timer, 0);
glutMainLoop();
return 0;
}
It looks like OpenGL may not allow you to explicitly draw bitmaps outside of the viewport.
From the documentation on glRasterPos,
To set a valid raster position outside the viewport, first set a valid raster position, then call glBitmap with NULL as the bitmap parameter.
The documentation on glBitmap elaborates on this aspect:
To set a valid raster position outside the viewport, first set a valid raster position inside the viewport, then call glBitmap with NULL as the bitmap parameter and with xmove and ymove set to the offsets of the new raster position. This technique is useful when panning an image around the viewport.
I am having a small problem in essentially creating a path tracer.
In my project, I have an object which constantly moves around quite organically through an update function done in the while loop. I use immediate mode and represent the player as a square, I would like to make it so that every update the object is drawn in its current position, but also for it to draw it's previous position(s), so etching dots towards the path the object is going. I'm pretty sure we can do this by drawing the position as normal but not clearing everything up after this instance in the while loop, but I have no knowledge on how to do this.
Edit: For those who want the code, do understand that this code, in particular, is not adherent to the question and that I made a ton of generalizations (such as the particle(s) being referred to an object) so that the general gist of the question is understandable:
#include "PerlinNoise.hpp"
#include "Particle.hpp"
#include <iostream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <cmath>
#include <vector>
using namespace siv;
float map(float oValue, float oMin, float oMax, float nMin, float nMax)
{
float oRange = (oMax - oMin);
float nRange = (nMax - nMin);
return(((oValue - oMin) * nRange)/oRange) + nMin;
}
void drawRectangle(float x, float y, float xr, float yr, float R, float G, float B)
{
glBegin(GL_QUADS);
glColor3f(R,G,B);
glVertex2f(x,y);
glVertex2f(x+xr,y);
glVertex2f(x+xr,y+yr);
glVertex2f(x,y+yr);
glEnd();
}
void drawLine(float x, float y, float xr, float yr, float rotation)
{
float radius = sqrt(xr*xr + yr*yr);
float a0 = asin(yr/radius);
float tangle = a0+rotation;
//std::cout<<tangle*180/M_PI<<std::endl;
glBegin(GL_LINES);
glColor3f(.1,.1,.1);
glVertex2f(x,y);
glVertex2f(x + sin(tangle)*radius,y + cos(tangle)*radius);
glEnd();
}
int main()
{
float inc = 0.1;
int scl = 20;
int cols,rows;
Particle particles[100000];
//V2D flowfield[cols*rows];
GLFWwindow* window;
if (!glfwInit())
return 1;
int width = 800;
int height = 800;
window = glfwCreateWindow(width, height, "Window", NULL, NULL);
cols = floor(width/scl);
rows = floor(height/scl);
V2D flowfield[cols*rows];
float zoff = 0;
if (!window) {
glfwTerminate();
return 1;
}
glfwMakeContextCurrent(window);
if(glewInit()!=GLEW_OK)
std::cout<<"Error"<<std::endl;
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glfwGetFramebufferSize(window, &width, &height);
glOrtho(0, width*(width/height), height, 0, -2, 2);
PerlinNoise png = PerlinNoise(1);
while(!glfwWindowShouldClose(window)) {
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glClearColor(0.11, 0.14, 0.17, 1);
float yoff = 0;
for(int y = 0; y < rows; y++)
{
float xoff = 0;
for(int x = 0; x < cols; x++)
{
double noise = map(png.noise((double)xoff, (double)yoff, (double)zoff),-1,1,0,1);
double angle = noise * 8 *M_PI;
//std::cout<<angle/(2*M_PI)<<std::endl;
int index = x + y * cols;
V2D v = V2D(cos(angle), sin(angle));
v.normalize();
v = V2D(v.x*5,v.y*5);
flowfield[index] = v;
//drawLine(x*scl, y*scl, scl, 0, atan2(v.x, v.y));
//drawRectangle(x*scl,y*scl,scl,scl,noise,noise,noise);
xoff += inc;
}
yoff += inc;
zoff += 0.0001;
}
for(int i = 0; i < 100000; i++)
{
particles[i].follow(flowfield);
particles[i].update();
particles[i].show();
}
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
}
When drawing directly to a window (be it double buffered or not doesn't make a difference) you must not make any assumptions about its contents being persistent between drawing. Heck, strictly speaking the contents may become damaged mid draw, before things even finished up; of course in practice this isn't very likely to happen and given modern compositing graphics systems it's practically eliminated.
Your application screams for drawing to an intermediary framebuffer object. FBOs are guaranteed to retain their contents no matter what happens; also you can add further drawing to the backing buffer of an FBO at any time.
The official OpenGL wiki describes FBOs at https://www.khronos.org/opengl/wiki/Framebuffer_Object
Also ages ago I wrote a simple codesample (using a lot of outdated, legacy OpenGL); drawing is legacy, but the FBO parts are done today as it was 10 years ago: https://github.com/datenwolf/codesamples/blob/master/samples/OpenGL/minimalfbo/minimalfbo.c (I implemented it using render to texture; a render to renderbuffer and buffer blit to main framebuffer would work for you, 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 am using GL_TRIANGLE_FAN to draw a circle. When I use other Triangle primitives, I get some triangles, but when I use GL_TRIANGLE_FAN, I ge a blank screen. I am new to this, and I am not getting where I am going wrong.
#include <string>
#include <fstream>
#include <iostream>
#include <sstream>
#include <vector>
//Include GLEW
#include <GL/glew.h>
//Include GLFW
#include <glfw3.h>
#include <GL/glut.h>
#include <GL/gl.h>
#include <math.h>
int width;
int height;
float r;
float theta;
GLuint vboHandle[1];
GLuint indexVBO;
struct vertex
{
double x, y;
double u, v;
double r, g, b;
}temp;
std::vector<vertex> vertices;
std::vector<GLuint64> indeces;
void initNormal(){
float a=0;
int value1 = 1;
double radius = 0.3;
double centerX = 0;
double centerY = 0;
double theta = 0;
//u,v,r,g,b are dummy for now
temp.x = 0;
temp.y = 0;
temp.u = a;
temp.v = a;
temp.r = a;
temp.g = a;
temp.b = a;
vertices.push_back(temp);
indeces.push_back(0);
for (int i = 1; i <= 72; i++){
a = a+0.10;
temp.x = radius*cos(((22 / 7.0) / 180.0)*theta);
temp.y = radius*sin(((22 / 7.0) / 180.0)*theta);
temp.u = a;
temp.v = a;//value1 / (i * 2);
temp.r = a;//value1 / i;
temp.g = a; //value1 / (i * 2);
temp.b = a;//value1 / i;
std::ofstream ofs;
vertices.push_back(temp);
indeces.push_back(i);
theta = theta + 10;
}
}
void initVbo(){
GLenum err = glewInit();
if (err != GLEW_OK) {
fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
//return -1;
}
glPointSize(10);
glGenBuffers(1, &vboHandle[0]); // create a VBO handle
glBindBuffer(GL_ARRAY_BUFFER, vboHandle[0]); // bind the handle to the current VBO
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex)* vertices.size(), &vertices[0], GL_DYNAMIC_DRAW); // allocate space and copy the data over
glBindBuffer(GL_ARRAY_BUFFER, 0); // clean up
glGenBuffers(1, &indexVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexVBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint64)*indeces.size(), &indeces[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //clean up
}
void display(){
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
glColor4f(1, 1, 1, 1);
glEnableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, vboHandle[0]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexVBO);
glVertexPointer(2, GL_DOUBLE, sizeof(vertex), 0);
glDrawElements(GL_TRIANGLES, indeces.size(), GL_UNSIGNED_INT, (char*)NULL + 0);//2 indeces needed to make one line
glFlush();
}
void initializeGlut(int argc, char** argv){
std::cout << "entered";
glutInit(&argc, argv);
width = 800;
height = 800;
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowSize(width, height);
glutCreateWindow("Bhavya's Program");
glutDisplayFunc(display);
}
void main(int argc, char** argv){
initializeGlut(argc, argv);
initNormal();
initVbo();
//glutReshapeFunc(reshape);
glutMainLoop();
}
The main problem in your code is that you're using the wrong type for the index values:
std::vector<GLuint64> indeces;
GLuint64 is not a valid index type, and it certainly does not match the index type specified in the draw command:
glDrawElements(GL_TRIANGLES, indeces.size(), GL_UNSIGNED_INT, ...);
Replace all occurrences of GLuint64 with the correct type, which is GLuint, and you should start seeing something.
The reason you're not seeing anything at all when drawing with GL_TRIANGLE_FAN becomes clearer if you picture the memory layout of the index buffer with the wrong type. If you write a sequence of 64-bit values, which are then interpreted as 32-bit values, every second value will be read as value 0.
With GL_TRIANGLE_FAN, all triangles are formed from the first index (which you set to 0) and two sequential indices from the array. With every second index read as 0, this means that every triangle has two indices of value 0. Which in turn means that all triangles are degenerate, and will not light up any pixels.
The circle drawing code will need some improvement as well. Right now you're looping from 0 to 720 degrees, which will go around the circle twice. Also, 22/7 is a very rough approximation of pi. You may want to use a more precise constant definition from a math header file instead.
While it's not a correctness problem, I would also avoid using double values for vertex attributes. OpenGL implementations internally uses floats. If you specify the attributes as doubles, you will only use extra memory, and add overhead to convert the values from double to float.
Here's the screenshot of what I am doing. Currently, I'm stuck from drawing a curved borders into this rectangle.
My first solution was: draw a quartered circle behind the rectangle, but if I adjust the opacity of the shape, as you can see, the quartered circle gets shown.
I know this is pretty basic for you guys but I'm not really good at math.
I did try to reuse the computed edges of the arc and add the size of border but I got this as a result.
I also think of bezier curves as a replacement but I think it is more efficient to just reuse the computed vertices and add all the missing ones. Also, I don't know how to compute for the curved points of bezier curves and finding the right amount of t would be very computationally expensive so I don't implement it.
Here's the code how I draw the inner quartered circle and I think I can just reuse it.
void drawArc(int x, int y,
int startAngle, int endAngle,
uint32_t radiusX, uint32_t radiusY,
int border_x, int border_y,
const rgb color,
const rgb bcX, const rgb bcY,
uint8_t opacity)
{
if (radiusX <= 0 || radiusY <= 0) return;
static constexpr float DTR = 3.14159 / 180;
float cx, cy;
int step;
static std::vector<float> verts;
static std::vector<uint8_t> colors;
if (startAngle < endAngle)
{
step = +1;
++ endAngle;
} else
{
step = -1;
-- endAngle;
}
verts.clear();
colors.clear();
verts.push_back(x);
verts.push_back(y);
colors.push_back(color[R]);
colors.push_back(color[G]);
colors.push_back(color[B]);
colors.push_back(opacity);
while (startAngle != endAngle)
{
cx = cos(DTR * startAngle) * radiusX;
cy = sin(DTR * startAngle) * radiusY;
verts.push_back(x + cx);
verts.push_back(y - cy);
colors.push_back(color[R]);
colors.push_back(color[G]);
colors.push_back(color[B]);
colors.push_back(opacity);
startAngle += step;
}
drawElements(GL_POLYGON, sizeof(arcIndices) / sizeof(arcIndices[0]), GL_FLOAT,
&verts[0], &colors[0], &arcIndices[0]);
if (border_x != 0 || border_y != 0)
{
//remove (x, y)
verts.erase(verts.begin(), verts.begin() + 2);
// float px, py;
//
// px = *(verts.begin() + 0);
// py = *(verts.begin() + 1);
//
// glPointSize(5);
//
// glBegin(GL_POINTS);
//
// glColor3ub(0,0,255);
// glVertex2i(px, py);
//
// px = *(verts.end() - 2);
// py = *(verts.end() - 1);
//
// glColor3ub(255,0,0);
// glVertex2i(px , py);
// glEnd();
//attempting to reuse the edges
//I think the last vertices are opposed
//that's why I got a crossed out lines??
for (int i = 0;i <= 90; ++i)
{
verts.push_back(verts[i + 0] + border_x);
verts.push_back(verts[i + 1] + border_y);
colors.push_back(bcX[R]);
colors.push_back(bcX[G]);
colors.push_back(bcX[B]);
colors.push_back(opacity);
}
//91 = steps from 0-90 degree revolution
//182 = 91 * 2
unsigned int index[182 + 91 * 2];
for (int i = 0;i < 182 + 91 * 2; ++i)
index[i] = i;
drawElements(GL_LINE_LOOP, verts.size() / 2, GL_FLOAT,
&verts[0], &colors[0], &index[0]);
}
}
Edit:
Can't I just reuse the pre-calculated (x,y) before?
Sorry for too much use of pictures
The red dots are pre-calculated (x, y) I'm referring to and just append the next arc base on this.
I'm gonna render many of this kind so I need as efficient as possible(w/o too much use to trigo functions).
Update:
And here is the result I got from using stencil buffer as what Andon M. Coleman suggested:
Btw, as you can see, I am trying to emulate my own UI using OpenGL :D
You expressed an interest in seeing how this could be solved using the stencil buffer yesterday, so I am following up with some basic pseudo-code.
glClearStencil (0x0);
glClear (GL_STENCIL_BUFFER_BIT);
glEnable (GL_STENCIL_TEST);
glStencilFunc (GL_ALWAYS, 0x0, 0x0);
// Add 1 to stencil buffer at every location the object to be bordered is visible
glStencilOp (GL_KEEP, GL_KEEP, GL_INCR);
// Draw your grey object
// Only draw the red border where the grey object was never drawn (stencil = 0x0)
glStencilFunc (GL_EQUAL, 0x0, 0xff);
// Draw your red quarter circles
glDisable (GL_STENCIL_TEST);
Clearing the stencil buffer everytime you draw your outlined object is probably overkill. If you opt to clear the stencil buffer once per-frame instead, you can do some pretty interesting things. For instance, if you drew the outlines as a separate pass after all non-outlined shapes are drawn you could use this stencil buffer setup to outline the union (instead of including the intersection of objects as part of the drawn outline) of any overlapping objects.. this would allow you to construct more complicated shapes from your simple rounded rectangles.
Of course for this to work, your pixel format must have a stencil buffer. I will have to leave that part up to you, because the process of setting that up is implementation specific.
GL_POLYGON is only for convex polygons.
Link together the vertices on your inner and outer radii to form quads/triangles:
#include <GL/glut.h>
#include <cmath>
void Torus2d
(
float angle, // starting angle in radians
float length, // length of arc in radians, >0
float radius, // inner radius, >0
float width, // width of torus, >0
unsigned int samples // number of circle samples, >=3
)
{
if( samples < 3 ) samples = 3;
const float outer = radius + width;
glBegin( GL_QUAD_STRIP );
for( unsigned int i = 0; i <= samples; ++i )
{
float a = angle + ( i / (float)samples ) * length;
glVertex2f( radius * cos( a ), radius * sin( a ) );
glVertex2f( outer * cos( a ), outer * sin( a ) );
}
glEnd();
}
void display()
{
glClear( GL_COLOR_BUFFER_BIT );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
double w = glutGet( GLUT_WINDOW_WIDTH );
double h = glutGet( GLUT_WINDOW_HEIGHT );
double ar = w / h;
glOrtho( -4 * ar, 4 * ar, -4, 4, -1, 1);
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glColor3ub( 255, 0, 0 );
Torus2d( 0, 1.57079633, 2, 1, 20 );
glutSwapBuffers();
}
int main( int argc, char **argv )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE );
glutInitWindowSize( 640, 480 );
glutCreateWindow( "GLUT" );
glutDisplayFunc( display );
glutMainLoop();
return 0;
}