Calculate grid width given a set of points - opengl

I am drawing a grid in opengl using this -
void draw_grid()
{
glColor3f(0.32, 0.32, 0.32);
int iterations = int(WIDTH / grid_width) + 1;
glBegin(GL_LINES);
for (int i = 0; i < iterations; i++)
{
int x = i * grid_width;
glVertex2f(x, 0);
glVertex2f(x, HEIGHT);
}
for (int i = 0; i < iterations; i++)
{
int y = i * grid_width;
glVertex2f(0, y);
glVertex2f(WIDTH, y);
}
glEnd();
}
And, then I plot points at the intersections of this grid.
I am implementing simple dda method for drawing lines.
For endpoints (2,3) and (15, 8) I get this as output -
But, for endpoints (2,3) and (35, 8) I get this -
You can see that for the second case some points get plotted outside the window and thus are not visible.
This happens because I have hardcoded the grid_width.
I understand that more the difference between the endpoints the smaller the grid_width is supposed to be.
But I can't figure out how exactly to calculate the grid_width so that no matter what endpoints are given they are drawn in the bounds of the window.

You have to determine the grid_width depending on the maximum coordinate. The maximum width of the grid is WIDTH / maxC where maxC is the maximum coordinate. e.g.:
grid_width = int(WIDTH / maxC);

Related

SDL2 function to draw a filled circle

I am looking for a function that draws a filled circle using SDL2 without using a renderer at all. I currently have this:
void Circle(int center_x, int center_y, int radius, SDL_Color color) {
eraseOldCircle();
uint32_t *pixels = (uint32_t *) windowSurface->pixels;
SDL_PixelFormat *windowFormat = windowSurface->format;
SDL_LockSurface(windowSurface); // Lock surface for direct pixel access capability
int radiussqrd = radius * radius;
for(int x=center_x-radius; x<=center_x+radius; x++) {
int dx = center_x - x;
for(int y=center_y-radius; y<=center_y+radius; y++) {
int dy = center_y - y;
if((dy * dy + dx * dx) <= radiussqrd) {
pixels[(y * WIDTH + x)] = SDL_MapRGB(windowFormat, color.r, color.g, color.b);
}
}
}
SDL_UnlockSurface(windowSurface);
SDL_UpdateWindowSurface(window);
}
which has been adapted from another function I found here, it draws the pixels directly to the windowSurface after calling eraseOldCircle (which puts the game's background image back to the previous position of the circle, effectively erasing it from there.) but it is still too slow for what I need (probably the maths?). What would be the fastest way to draw a circle using direct pixel access? I need it to be high speed so I can use it in a 2D game. I haven't been able to find anything until now, everything I see uses SDL_Renderer, but I should strictly never use it.
Here is eraseOldCircle() in case it helps:
void eraseOldCircle() {
//Calculate previous position of ball
SDL_Rect pos = {circlePosition.x-(radius+steps), circlePosition.y-(radius+steps), radius*radius, radius*2+steps};
SDL_BlitSurface(backgroundImage, &pos, windowSurface, &pos);
}
I'm not too sure how to do it with surfaces and memory management and all that, but if this helps, here is a version using an SDL_Renderer that runs pretty quickly:
void draw_circle(SDL_Renderer *renderer, int x, int y, int radius, SDL_Color color)
{
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
for (int w = 0; w < radius * 2; w++)
{
for (int h = 0; h < radius * 2; h++)
{
int dx = radius - w; // horizontal offset
int dy = radius - h; // vertical offset
if ((dx*dx + dy*dy) <= (radius * radius))
{
SDL_RenderDrawPoint(renderer, x + dx, y + dy);
}
}
}
}
If you draw many circles, I would guess SDL_UpdateWindowSurface is where you spend the most time. Try this instead
SDL_LockSurface
// erase and draw all circles (possibly >1000)
SDL_UnlockSurface
SDL_UpdateWindowSurface
You can optimize your circle drawing code a bit, but it is probably fast enough. I also think that SDL_Renderer is probably fast enough.
The documentation for SDL_UpdateWindowSurface says it will copy the surface to the screen. You only need to do this once per frame.

Changing a heightmap so it show 16 hieghtmaps on a 4x4 grid

Change the program to display 16 identical heightmaps arranged in a 4 x 4 grid. The edges of the heightmaps should be side by side in X and Z coordinates. However, they will not touch in the Y direction because the heights will be different.
C++
The below code is what I have already, i am just not too sure how to make it show the 16 identical heightmaps arranged in a 4x4 grid. I know it has to do with the squares on the height map, but i am very confused.
const int HEIGHTMAP_SIZE = 12;
float heights[HEIGHTMAP_SIZE + 1][HEIGHTMAP_SIZE + 1];
initDisplay();
for (unsigned int x = 0; x <= HEIGHTMAP_SIZE; x++)
{
for (unsigned int z = 0; z <= HEIGHTMAP_SIZE; z++)
{
heights[x][z] = (x % 2) * 0.5f -
z * z * 0.05f;
}
}
//TextureManager::activate("rainbow.bmp");
initHeightmapDisplayList();
void initHeightmapHeights()
{
for (unsigned int x0 = 0; x0 < HEIGHTMAP_SIZE; x0++)
{
unsigned int x1 = x0 + 1;
float tex_x0 = (float)(x0) / HEIGHTMAP_SIZE;
float tex_x1 = (float)(x1) / HEIGHTMAP_SIZE;
glBegin(GL_TRIANGLE_STRIP);
for (unsigned int z = 0; z <= HEIGHTMAP_SIZE; z++)
{
float tex_z = (float)(z) / HEIGHTMAP_SIZE;
glTexCoord2d(tex_x1, tex_z);
glVertex3d(x1, heights[x1][z], z);
glTexCoord2d(tex_x0, tex_z);
glVertex3d(x0, heights[x0][z], z);
}
glEnd();
}
}
void initHeightmapDisplayList()
{
heightmap_list.begin();
glEnable(GL_TEXTURE_2D);
TextureManager::activate("ground.bmp");
glColor3d(1.0, 1.0, 1.0);
initHeightmapHeights();
glDisable(GL_TEXTURE_2D);
heightmap_list.end();
}
I suspect that your TextureManager already has a way of doing this without direct calls to OpenGL.
What you should do is make the texture repeat itself.
glTexParamteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
By then scaling your texture coordinates up by a factor of 4, you would obtain a 4x4 grid of the original texture.

Get OpenGL point size in pixels on Windows?

I am using OpenGL in WinAPI to create a 2D line graph. My points are plotted in point size 8, and I want to adjust the height of the plotted points (and the line connecting them) so that the bottom of the point is at the proper y-position (i.e., so that a point at 0 isn't split by the x-axis).
I had an adjustment hard-coded, but I would rather have it scale with the plotted point size, so that when it's plotted in a different size window, it works the same.
Here is my method for plotting the points and the line connecting them:
void plotScores() {
if (samples > 1) { //if this is at least the second score, connect the scores with a line
glLineWidth(12.0);
GLdouble lineXPos = 0, lineYPos = 0;
glColor3d(0.3, 0.3, 0.3);
glBegin(GL_LINE_STRIP);
for (int i = 0; i < scores.size(); i++) {
lineXPos = (i * 0.05) - 0.88;
lineYPos = ((scores[i] - 0.5) * 1.6); //need to adjust this for line y-position...
glVertex2d(lineXPos, lineYPos);
}
glEnd();
}
for (int i = 0; i < scores.size(); i++) {
GLdouble pointXPos = (i * 0.05) - 0.88;
GLdouble pointYPos = ((scores[i] - 0.5) * 1.6); //...and this for point y-position
if (scores[i] >= threshold) {
glColor3d(0.0, 1.0, 0.2);
}
else {
glColor3d(1.0, 0.2, 0.0);
}
glBegin(GL_POINTS);
glVertex2d(pointXPos, pointYPos);
glEnd();
}
}
You set the point size with glPointSize, so you should know that value. If you want to query it afterwards for some reason, it can be done with glGet and GL_POINT_SIZE enum.

Drawing a circle in c++ using openGL

I've been trying to draw a circle in c++ using openGL. So far i have a compresses circle and it just has a random line going across the screen.
This is the function I'm using to get this shape.
void Sprite::init(int x, int y, int width, int height, Type mode, float scale) {
_x = x;
_y = y;
_width = width;
_height = height;
//generate buffer if it hasn't been generated
if (_vboID == 0) {
glGenBuffers(1, &_vboID);
}
Vertex vertexData[360];
if (mode == Type::CIRCLE) {
float rad = 3.14159;
for (int i = 0; i < 359; i++) {
vertexData[i].setPosition((rad * scale) * cos(i), (rad * scale) * sin(i));
}
}
//Tell opengl to bind our vertex buffer object
glBindBuffer(GL_ARRAY_BUFFER, _vboID);
//Upload the data to the GPU
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
//Unbind the buffer
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
What is causing the line? Why is my circle being compressed?
Sorry if this is a dumb question or if this question doesn't belong on this website I'm very new to both c++ as well as this website.
It is difficult to be sure without testing the code myself, but I'll guess anyway.
Your weird line is probably caused by the buffer not being fully initialized. This is wrong:
Vertex vertexData[360];
for (int i = 0; i < 359; i++) {
It should be:
for (int i = 0; i < 360; i++) {
or else the position at vertexData[359] is left uninitialized and contains some far away point.
About the ellipse instead of a circle, that is probably caused by your viewport not having the same scale horizontally and vertically. If you configure the viewport plus transformation matrices to have a viewing frustum of X=-10..10, Y=-10..10, but the actual viewport is X=0..800 and the Y=0..600, for example, then the scale would be different and you'll get your image distorted.
The solution would be one of:
Create a square viewport instead of rectangular. Check your arguments to glViewport().
Define a view matrix to consider the same ratio your viewport has. You don't show how you set the view/world matrix, maybe you are not even using matrices... If that is the case, you should probably use one.
I don't understand, exactly, what you want obtain but... cos() and sin() receive a radiant argument; so, instead of cos(i) and sin(i), I suppose you need cos((2*rad*i)/360.0)) and sin((2*rad*i)/360.0)) or, semplified, cos((rad*i)/180.0)) and cos((rad*i)/180.0))
And what about the center and the radious of the circle?
(x, y) should be the center of the circle?
scale is the radious?
In this case, I suppose you should write something like (caution: not tested)
Vertex vertexData[360];
float rad = 3.14159;
if (mode == Type::CIRCLE) {
for (int i = 0; i < 359; ++i) {
float angle = (rad / 180) * i; // (thanks Rodrigo)
vertexData[i].setPosition(x + scale * cos(angle), y + scale * sin(angle));
}
}
or, loosing precision but avoidind some moltiplication,
Vertex vertexData[360];
float rad = 3.14159;
float angIncr = rad / 180.0;
if (mode == Type::CIRCLE) {
for (int i = 0, float angle = 0.0; i < 359; ++i, angle += angIncr) {
vertexData[i].setPosition(x + scale * cos(angle), y + scale * sin(angle));
}
}
But what about width and heigth?
p.s.: sorry for my bad English.
--- modified with suggestion from Rodrigo --

Rasterisation Algorithm: finding the "ST" coordinates of point in 2D quad and Inverse Projection

My goal is to render the image of a quad using the rasterisation algorithm. I have been as far as:
creating the quad in 3D
projecting the quad's vertices onto the screen using a perspective divide
converting the resulting coordinates from screen space to raster space, and comput the bounding box of the quad in raster space
looping over all pixels inside this bounding box, and finding out if the current pixel P is contained within the quad. For this I am using a simple test which consist of taking the dot between the edge AB of the quad and the vector defined between the vertex A and the point P. I repeat this process for all 4 edges and if the sign is the same, then the point is inside the quad.
I have implemented this successfully (see code below). But I am stuck with the remaining bits which I'd like to play with which is essentially finding the st or texture coordinates of my quad.
I don't know if it's possible to find the st coordinates of the current pixel P in the quad in raster space, and then convert that back into world space? Could you someone please point me in the right direction of tell me how to do this?
alternatively how can I compute the z or depth value of the pixel contained in the quad. I guess it's related to finding the st coordinates of the point in the quad, and then interpolating z values of vertices?
PS: this is NOT a homework. I do this to understand the rasterization algorithm, and precisely where I am stuck now, is the bit I don't understand which I believe in the GPU rendering pipeline involves some sort of inverse projection, but I am just lost at this point. Thanks for your help.
Vec3f verts[4]; // vertices of the quad in world space
Vec2f vraster[4]; // vertices of the quad in raster space
uint8_t outside = 0; // is the quad in raster space visible at all?
Vec2i bmin(10e8), bmax(-10e8);
for (uint32_t j = 0; j < 4; ++j) {
// transform unit quad to world position by transforming each
// one of its vertices by a transformation matrix (represented
// here by 3 unit vectors and a translation value)
verts[j].x = quads[j].x * right.x + quads[j].y * up.x + quads[j].z * forward.x + pt[i].x;
verts[j].y = quads[j].x * right.y + quads[j].y * up.y + quads[j].z * forward.y + pt[i].y;
verts[j].z = quads[j].x * right.z + quads[j].y * up.z + quads[j].z * forward.z + pt[i].z;
// project the vertices on the image plane (perspective divide)
verts[j].x /= -verts[j].z;
verts[j].y /= -verts[j].z;
// assume the image plane is 1 unit away from the eye
// and fov = 90 degrees, thus bottom-left and top-right
// coordinates of the screen are (-1,-1) and (1,1) respectively.
if (fabs(verts[j].x) > 1 || fabs(verts[j].y) > 1) outside |= (1 << j);
// convert image plane coordinates to raster
vraster[j].x = (int32_t)((verts[j].x + 1) * 0.5 * width);
vraster[j].y = (int32_t)((1 - (verts[j].y + 1) * 0.5) * width);
// compute box of the quad in raster space
if (vraster[j].x < bmin.x) bmin.x = (int)std::floor(vraster[j].x);
if (vraster[j].y < bmin.y) bmin.y = (int)std::floor(vraster[j].y);
if (vraster[j].x > bmax.x) bmax.x = (int)std::ceil(vraster[j].x);
if (vraster[j].y > bmax.y) bmax.y = (int)std::ceil(vraster[j].y);
}
// cull if all vertices are outside the canvas boundaries
if (outside == 0x0F) continue;
// precompute edge of quad
Vec2f edges[4];
for (uint32_t j = 0; j < 4; ++j) {
edges[j] = vraster[(j + 1) % 4] - vraster[j];
}
// loop over all pixels contained in box
for (int32_t y = std::max(0, bmin.y); y <= std::min((int32_t)(width -1), bmax.y); ++y) {
for (int32_t x = std::max(0, bmin.x); x <= std::min((int32_t)(width -1), bmax.x); ++x) {
bool inside = true;
for (uint32_t j = 0; j < 4 && inside; ++j) {
Vec2f v = Vec2f(x + 0.5, y + 0.5) - vraster[j];
float d = edges[j].x * v.x + edges[j].y * v.y;
inside &= (d > 0);
}
// pixel is inside quad, mark in the image
if (inside) {
buffer[y * width + x] = 255;
}
}
}