Close

Extending the Graphics

A project log for ChassC

As in 'Chassis for C' Simple Direct Media Layer (SDL2) Template for C++

morningstarMorning.Star 02/19/2018 at 13:070 Comments

That really is about all SDL can do on its own. It does have tricks up its sleeve, and there is the mixer, fonts and other libraries you can add to it, plus a graphics library containing all the primitives - circles, polygons etc.

If you're like me, you wont want to load another library to use the one you just loaded. Besides, they are all written in SDL, to do things that SDL cant on its own.

Here's a good example. Filling a triangle, fast. I've had to code a routine to do this using a rasterising arrangement - breaking the triangle up into lines and drawing them using RenderDrawLine repeatedly.

#include <vector>

void trigon(double nx1, double ny1, double nx2, double ny2,double nx3, double ny3) {

  double sx,sy,nx,ny,dx1,dx2,dx3,x1,y1,x2,y2,x3,y3;

  if (ny1<=ny2 and ny1<=ny3) { 
    x1=nx1; y1=ny1;
    if (ny2<=ny3) { x2=nx2; y2=ny2; x3=nx3; y3=ny3; }   // make sure y1<y2<y3
    if (ny3<=ny2) { x2=nx3; y2=ny3; x3=nx2; y3=ny2; }
  }

  if (ny2<=ny1 and ny2<=ny3) { 
    x1=nx2; y1=ny2;
    if (ny1<=ny3) { x2=nx1; y2=ny1; x3=nx3; y3=ny3; }
    if (ny3<=ny1) { x2=nx3; y2=ny3; x3=nx1; y3=ny1; }
  }

  if (ny3<=ny1 and ny3<=ny2) { 
    x1=nx3; y1=ny3;
    if (ny1<=ny2) { x2=nx1; y2=ny1; x3=nx2; y3=ny2; }
    if (ny2<=ny1) { x2=nx2; y2=ny2; x3=nx1; y3=ny1; }
  }

  SDL_RenderDrawLine(render,x1,y1,x2,y2);
  SDL_RenderDrawLine(render,x2,y2,x3,y3);
  SDL_RenderDrawLine(render,x3,y3,x1,y1);
    
  if (y1==y2) {                                         // if top of triangle is flat
  
    sx=x1; nx=x2;                                       // begin with full width
    dx1=(x3-x1)/(y3-y1);                                // and graduate to a point
    dx2=(x3-x2)/(y3-y1);
  
    for (sy=y1;sy<y3;sy++) {                            // fill in the scanlines
      SDL_RenderDrawLine(render,sx,sy,nx,sy);
      sx=sx+dx1;
      nx=nx+dx2;
    }
  
  } else {

    sx=x1; nx=x1;                                       // if top of triangle is a point
    dx1=(x2-x1)/(y2-y1);                                // fill in the top half of the triangle
    dx2=(x3-x1)/(y3-y1);
  
    for (sy=y1;sy<y2;sy++) {                            // fill the scanlines
      SDL_RenderDrawLine(render,sx,sy,nx,sy);
      sx=sx+dx1;
      nx=nx+dx2;
    }

    dx1=(x3-x2)/(y3-y2);                                // the width of the top of bottom half
    sx=x2;
    
    for (sy=y2;sy<y3;sy++) {                            // fill the scanlines
      SDL_RenderDrawLine(render,sx,sy,nx,sy);
      sx=sx+dx1;
      nx=nx+dx2;
    }

  }

}

Simply call Trigon with three coordinate pairs.

trigon(600,100,700,150,650,200); 

Rather than write a routine to handle four, five etc sides, I've also written a routine called Polygon, which calls Trigon to fill in the triangles it breaks the poly into. However, rather than split the drawing routines into classes like point, line, circle etc, I've incorporated them all into Polygon.

Calling it with one pair of coordinates draws a pixel. With two pairs, it draws a line, and with three or more pairs of coordinates it draws a filled shape. The coordinates are passed as a Vector for simplicity.

double pi=atan(1)*4.0
double d2r=pi/180.0

void polygon(vector <SDL_Point> pt) {

  int n,pts=pt.size();
  double x1,y1,x2,y2,x3,y3;
  
  if (pts==1) {
    SDL_RenderDrawPoint(render,pt[0].x,pt[0].y);
  }

  if (pts==2) {
    SDL_RenderDrawLine(render,pt[0].x,pt[0].y,pt[1].x,pt[1].y);
  }

  if (pts==3) {
    trigon(pt[0].x,pt[0].y,pt[1].x,pt[1].y,pt[2].x,pt[2].y);
  }
  
  if (pts>3) {
  
    trigon(pt[0].x,pt[0].y,pt[1].x,pt[1].y,pt[2].x,pt[2].y);
    
    for (n=0; n<pts-3; n++) {
    
      x1=pt[0].x; y1=pt[0].y;
      x2=pt[2+n].x; y2=pt[2+n].y;
      x3=pt[3+n].x; y3=pt[3+n].y;
      
      trigon(x1,y1,x2,y2,x3,y3);
    
    }
    
  }

}

 And finally, to complete the set there is PieSlice, which takes coordinates and an arc angle, arc length and radius to draw a pie slice or circle centered on the coordinates.

void pieslice(SDL_Point pt, double st, double nd, double rds) {

  double n;
  SDL_Point p;
  vector <SDL_Point> pl;
  
  if (nd-st<360) { 
    pl.push_back(pt); 
  }
  
  for (n=0;n<=nd;n=n+(nd/48.0)) {
    p.x=(cos((st+n)*d2r)*rds)+pt.x;
    p.y=(sin((st+n)*d2r)*rds)+pt.y;
    pl.push_back(p);
  }
  
  polygon(pl);

}

To use them...

  vector <SDL_Point> pts;
  SDL_Point p;
  
  p.x=600; p.y=300;
  pts.push_back(p);
  p.x=700; p.y=350;
  pts.push_back(p);
  p.x=650; p.y=400;
  pts.push_back(p);
  p.x=600; p.y=450;
  pts.push_back(p);
  
  polygon(pts);
  
  p.x=800; p.y=200;
  
  pieslice(p,0,270,50); 

Discussions