You can use render targets perfectly fine. They aren't rendered to the screen they are rendered to a new texture at run time. The image is the only thing that's being drawn to the screen. So, you could have a 100 draw functions and render it to a single texture and only draw that texture to the screen with dxDrawImage.
The reason your text became blurry with render targets is because you were either stretching the image or the positions/dimensions were off.
Take this simple object oriented approach and you'll have an easy to use function. It works similar to the CEGUI functions except that you're responsible for drawing it, although you could make the function handle that as well.
function dxCreateFramedText(text, left, top, width, height, color, scale, font, alignX, alignY, clip, wordBreak, postGUI)
local self = {}
local rt = dxCreateRenderTarget(width, height, true)
self.draw = function(x, y, w, h)
dxDrawImage(left, top, width, height, rt)
end
self.update = function()
dxSetRenderTarget(rt, true)
dxDrawText(text, 1, 1, width + 1, height + 1, tocolor(0, 0, 0), scale, font, alignX, alignY, clip, wordBreak, postGUI)
dxDrawText(text, 1, -1, width + 1, height - 1, tocolor(0, 0, 0), scale, font, alignX, alignY, clip, wordBreak, postGUI)
dxDrawText(text, -1, 1, width - 1, height + 1, tocolor(0, 0, 0), scale, font, alignX, alignY, clip, wordBreak, postGUI)
dxDrawText(text, 1, 1, width - 1, height - 1, tocolor(0, 0, 0), scale, font, alignX, alignY, clip, wordBreak, postGUI)
dxDrawText(text, 0, 0, width, height, color, scale, font, alignX, alignY, clip, wordBreak, postGUI)
dxSetRenderTarget()
end
self.setText = function(v)
text = v
self.update()
end
self.setColor = function(v)
color = v
self.update()
end
self.update()
return self
end
local msg1 = dxCreateFramedText("Hello there",222,300,520,140,tocolor(0,255,0),3,'default','left','top',false,false,false)
local msg2 = dxCreateFramedText("How are you?",222,400,520,140,tocolor(0,255,0),3,'default','left','top',false,false,false)
addEventHandler('onClientRender', root, function()
msg1.draw()
msg2.draw()
end)
msg2.setColor(tocolor(0,255,255))
addCommandHandler('c', function() msg1.setColor(tocolor(255,99,0)) end)
It may look a little over the top but yeah, it works, and it's fast.