void SoundplaneZoneView::renderGrid()
{
    int viewW = getBackingLayerWidth();
    int viewH = getBackingLayerHeight();
    
    MLGL::orthoView2(viewW, viewH);

	int gridWidth = 30; // Soundplane A TODO get from tracker
	int gridHeight = 5;
   // int margin = viewW / 50;
	MLRange xRange(0, gridWidth, 1, viewW);
	MLRange yRange(0, gridHeight, 1, viewH);
    
	// draw thin lines at key grid
	Vec4 lineColor;
	Vec4 darkBlue(0.3f, 0.3f, 0.5f, 1.f);
	Vec4 gray(0.6f, 0.6f, 0.6f, 1.f);
	lineColor = gray;

	// horiz lines
	glColor4fv(&lineColor[0]);
	for(int j=0; j<=gridHeight; ++j)
	{
		glBegin(GL_LINE_STRIP);
		for(int i=0; i<=gridWidth; ++i)
		{
			float x = xRange.convert(i);
			float y = yRange.convert(j);
			glVertex2f(x, y);
		}
		glEnd();
	}
	// vert lines
	for(int i=0; i<=gridWidth; ++i)
	{
		glBegin(GL_LINE_STRIP);
		for(int j=0; j<=gridHeight; ++j)
		{
			float x = xRange.convert(i);
			float y = yRange.convert(j);
			glVertex2f(x, y);
		}
		glEnd();
	}
	
	// draw dots
    float r = viewH / 80.;
	for(int i=0; i<=gridWidth; ++i)
	{
		float x = xRange.convert(i + 0.5);
		float y = yRange.convert(2.5);
		int k = i%12;
		if(k == 0)
		{
			float d = viewH / 50;
            Vec4 dotColor(0.6f, 0.6f, 0.6f, 1.f);
            glColor4fv(&dotColor[0]);
            MLGL::drawDot(Vec2(x, y - d), r);
			MLGL::drawDot(Vec2(x, y + d), r);
		}
		if((k == 3)||(k == 5)||(k == 7)||(k == 9))
		{
            Vec4 dotColor(0.6f, 0.6f, 0.6f, 1.f);
            glColor4fv(&dotColor[0]);
            MLGL::drawDot(Vec2(x, y), r);
		}
	}
}
void SoundplaneZoneView::renderZones()
{
	if (!mpModel) return;
    const ScopedLock lock(*(mpModel->getZoneLock()));
    const std::vector<ZonePtr>& zoneList = mpModel->getZones();

    int viewW = getBackingLayerWidth();
    int viewH = getBackingLayerHeight();
	int viewScale = getRenderingScale();
	// float viewAspect = (float)viewW / (float)viewH;
    
	int gridWidth = 30; // Soundplane A TODO get from tracker
	int gridHeight = 5;
    int lineWidth = viewW / 200;
    int thinLineWidth = viewW / 400;
    // int margin = lineWidth*2;
    
    // put origin in lower left. 
    MLGL::orthoView2(viewW, viewH);
    MLRange xRange(0, gridWidth, 1, viewW);
	MLRange yRange(0, gridHeight, 1, viewH);

	Vec4 lineColor;
	Vec4 darkBlue(0.3f, 0.3f, 0.5f, 1.f);
	Vec4 gray(0.6f, 0.6f, 0.6f, 1.f);
	Vec4 lightGray(0.9f, 0.9f, 0.9f, 1.f);
	Vec4 blue2(0.1f, 0.1f, 0.5f, 1.f);
    float smallDotSize = xRange(1.f);
    
   // float strokeWidth = viewW / 100;    
    
    std::vector<ZonePtr>::const_iterator it;

    for(it = zoneList.begin(); it != zoneList.end(); ++it)
    {
        const Zone& zone = **it;
        
        int t = zone.getType();
        MLRect zr = zone.getBounds();
        const char * name = zone.getName().c_str();
		int offset = zone.getOffset();
        
        // affine transforms TODO for better syntax: MLRect zrd = zr.xform(gridToView);
        
        MLRect zoneRectInView(xRange.convert(zr.x()), yRange.convert(zr.y()), xRange.convert(zr.width()), yRange.convert(zr.height()));
        zoneRectInView.shrink(lineWidth);
		
		// color idx = type + port offset.
        Vec4 zoneStroke(MLGL::getIndicatorColor(t + offset));
        Vec4 zoneFill(zoneStroke);
        zoneFill[3] = 0.1f;
        Vec4 activeFill(zoneStroke);
        activeFill[3] = 0.25f;
        Vec4 dotFill(zoneStroke);
        dotFill[3] = 0.5f;
        
        // draw box common to all kinds of zones
        glColor4fv(&zoneFill[0]);
        MLGL::fillRect(zoneRectInView);
        glColor4fv(&zoneStroke[0]);
        glLineWidth(lineWidth);
        MLGL::strokeRect(zoneRectInView, 2.0f*viewScale);
        glLineWidth(1);
        // draw name
        // all these rect calculations read upside-down here because view origin is at bottom
        MLGL::drawTextAt(zoneRectInView.left() + lineWidth, zoneRectInView.top() + lineWidth, 0.f, 0.1f, viewScale, name);
        
        // draw any zone-specific things
        float x, y;
        int toggle;
        switch(t)
        {
            case kNoteRow:
                for(int i = 0; i < kSoundplaneMaxTouches; ++i)
                {
                    const ZoneTouch& uTouch = zone.getTouch(i);
                    const ZoneTouch& touch = zone.touchToKeyPos(uTouch);
                    if(touch.isActive())
                    {
                        glColor4fv(&dotFill[0]);
                        float dx = xRange(touch.pos.x());
                        float dy = yRange(touch.pos.y());
                        float dz = touch.pos.z();
                        MLGL::drawDot(Vec2(dx, dy), dz*smallDotSize);
                    }
                }
                break;
                
            case kControllerX:
                x = xRange(zone.getXKeyPos());
                glColor4fv(&zoneStroke[0]);
                glLineWidth(thinLineWidth);
                MLGL::strokeRect(MLRect(x, zoneRectInView.top(), 0., zoneRectInView.height()), viewScale);
                glColor4fv(&activeFill[0]);
                MLGL::fillRect(MLRect(zoneRectInView.left(), zoneRectInView.top(), x - zoneRectInView.left(), zoneRectInView.height()));
                break;
                
            case kControllerY:
                y = yRange(zone.getYKeyPos());
                glColor4fv(&zoneStroke[0]);
                glLineWidth(thinLineWidth);                
                MLGL::strokeRect(MLRect(zoneRectInView.left(), y, zoneRectInView.width(), 0.), viewScale);
                glColor4fv(&activeFill[0]);
                MLGL::fillRect(MLRect(zoneRectInView.left(), zoneRectInView.top(), zoneRectInView.width(), y - zoneRectInView.top()));
                break;
                
            case kControllerXY:
                x = xRange(zone.getXKeyPos());
                y = yRange(zone.getYKeyPos());
                glColor4fv(&zoneStroke[0]);
                glLineWidth(thinLineWidth);
                // cross-hairs centered on dot
                MLGL::strokeRect(MLRect(x, zoneRectInView.top(), 0., zoneRectInView.height()), viewScale);
                MLGL::strokeRect(MLRect(zoneRectInView.left(), y, zoneRectInView.width(), 0.), viewScale);
                glColor4fv(&dotFill[0]);
                MLGL::drawDot(Vec2(x, y), smallDotSize*0.25f);
                break;
                                
            case kControllerZ:
                y = yRange(zone.mYRange(zone.getValue(0))); // look at z value over y range
                glColor4fv(&zoneStroke[0]);
                glLineWidth(thinLineWidth);
                MLGL::strokeRect(MLRect(zoneRectInView.left(), y, zoneRectInView.width(), 0.), viewScale);
                glColor4fv(&activeFill[0]);
                MLGL::fillRect(MLRect(zoneRectInView.left(), zoneRectInView.top(), zoneRectInView.width(), y - zoneRectInView.top()));
                break;

            case kToggle:
                toggle = zone.getToggleValue();
                glColor4fv(&zoneStroke[0]);
                glLineWidth(thinLineWidth);
                if(toggle)
                {
                    MLRect toggleFill = zoneRectInView;
                    Vec2 zoneCenter = zoneRectInView.getCenter();
                    glColor4fv(&activeFill[0]);
                    MLGL::fillRect(zoneRectInView);
                    glColor4fv(&dotFill[0]);
                    MLGL::drawDot(zoneCenter, smallDotSize*0.25f);
                }
                break;
         }
    }
}
void SoundplaneTouchGraphView::renderTouchBarGraphs()
{
	if (!mpModel) return;
	if (!isShowing()) return;
    
    int viewW = getBackingLayerWidth();
    int viewH = getBackingLayerHeight();
	
	const MLSignal& currentTouch = mpModel->getTouchFrame();
	const MLSignal& touchHistory = mpModel->getTouchHistory();
	const int frames = mpModel->getFloatProperty("max_touches");
	if (!frames) return;
		
	const Colour c = findColour(MLLookAndFeel::backgroundColor);
	float p = c.getBrightness();
		
	int margin = viewH / 30;
	int numSize = margin*2;
	int left = margin*2 + numSize;
	
	int right = viewW - margin;
	int top = margin;
	int bottom = viewH - margin;
	
	int frameWidth = right - left;
	int frameOffset = (bottom - top)/frames;
	int frameHeight = frameOffset - margin;
	MLRect frameSize(0, 0, frameWidth, frameHeight);		

    MLGL::orthoView(viewW, viewH);
	for(int j=0; j<frames; ++j)
	{
		// draw frames
		p = 0.9f;
		glColor4f(p, p, p, 1.0f);
		MLRect fr = frameSize.translated(Vec2(left, margin + j*frameOffset));
		MLGL::fillRect(fr);	
		p = 0.6f;
		glColor4f(p, p, p, 1.0f);
        MLGL::strokeRect(fr);
		
		// draw touch activity indicators at left
		glColor4fv(MLGL::getIndicatorColor(j));
		MLRect r(0, 0, numSize, numSize);		
		MLRect tr = r.translated(Vec2(margin, margin + j*frameOffset + (frameHeight - numSize)/2));				
		int age = currentTouch(4, j);		
		if (age > 0)
			MLGL::fillRect(tr);	
		else
			MLGL::strokeRect(tr);
			
		// draw history	
		MLRange frameXRange(fr.left(), fr.right());
		frameXRange.convertTo(MLRange(0, (float)kSoundplaneHistorySize));		
		MLRange frameYRange(0, 1);
		frameYRange.convertTo(MLRange(fr.bottom(), fr.top()));
		
		glBegin(GL_LINES);
		for(int i=fr.left() + 1; i<fr.right()-1; ++i)
		{
			int time = frameXRange(i);			
			float force = touchHistory(2, j, time);
	//		float d = touchHistory(3, j, time);
	//		int age = touchHistory(4, j, time);
			float y = frameYRange.convert(force);
	//		float drawY = (age > 0) ? y : 0.;	
	//		y = frameYRange.convert(d);
			
			// draw line
			glVertex2f(i, fr.bottom());	
			glVertex2f(i, y);	
		}
		glEnd();
	}
}