Beispiel #1
0
void TTF_TextBox(const drawTextCommand_t *cmd, const char *string, int count) {
	TTFtextRow rows[2];
	int nrows = 0, i;
	int oldAlign = state.align;
	int halign = state.align & (FONS_ALIGN_LEFT | FONS_ALIGN_CENTER | FONS_ALIGN_RIGHT);
	int valign = state.align & (FONS_ALIGN_TOP | FONS_ALIGN_MIDDLE | FONS_ALIGN_BOTTOM | FONS_ALIGN_BASELINE);
	float lineh;

	fonsPushState(ctx);

	fonsVertMetrics(ctx, nullptr, nullptr, &lineh);
	fonsSetAlign(ctx, FONS_ALIGN_LEFT | valign);

	float x = cmd->x;
	float y = cmd->y;
	lineh *= state.lineHeight;

	const char *end = TTF_CountChars(string, count);

	while ((nrows = TTF_BreakLines(string, end, cmd->w, rows, 2)) > 0) {
		for (i = 0; i < nrows; i++) {
			TTFtextRow* row = &rows[i];
			if (halign & FONS_ALIGN_LEFT)
				fonsDrawText(ctx, x, y, row->start, row->end);
			else if (halign & FONS_ALIGN_CENTER)
				fonsDrawText(ctx, x + cmd->w * 0.5f - row->width*0.5f, y, row->start, row->end);
			else if (halign & FONS_ALIGN_RIGHT)
				fonsDrawText(ctx, x + cmd->w - row->width, y, row->start, row->end);
			y += lineh;
		}
		string = rows[nrows - 1].next;
	}

	fonsPopState(ctx);
}
Beispiel #2
0
std::vector<FONSquad>& FontContext::rasterize(const std::string& _text, FontID _fontID,
                                              float _fontSize, float _sdf) {

    m_quadBuffer.clear();

    fonsSetSize(m_fsContext, _fontSize);
    fonsSetFont(m_fsContext, _fontID);

    if (_sdf > 0){
        fonsSetBlur(m_fsContext, _sdf);
        fonsSetBlurType(m_fsContext, FONS_EFFECT_DISTANCE_FIELD);
    } else {
        fonsSetBlurType(m_fsContext, FONS_EFFECT_NONE);
    }

    float advance = fonsDrawText(m_fsContext, 0, 0,
                                 _text.c_str(), _text.c_str() + _text.length(),
                                 0);
    if (advance < 0) {
        m_quadBuffer.clear();
        return m_quadBuffer;
    }

    return m_quadBuffer;
}
    /**
     * Render the font, called by Renderer.cpp
     */
    void FontStashAdapter::render() {
        glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
		glEnable(GL_CULL_FACE);
        glFrontFace( GL_CCW );
        
        shaderLib->bind();
        shaderLib->getShader()->setUniform("ortho", orthogonalProjection );
        
        glActiveTexture( GL_TEXTURE0 );
        glBindTexture( GL_TEXTURE_2D , textureID );
        shaderLib->getShader()->setUniform("font", 0 );
        fonsClearState(context);
        
        for( auto text_info: texts ){
            fonsSetFont   ( context, text_info.fontID );
            fonsSetSize   ( context, text_info.fontSize );
            fonsSetColor  ( context, text_info.color );
            fonsSetSpacing( context, text_info.spacing );
            fonsSetBlur   ( context, text_info.blur );
            fonsDrawText  ( context, text_info.x, text_info.y, text_info.text.c_str(), NULL );
        }
        
        shaderLib->unbind();
    }
float ofxFontStash2::draw(const string& text, const ofxFontStashStyle& style, float x, float y){

	FONT_STASH_PRE_DRAW;
	ofPushMatrix();
	ofScale(1/pixelDensity, 1/pixelDensity);
	applyStyle(style);
	float dx = fonsDrawText(fs, x*pixelDensity, y*pixelDensity, text.c_str(), NULL)/pixelDensity;
	ofPopMatrix();
	FONT_STASH_POST_DRAW;
	return dx;
}
Beispiel #5
0
bool CRenderEngine::DrawTextSt(const char* text, DuiRECT& pos,int style,int iFont,DWORD dwTextColor)
{
	if (s_fs == NULL)
	{
		s_fs = glfonsCreate(512, 512, FONS_ZERO_TOPLEFT);
		if (s_fs == NULL)
		{
			return false;
		}
		s_fontNormal = fonsAddFont(s_fs, "sans", "msyh.ttf");
		if (s_fontNormal == FONS_INVALID)
		{
			return false;
		}
	}
	float line_height = 15.0f;

	//¸ù¾Ýstyle×óÓÒÖмä¶ÔÆë¼ÆËã
	float s_x = pos.left;
	float s_y = (pos.bottom - pos.top) / 2.f + pos.top;

	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	 
	unsigned char a = (dwTextColor) >> 24;
	unsigned char r = (dwTextColor & 0xff0000) >> 16;
	unsigned char g = (dwTextColor & 0xff00) >> 8;
	unsigned char b = (dwTextColor & 0xff);

	unsigned int  text_clr = glfonsRGBA(r,g,b,a);

	fonsClearState(s_fs);
	fonsSetSize(s_fs, line_height);
	fonsSetFont(s_fs, s_fontNormal);
	fonsSetColor(s_fs, text_clr);
	fonsDrawText(s_fs, s_x, s_y, text, NULL);

	return true;
}
Beispiel #6
0
void
GLHelper::drawText(const std::string& text, const Position& pos,
                   const double layer, const double size,
                   const RGBColor& col, const double angle, const int align,
                   double width) {
    if (width <= 0) {
        width = size;
    }
    if (!initFont()) {
        return;
    };
    glPushMatrix();
    glAlphaFunc(GL_GREATER, 0.5);
    glEnable(GL_ALPHA_TEST);
    glTranslated(pos.x(), pos.y(), layer);
    glScaled(width / myFontSize, size / myFontSize, 1.);
    glRotated(-angle, 0, 0, 1);
    fonsSetAlign(myFont, align == 0 ? FONS_ALIGN_CENTER | FONS_ALIGN_MIDDLE : align);
    fonsSetColor(myFont, glfonsRGBA(col.red(), col.green(), col.blue(), col.alpha()));
    fonsDrawText(myFont, 0., 0., text.c_str(), nullptr);
    glPopMatrix();
}
Beispiel #7
0
int main()
{
	int fontNormal = FONS_INVALID;
	int fontItalic = FONS_INVALID;
	int fontBold = FONS_INVALID;
	int fontJapanese = FONS_INVALID;

	GLFWwindow* window;
	const GLFWvidmode* mode;
	
	struct FONSparams params;
	struct FONScontext* fs = NULL;

	if (!glfwInit())
		return -1;

	mode = glfwGetVideoMode(glfwGetPrimaryMonitor());
    window = glfwCreateWindow(mode->width - 40, mode->height - 80, "Font Stash", NULL, NULL);
	if (!window) {
		glfwTerminate();
		return -1;
	}

	glfwMakeContextCurrent(window);

	memset(&params, 0, sizeof(params));
	params.width = 512;
	params.height = 512;
	params.flags = FONS_ZERO_TOPLEFT;

	if (glstInit(&params) == 0) {
		printf("Could not create renderer.\n");
		return -1;
	}

	fs = fonsCreate(&params);
	if (fs == NULL) {
		printf("Could not create stash.\n");
		return -1;
	}

	fontNormal = fonsAddFont(fs, "../example/DroidSerif-Regular.ttf");
	if (fontNormal == FONS_INVALID) {
		printf("Could not add font normal.\n");
		return -1;
	}
	fontItalic = fonsAddFont(fs, "../example/DroidSerif-Italic.ttf");
	if (fontItalic == FONS_INVALID) {
		printf("Could not add font italic.\n");
		return -1;
	}
	fontBold = fonsAddFont(fs, "../example/DroidSerif-Bold.ttf");
	if (fontBold == FONS_INVALID) {
		printf("Could not add font bold.\n");
		return -1;
	}
	fontJapanese = fonsAddFont(fs, "../example/DroidSansJapanese.ttf");
	if (fontJapanese == FONS_INVALID) {
		printf("Could not add font japanese.\n");
		return -1;
	}

	while (!glfwWindowShouldClose(window))
	{
		float sx, sy, dx, dy, lh = 0;
		int width, height;
		glfwGetFramebufferSize(window, &width, &height);
		// Update and render
		glViewport(0, 0, width, height);
		glClearColor(0.3f, 0.3f, 0.32f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glDisable(GL_TEXTURE_2D);
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		glOrtho(0,width,height,0,-1,1);

		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
		glDisable(GL_DEPTH_TEST);
		glColor4ub(255,255,255,255);
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);


		unsigned int white = glstRGBA(255,255,255,255);
		unsigned int brown = glstRGBA(192,128,0,128);
		unsigned int blue = glstRGBA(0,192,255,255);

		sx = 100; sy = 100;
		
		dx = sx; dy = sy;

		dash(dx,dy);

		fonsSetSize(fs, 124.0f);
		fonsSetFont(fs, fontNormal);
		fonsVertMetrics(fs, NULL, NULL, &lh);
		dx = sx;
		dy += lh;
		dash(dx,dy);
		
		fonsSetSize(fs, 124.0f);
		fonsSetFont(fs, fontNormal);
		fonsSetColor(fs, white);
		fonsDrawText(fs, dx,dy,"The quick ",&dx);

		fonsSetSize(fs, 48.0f);
		fonsSetFont(fs, fontItalic);
		fonsSetColor(fs, brown);
		fonsDrawText(fs, dx,dy,"brown ",&dx);

		fonsSetSize(fs, 24.0f);
		fonsSetFont(fs, fontNormal);
		fonsSetColor(fs, white);
		fonsDrawText(fs, dx,dy,"fox ",&dx);

		fonsVertMetrics(fs, NULL, NULL, &lh);
		dx = sx;
		dy += lh*1.2f;
		dash(dx,dy);
		fonsSetFont(fs, fontItalic);
		fonsDrawText(fs, dx,dy,"jumps over ",&dx);
		fonsSetFont(fs, fontBold);
		fonsDrawText(fs, dx,dy,"the lazy ",&dx);
		fonsSetFont(fs, fontNormal);
		fonsDrawText(fs, dx,dy,"dog.",&dx);

		dx = sx;
		dy += lh*1.2f;
		dash(dx,dy);
		fonsSetSize(fs, 12.0f);
		fonsSetFont(fs, fontNormal);
		fonsSetColor(fs, blue);
		fonsDrawText(fs, dx,dy,"Now is the time for all good men to come to the aid of the party.",&dx);

		fonsVertMetrics(fs, NULL,NULL,&lh);
		dx = sx;
		dy += lh*1.2f*2;
		dash(dx,dy);
		fonsSetSize(fs, 18.0f);
		fonsSetFont(fs, fontItalic);
		fonsSetColor(fs, white);
		fonsDrawText(fs, dx,dy,"Ég get etið gler án þess að meiða mig.",&dx);

		fonsVertMetrics(fs, NULL,NULL,&lh);
		dx = sx;
		dy += lh*1.2f;
		dash(dx,dy);
		fonsSetFont(fs, fontJapanese);
		fonsDrawText(fs, dx,dy,"私はガラスを食べられます。それは私を傷つけません。asd",&dx);

		glEnable(GL_DEPTH_TEST);

		glfwSwapBuffers(window);
		glfwPollEvents();
	}

	fonsDelete(fs);

	glfwTerminate();
	return 0;
}
void LikertHCI::initializeText(int threadId, FONScontext* fs, int fontNormal, int lineCount, float border, std::shared_ptr<GLSLProgram> shader, float textSize, const std::vector<std::string> &texts, std::string texKey, std::vector<std::vector<std::shared_ptr<Texture> > > &textures, std::vector<std::vector<glm::dvec2> > &sizes)
{
	float sx, sy, lh = 0;
	unsigned int white = glfonsRGBA(255,255,255,255);
	unsigned int gray = glfonsRGBA(81, 76, 76, 255);

	fonsClearState(fs);
	fonsSetSize(fs, textSize);
	fonsSetFont(fs, fontNormal);
	fonsSetColor(fs, white);
	fonsSetAlign(fs, FONS_ALIGN_CENTER | FONS_ALIGN_TOP);
	fonsVertMetrics(fs, NULL, NULL, &lh);

	for(int i=0; i < texts.size(); i++) {

		std::stringstream ss(texts[i]);
		std::string line;
		std::vector<std::string> lines;

		float maxWidth = 0;
		while(std::getline(ss, line, '\n')){
			float width = fonsTextBounds(fs, line.c_str(), NULL, NULL);
			if (width > maxWidth) {
				maxWidth = width;
			}
			lines.push_back(line);
		}

		sx = maxWidth + (1.0f*border);
		sy = border;
		if (lineCount > lines.size()) {
			sy += lh * (lineCount - lines.size()) * 0.5;
		}
		float height = lh*lineCount+2.0*border;


		std::shared_ptr<Texture> depthTexture = Texture::createEmpty("depthTex", sx, height, 1, 1, false, GL_TEXTURE_2D, GL_DEPTH_COMPONENT32F);
		depthTexture->setTexParameteri(GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		depthTexture->setTexParameteri(GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		depthTexture->setTexParameteri(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		depthTexture->setTexParameteri(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
		glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexture->getID(), 0);

		textures[threadId][i] = Texture::createEmpty("colorTex", sx, height, 1, 4, false, GL_TEXTURE_2D, GL_RGBA8);
		textures[threadId][i]->setTexParameteri(GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		textures[threadId][i]->setTexParameteri(GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		textures[threadId][i]->setTexParameteri(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		textures[threadId][i]->setTexParameteri(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
		textures[threadId][i]->setTexParameterf(GL_TEXTURE_MAX_ANISOTROPY_EXT, 16.0);
		glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textures[threadId][i]->getID(), 0);
			
		GLenum status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
		switch(status) {
		case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
			assert(false);
			break;
		case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
			assert(false);
			break;
		case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
			assert(false);
			break;
		case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
			assert(false);
			break;
		case GL_FRAMEBUFFER_UNSUPPORTED:
			assert(false);
			break;
		case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
			assert(false);
			break;
		default:
			break;
		}
		assert(status == GL_FRAMEBUFFER_COMPLETE);

		sizes[threadId].push_back(glm::dvec2(sx, height));

		glViewport(0,0, sx, height);
		glClear(GL_COLOR_BUFFER_BIT);

		shader->setUniform("projection_mat", glm::ortho(0., (double)sx, (double)height, 0., -1., 1.));
		shader->setUniform("view_mat", glm::dmat4(1.0));
		shader->setUniform("model_mat", glm::dmat4(1.0));
		shader->setUniform("has_lambertian_texture", false);

		glDisable(GL_DEPTH_TEST);


		// Draw the darker interior quad so we get a white border around the outside from the clear color
		float rim = border/4.0f;

		GLfloat vertices[]  = {rim, height-rim,    sx-rim, height-rim,  rim, rim,  sx-rim, rim};
		GLfloat texCoords[] = { 0, 1,   1, 1,  1, 0,  0, 0 };
		GLfloat colors[]  = { 0.32, 0.3, 0.3, 1.0,   0.32, 0.3, 0.3, 1.0,   0.32, 0.3, 0.3, 1.0,   0.32, 0.3, 0.3, 1.0};

		// create the vao
		GLuint vaoID = 0;
		glGenVertexArrays(1, &vaoID);
		glBindVertexArray(vaoID);

		GLuint quadVBO = 0;
		glGenBuffers(1, &quadVBO);
		glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
		glBufferData(GL_ARRAY_BUFFER, sizeof(vertices)+sizeof(texCoords)+sizeof(colors), 0, GL_STREAM_DRAW);
		glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);                             // copy vertices starting from 0 offest
		glBufferSubData(GL_ARRAY_BUFFER, sizeof(vertices), sizeof(texCoords), texCoords);                // copy texCoords after vertices
		glBufferSubData(GL_ARRAY_BUFFER, sizeof(vertices)+sizeof(texCoords), sizeof(colors), colors);  // copy colours after normals

		// set up vertex attributes
		glEnableVertexAttribArray(0);
		glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
		glEnableVertexAttribArray(1);
		glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)sizeof(vertices));
		glEnableVertexAttribArray(2);
		glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 0, (void*)(sizeof(vertices)+sizeof(texCoords)));

		glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

		glBindVertexArray(0);
		glDeleteBuffers(1, &quadVBO);
		glDeleteVertexArrays(1, &vaoID);

		shader->setUniform("has_lambertian_texture", true);
		glActiveTexture(GL_TEXTURE0);
		shader->setUniform("lambertian_texture", 0);

		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

		for(int j=0; j < lines.size(); j++) { 
			std::string text = boost::replace_all_copy(lines[j], "_", " ");
			fonsDrawText(fs, sx/2.0, sy, text.c_str(), NULL);
			sy += lh;
		}

		glDisable(GL_BLEND);

		textures[threadId][i]->generateMipMaps();
		std::string textureKey = texKey + texts[i];
		texMan->setTextureEntry(threadId, textureKey, textures[threadId][i]);

		depthTexture.reset();
	}
}
Beispiel #9
0
int main()
{
	int fontNormal = FONS_INVALID;
	int fontItalic = FONS_INVALID;
	int fontBold = FONS_INVALID;
	int fontJapanese = FONS_INVALID;
	GLFWwindow* window;
	const GLFWvidmode* mode;
	
	if (!glfwInit())
		return -1;

	mode = glfwGetVideoMode(glfwGetPrimaryMonitor());
    window = glfwCreateWindow(mode->width - 40, mode->height - 80, "Font Stash", NULL, NULL);
	if (!window) {
		glfwTerminate();
		return -1;
	}

    glfwSetKeyCallback(window, key);
	glfwMakeContextCurrent(window);

	fs = glfonsCreate(256, 256, FONS_ZERO_TOPLEFT);
	if (fs == NULL) {
		printf("Could not create stash.\n");
		return -1;
	}

	fonsSetErrorCallback(fs, stashError, fs);

	fontNormal = fonsAddFont(fs, "sans", "../example/DroidSerif-Regular.ttf");
	if (fontNormal == FONS_INVALID) {
		printf("Could not add font normal.\n");
		return -1;
	}
	fontItalic = fonsAddFont(fs, "sans-italic", "../example/DroidSerif-Italic.ttf");
	if (fontItalic == FONS_INVALID) {
		printf("Could not add font italic.\n");
		return -1;
	}
	fontBold = fonsAddFont(fs, "sans-bold", "../example/DroidSerif-Bold.ttf");
	if (fontBold == FONS_INVALID) {
		printf("Could not add font bold.\n");
		return -1;
	}
	fontJapanese = fonsAddFont(fs, "sans-jp", "../example/DroidSansJapanese.ttf");
	if (fontJapanese == FONS_INVALID) {
		printf("Could not add font japanese.\n");
		return -1;
	}

	while (!glfwWindowShouldClose(window))
	{
		float sx, sy, dx, dy, lh = 0;
		int width, height;
		int atlasw, atlash;
		unsigned int white,black,brown,blue;
		char msg[64];
		glfwGetFramebufferSize(window, &width, &height);
		// Update and render
		glViewport(0, 0, width, height);
		glClearColor(0.3f, 0.3f, 0.32f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glDisable(GL_TEXTURE_2D);
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		glOrtho(0,width,height,0,-1,1);

		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
		glDisable(GL_DEPTH_TEST);
		glColor4ub(255,255,255,255);
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
		glEnable(GL_CULL_FACE);

		white = glfonsRGBA(255,255,255,255);
		brown = glfonsRGBA(192,128,0,128);
		blue = glfonsRGBA(0,192,255,255);
		black = glfonsRGBA(0,0,0,255);

		sx = 50; sy = 50;
		
		dx = sx; dy = sy;

		dash(dx,dy);

		fonsClearState(fs);

		fonsSetSize(fs, size);
		fonsSetFont(fs, fontNormal);
		fonsVertMetrics(fs, NULL, NULL, &lh);
		dx = sx;
		dy += lh;
		dash(dx,dy);
		
		fonsSetSize(fs, size);
		fonsSetFont(fs, fontNormal);
		fonsSetColor(fs, white);
		dx = fonsDrawText(fs, dx,dy,"The quick ",NULL);

		fonsSetSize(fs, size/2);
		fonsSetFont(fs, fontItalic);
		fonsSetColor(fs, brown);
		dx = fonsDrawText(fs, dx,dy,"brown ",NULL);

		fonsSetSize(fs, size/3);
		fonsSetFont(fs, fontNormal);
		fonsSetColor(fs, white);
		dx = fonsDrawText(fs, dx,dy,"fox ",NULL);

		fonsSetSize(fs, 14);
		fonsSetFont(fs, fontNormal);
		fonsSetColor(fs, white);
		fonsDrawText(fs, 20, height-20,"Press UP / DOWN keys to change font size and to trigger atlas full callback, R to reset atlas, E to expand atlas.",NULL);

		fonsGetAtlasSize(fs, &atlasw, &atlash);
		snprintf(msg, sizeof(msg), "Atlas: %d × %d", atlasw, atlash);
		fonsDrawText(fs, 20, height-50, msg, NULL);

		fonsDrawDebug(fs, width - atlasw - 20, 20.0);

		glEnable(GL_DEPTH_TEST);

		glfwSwapBuffers(window);
		glfwPollEvents();
	}

	glfonsDelete(fs);

	glfwTerminate();
	return 0;
}
float ofxFontStash2::drawLines(const vector<StyledLine> &lines, float x, float y, bool debug){

	// if possible get rid of this translate:
	#ifndef GL_VERSION_3
	ofPushMatrix();
	ofTranslate(x, y);
	#endif

	ofVec2f offset;
	#ifdef GL_VERSION_3
	offset.x = x * pixelDensity;
	offset.y = y * pixelDensity;
	#endif

//	TS_START("count words");
//	int nDrawnWords;
//	for(int i = 0; i < lines.size(); i++){
//		for(int j = 0; j < lines[i].elements.size(); j++){
//			nDrawnWords ++;
//		}
//	}
//	TS_STOP("count words");

	//debug line heights!
	if(debug){
		TS_START("draw line Heights");
		ofSetColor(0,255,0,32);
		float yy = 0;
		for( const StyledLine &line : lines ){
			ofDrawLine(offset.x + 0.5f, offset.y + yy + 0.5f, offset.x + line.lineW + 0.5f, offset.y + yy + 0.5f);
			yy += line.lineH;
		}
		TS_STOP("draw line Heights");
	}

	ofxFontStashStyle drawStyle;
	drawStyle.fontSize = -1;

	float offY = 0.0f; // only track for return value
	TS_START("draw all lines");

	FONT_STASH_PRE_DRAW;

	#ifndef GL_VERSION_3
	if (pixelDensity != 1.0f){ //hmmmm
		ofScale(1.0f/pixelDensity, 1.0f/pixelDensity);
	}
	#endif


	for(int i = 0; i < lines.size(); i++){
		y += lines[i].lineH;
		
		for(int j = 0; j < lines[i].elements.size(); j++){

			if(lines[i].elements[j].content.type != SEPARATOR_INVISIBLE ){ //no need to draw the invisible chars

				const StyledLine &l = lines[i];
				const LineElement &el = l.elements[j];
				const string & texttt = el.content.styledText.text;

				if (el.content.styledText.style.valid &&
					drawStyle != el.content.styledText.style ){

					drawStyle = el.content.styledText.style;
					TS_START_ACC("applyStyle");
					applyStyle(drawStyle);
					TS_STOP_ACC("applyStyle");
				}
				//lines[i].elements[j].area.y += lines[i].lineH -lines[0].lineH;

				//TS_START_ACC("fonsDrawText");
				fonsDrawText(fs,
							 el.x * pixelDensity + offset.x,
							 (el.baseLineY + l.lineH - lines[0].lineH) * pixelDensity + offset.y,
							 texttt.c_str(),
							 NULL);
				//TS_STOP_ACC("fonsDrawText");

				//debug rects
				if(debug){
					//TS_START_ACC("debug rects");
					if(el.content.type == BLOCK_WORD) ofSetColor(70 * i, 255 - 70 * i, 0, 200);
					else ofSetColor(50 * i,255 - 50 * i, 0, 100);
					const ofRectangle &r = el.area;
					ofDrawRectangle(pixelDensity * r.x, pixelDensity * r.y, pixelDensity * r.width, pixelDensity * r.height);
					ofFill();
				}
			}
		}
	}
	TS_STOP("draw all lines");

	#ifndef GL_VERSION_3
	ofPopMatrix();
	#endif
	FONT_STASH_POST_DRAW;

	if(debug){
		ofSetColor(255);
	}
	return offY;
}