Vishwas
Vishwas

Reputation: 526

Drawing a line using individual pixels in OpenGl core

I am trying to implement a line drawing algorithm in OpenGl. I have learnt the basics of using OpenGl from learnopengl. In the line drawing algorithm I need to set the individual pixel itself. I don't understand how to use the OpenGl at pixel level. I tried searching for the implementation bresenham's line algorithm in opengl, everywhere the implementation uses the function glDrawPixels which is not supported in OpenGl3.3. Is there anything that I'm missing in OpenGl3.3?

Upvotes: 1

Views: 1467

Answers (2)

Spektre
Spektre

Reputation: 51845

The easiest way is to use old style GL api

const int sz=400;   // window resolution
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(-1.0,-1.0,0.0);
glScalef(2.0/float(sz),2.0/float(sz),0.0);

glBegin(GL_POINTS);
glColor3f(1.0,1.0,1.0);
glVertex2i(x0,y0);
glVertex2i(x1,y1);
glVertex2i(x2,y2);
...
glEnd(); 

glFinish();
SwapBuffers(hdc);

But that will work only in compatibility profile or in older GL implementation.

For the new stuff you need to create a list of points to render set VAO/VBOs with them and use glDrawArrays/glDrawElements with GL_POINT style and of coarse you need to use shaders. Look here for complete cube example to start with:

To make this simper here example of both approaches (select with commenting or uncommenting the _gl_old define) with just some random points and very simple shaders (expecting 400x400 window and points in [pixels] units) using the gl_simple.h from previous link:

//---------------------------------------------------------------------------
#include <vcl.h>
#include <math.h>
#pragma hdrstop
#include "Unit1.h"
#include "gl_simple.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
// this define determines if old or new stuff is used
//#define _gl_old
//---------------------------------------------------------------------------
const int sz=400;   // window resolution
const int n=1024;   // points
const int n2=n+n;   // points*dimensions
GLint pnt[n2];      // points x,y ...
#ifndef _gl_old
GLuint pnt_vbo=-1;
GLuint pnt_vao=-1;
#endif
//---------------------------------------------------------------------------
void pnt_init()
    {
    // compute some points (your line algo should do it I use random instead)
    Randomize();
    for (int i=0;i<n2;i++) pnt[i]=Random(sz);
    // the new stuff need VBO
    #ifndef _gl_old
    // create VAO/VBO
    glGenVertexArrays(1,&pnt_vao);
    glGenBuffers(1,&pnt_vbo);
    glBindVertexArray(pnt_vao);
    // points -> VBO
    glBindBuffer(GL_ARRAY_BUFFER,pnt_vbo);
    glBufferData(GL_ARRAY_BUFFER,sizeof(pnt),pnt,GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribIPointer(0,2,GL_INT,0,0);
    // unbind VAO/VBO
    glBindVertexArray(0);
    glBindBuffer(GL_ARRAY_BUFFER,0);
    glDisableVertexAttribArray(0);
    #endif
    }
//---------------------------------------------------------------------------
void pnt_exit()
    {
    // the new stuff needs to release VBO/VAO
    #ifndef _gl_old
    glDeleteVertexArrays(1,&pnt_vao);
    glDeleteBuffers(1,&pnt_vbo);
    #endif
    }
//---------------------------------------------------------------------------
void gl_draw()
    {
    glClear(GL_COLOR_BUFFER_BIT);
    glDisable(GL_DEPTH_TEST);
    glDisable(GL_TEXTURE_2D);

    // Old GL 1.0 stuff
    #ifdef _gl_old
    // set view to 2D in [pixels]
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslatef(-1.0,-1.0,0.0);
    glScalef(2.0/float(sz),2.0/float(sz),0.0);
    // render points froma list
    glBegin(GL_POINTS);
    glColor3f(1.0,1.0,1.0);
    for (int i=0;i<n2;i+=2) glVertex2iv(pnt+i);
    glEnd();
    #endif

    // New GL stuff
    #ifndef _gl_old
    glUseProgram(prog_id);
    glBindVertexArray(pnt_vao);
    glDrawArrays(GL_POINTS,0,sizeof(pnt)/sizeof(pnt[0]));
    glBindVertexArray(0);
    glUseProgram(0);
    #endif

//  glFlush();
    glFinish();
    SwapBuffers(hdc);
    }
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner)
    {
    // Init of program
    gl_init(Handle);    // init OpenGL
    pnt_init();         // init pooints and VAO/VBO
    #ifndef _gl_old
    // init shaders
    char   vertex[]="#version 330 core\r\nlayout(location=0) in ivec2 pos;\r\nvoid main(void) { vec2 p; p=vec2(pos); p-=200; p/=200.0; gl_Position=vec4(p,0.0,1.0); }";
    char fragment[]="#version 330 core\r\nout vec4 col;\r\nvoid main() { col=vec4(1.0,1.0,1.0,1.0); }";
    glsl_init(vertex,fragment);
    int hnd=FileCreate("GLSL.txt"); FileWrite(hnd,glsl_log,glsl_logs); FileClose(hnd); // just write logs into file
    #endif
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
    {
    // Exit of program
    gl_exit();
    pnt_exit();
    #ifndef _gl_old
    glsl_exit();
    #endif
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormPaint(TObject *Sender)
    {
    // repaint
    gl_draw();
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormResize(TObject *Sender)
    {
    // resize
    gl_resize(ClientWidth,ClientHeight);
    }
//---------------------------------------------------------------------------

It is OpenGL/VCL/C++ so just ignore the VCL (all the defines, pragmas, includes ... except gl_simple.h and _gl_old) stuff and mimic events on your platform (repaint, init/exit,resize). The difference between new and old style is that you need to compute the rendered pixels ahead prior to rendering and store them into table/array.

Upvotes: 0

Jesse Hall
Jesse Hall

Reputation: 6787

The point of OpenGL is to use hardware that will do rasterization for you. If you're doing rasterization yourself, just write pixels into memory you allocate yourself, you don't need OpenGL at all; it isn't going to be doing anything for you anyway.

To display your image, you can upload your image to a texture (glTexImage2D/glTexSubImage2D), and then draw a quad with that texture mapped to it. Or use your OS's window/UI routines to paint the image on the window, which will probably be easier.

If you really want to draw individual pixels one by one with OpenGL, you could use GL_POINTS. You'll still have to create vertex and fragment shaders, etc., which is a lot of extra work.

Upvotes: 1

Related Questions