_clipy1 = 0;
_clipy2 = _logy - 1;
+ // Default to black background / white text.
_backgroundColor[0] = 0.0;
_backgroundColor[1] = 0.0;
_backgroundColor[2] = 0.0;
_backgroundColor[3] = 1.0;
_pixelColor[0] = 1.0;
- _pixelColor[1] = 0.0;
- _pixelColor[2] = 0.0;
+ _pixelColor[1] = 1.0;
+ _pixelColor[2] = 1.0;
_pixelColor[3] = 1.0;
_ra2d_debug = false;
}
-void RenderArea2D::draw(osg::State& state) {
+void RenderArea2D::Draw(osg::State& state) {
static osg::ref_ptr<osg::StateSet> renderArea2DStateSet;
if(!renderArea2DStateSet.valid()) {
glDisable(GL_CLIP_PLANE2);
glDisable(GL_CLIP_PLANE3);
- oldDrawBackground();
+ DoDrawBackground();
for(unsigned int i = 0; i < drawing_list.size(); ++i) {
RA2DPrimitive prim = drawing_list[i];
switch(prim.type) {
case RA2D_LINE:
- oldDrawLine(prim.x1, prim.y1, prim.x2, prim.y2);
+ DoDrawLine(prim.x1, prim.y1, prim.x2, prim.y2);
break;
case RA2D_QUAD:
if(prim.debug) {
//cout << "Clipping = " << _clipx1 << ", " << _clipy1 << " to " << _clipx2 << ", " << _clipy2 << '\n';
//cout << "Drawing quad " << prim.x1 << ", " << prim.y1 << " to " << prim.x2 << ", " << prim.y2 << '\n';
}
- oldDrawQuad(prim.x1, prim.y1, prim.x2, prim.y2, prim.invert);
+ DoDrawQuad(prim.x1, prim.y1, prim.x2, prim.y2, prim.invert);
break;
case RA2D_PIXEL:
- oldDrawPixel(prim.x1, prim.y1, prim.invert);
+ DoDrawPixel(prim.x1, prim.y1, prim.invert);
break;
}
}
+ drawing_list.clear();
+
glPopAttrib();
state.popStateSet();
state.setClientActiveTextureUnit(0);
}
+void RenderArea2D::Flush() {
+ drawing_list.clear();
+}
+
+void RenderArea2D::SetPixelColor(const float* rgba) {
+ _pixelColor[0] = rgba[0];
+ _pixelColor[1] = rgba[1];
+ _pixelColor[2] = rgba[2];
+ _pixelColor[3] = rgba[3];
+}
+
// Set clipping region in logical units
void RenderArea2D::SetClipRegion(int x1, int y1, int x2, int y2) {
_clipx1 = x1;
}
void RenderArea2D::DrawPixel(int x, int y, bool invert) {
- // Clipping is currently performed in oldDrawPixel - could clip here instead though.
+ // Clip
+ if(x < _clipx1 || x > _clipx2 || y < _clipy1 || y > _clipy2) return;
RA2DPrimitive prim;
prim.x1 = x;
drawing_list.push_back(prim);
}
-void RenderArea2D::oldDrawPixel(int x, int y, bool invert) {
- // Clip
+void RenderArea2D::DoDrawPixel(int x, int y, bool invert) {
+ // Clip. In theory this shouldn't be necessary, since all input is clipped before adding
+ // to the drawing list, but it ensures that any errors in clipping lines etc will only
+ // spill over the clip area within the instrument, and still be clipped from straying
+ // outside the instrument.
if(x < _clipx1 || x > _clipx2 || y < _clipy1 || y > _clipy2) return;
// Scale to position within background
//cout << "DP: " << fx1 << ", " << fy1 << " ... " << fx2 << ", " << fy2 << '\n';
- doSetColor(invert ? _backgroundColor : _pixelColor);
+ SetRenderColor(invert ? _backgroundColor : _pixelColor);
SGVec2f corners[4] = {
SGVec2f(fx1, fy1),
SGVec2f(fx2, fy1),
SGVec2f(fx2, fy2),
SGVec2f(fx1, fy2)
};
- doDrawQuad(corners);
+ RenderQuad(corners);
}
void RenderArea2D::DrawLine(int x1, int y1, int x2, int y2) {
+ // We need to clip the line to the current region before storing it in the drawing
+ // list, since when we come to actually draw it the clip region may have changed.
+
+ // Liang-Barsky clipping algorithm
+ int p[4], q[4];
+ float u1 = 0.0f, u2 = 1.0f;
+ p[0] = -(x2 - x1); q[0] = (x1 - _clipx1);
+ p[1] = (x2 - x1); q[1] = (_clipx2 - x1);
+ p[2] = -(y2 - y1); q[2] = (y1 - _clipy1);
+ p[3] = (y2 - y1); q[3] = (_clipy2 - y1);
+
+ for(int i=0; i<4; ++i) {
+ if(p[i] == 0) {
+ if(q[i] < 0) {
+ // Then we have a trivial rejection of a line parallel to a clip plane
+ // completely outside the clip region.
+ return;
+ }
+ } else if(p[i] < 0) {
+ float r = (float)q[i]/(float)p[i];
+ u1 = (u1 > r ? u1 : r);
+ } else { // p[i] > 0
+ float r = (float)q[i]/(float)p[i];
+ u2 = (u2 < r ? u2 : r);
+ }
+ if(u1 > u2) {
+ // Then the line is completely outside the clip area.
+ return;
+ }
+ }
+
+ float fx1 = x1 + u1 * (float)(x2 - x1);
+ float fy1 = y1 + u1 * (float)(y2 - y1);
+ float fx2 = x1 + u2 * (float)(x2 - x1);
+ float fy2 = y1 + u2 * (float)(y2 - y1);
+ x1 = (int)(fx1 + 0.5);
+ y1 = (int)(fy1 + 0.5);
+ x2 = (int)(fx2 + 0.5);
+ y2 = (int)(fy2 + 0.5);
+
RA2DPrimitive prim;
prim.x1 = x1;
prim.y1 = y1;
drawing_list.push_back(prim);
}
-void RenderArea2D::oldDrawLine(int x1, int y1, int x2, int y2) {
+void RenderArea2D::DoDrawLine(int x1, int y1, int x2, int y2) {
// Crude implementation of Bresenham line drawing algorithm.
// Our lines are non directional, so first order the points x-direction-wise to leave only 4 octants to consider.
int y = y1;
int yn = dx/2;
for(int x=x1; x<=x2; ++x) {
- DrawPixel(x, y);
+ DoDrawPixel(x, y);
yn += dy;
if(yn >= dx) {
yn -= dx;
// Must be a more elegant way to roll the next two cases into one!
if(flip_y) {
for(int y=y1; y>=y2; --y) {
- DrawPixel(x, y);
+ DoDrawPixel(x, y);
xn += dx;
if(xn >= dy) {
xn -= dy;
}
} else {
for(int y=y1; y<=y2; ++y) {
- DrawPixel(x, y);
+ DoDrawPixel(x, y);
xn += dx;
if(xn >= dy) {
xn -= dy;
}
void RenderArea2D::DrawQuad(int x1, int y1, int x2, int y2, bool invert) {
- // Clip and sanity-check.
+ // Force the input to be ordered with x1 < x2 and y1 < y2.
if(x1 > x2) {
int x = x2;
x2 = x1;
y2 = y1;
y1 = y;
}
+
+ // Clip the input to the current drawing region.
x1 = x1 < _clipx1 ? _clipx1 : x1;
if(x1 > _clipx2) { return; }
x2 = x2 > _clipx2 ? _clipx2 : x2;
drawing_list.push_back(prim);
}
-void RenderArea2D::oldDrawQuad(int x1, int y1, int x2, int y2, bool invert) {
+void RenderArea2D::DoDrawQuad(int x1, int y1, int x2, int y2, bool invert) {
// Scale to position within background
float fx1 = (float)x1, fy1 = (float)y1;
float fx2 = (float)x2, fy2 = (float)y2;
//cout << "DP: " << fx1 << ", " << fy1 << " ... " << fx2 << ", " << fy2 << '\n';
- doSetColor(invert ? _backgroundColor : _pixelColor);
+ SetRenderColor(invert ? _backgroundColor : _pixelColor);
SGVec2f corners[4] = {
SGVec2f(fx1, fy1),
SGVec2f(fx2, fy1),
SGVec2f(fx2, fy2),
SGVec2f(fx1, fy2)
};
- doDrawQuad(corners);
+ RenderQuad(corners);
}
void RenderArea2D::DrawBackground() {
- // TODO
+ // Currently a NO-OP
}
-void RenderArea2D::oldDrawBackground() {
- doSetColor(_backgroundColor);
+void RenderArea2D::DoDrawBackground() {
+ SetRenderColor(_backgroundColor);
SGVec2f corners[4] = {
SGVec2f(_posx, _posy),
SGVec2f(_posx + _sizex, _posy),
SGVec2f(_posx, _posy + _sizey)
};
- doDrawQuad(corners);
-}
-
-void RenderArea2D::Flush() {
- drawing_list.clear();
+ RenderQuad(corners);
}
// -----------------------------------------
//
// -----------------------------------------
-void RenderArea2D::doSetColor( const float *rgba ) {
+void RenderArea2D::SetRenderColor( const float *rgba ) {
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, rgba);
glColor4fv( rgba );
}
-void RenderArea2D::doDrawQuad( const SGVec2f *p) {
+void RenderArea2D::RenderQuad( const SGVec2f *p) {
glBegin(GL_QUADS);
glNormal3f(0.0f, 0.0f, 0.0f);
glVertex2fv( p[0].data() );
glEnd();
}
-void RenderArea2D::doDrawQuad( const SGVec2f *p, const SGVec4f *color ) {
+void RenderArea2D::RenderQuad( const SGVec2f *p, const SGVec4f *color ) {
glBegin(GL_QUADS);
glNormal3f(0.0f, 0.0f, 0.0f);
glColor4fv( color[0].data() ); glVertex2fv( p[0].data() );