[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Written by Samuel Humphreys, samuel@users.sourceforge.net.
At the time of this writing procedural texture support is available with the following configurations:
Here is the basic, minimum code required to render text onto a procedural texture.
WARNING: OUTDATED!.
// Initialize a procedural texture of dimension 128x128. // Presuming you have already decided on which flags to use. iImage* proc_image = (iImage*)new csImageMemory(128,128); int flags = CS_TEXTURE_PROC | proc_tex_flags; iTextureHandle* proc_tex = main_txtmgr->RegisterTexture(proc_image,flags); main_txtmgr->PrepareTexture(proc_tex); // Get the interface to the procedural texture buffer. iGraphics3D* proc_G3D = proc_tex->GetProcTextureInterface(); int colour = proc_G3D->GetTextureManager()->FindRGB(255,255,255); // Before rendering with the main renderer, render to the // procedural texture buffer in the usual fashion. if (proc_G3D->BeginDraw(CSDRAW_2DGRAPHICS | CSDRAW_CLEARSCREEN)) { proc_G3D->GetDriver2D()->Write( 10, 10, colour, -1, "procedural texture"); proc_G3D->FinishDraw(); proc_G3D->Print(NULL); } |
Note: It would be better not to clear the screen each time and it would
be also better to calculate the extents of the text message as a `csRect'
and pass it to Print(csRect*)
.
The main design goal of the procedural texture subsystem is that you should be able to treat the `iGraphics3D' pointer the same as you would an `iGraphics3D' pointer to the main renderer. The mucky details of its implementation only surfaces to the application programmer when setting the flags while registering the procedural texture. Almost everything else is taken care of transparently.
The only blemish on an otherwise consistent interface and behaviors across all platforms and implementations is to do with the texture manager. This arises because there is a too good an optimization to lose with the software drivers, which requires a little care from the app programmer. It is basically this: When you query for the texture manager from the procedural texture buffer interface it may or may not be the same texture manager as that which is used by the main renderer. So you need to test for this and act accordingly. See the example application `dtsimple' for an example of how to deal with this. More details on this quirk are found below. The rest of this document is really about the choice of flags, and to be able to choose the right flags it is necessary to know something about how it all works.
First a warning: Procedural textures are quite expensive to utilize so if they are to be used at all, use them sparingly. Drawing on a procedural texture is in the best case as slow as drawing on screen. Depending on the special features you request for this texture via flags, things can even be worse.
For the most part procedural textures are useful if you intend for the texture images' content to respond to the user and where it would be impossible or too expensive to precompute all possible outcomes.
The `dtsimple' test application demonstrates in more detail how to setup and use procedural textures in ways which I wouldn't recommended for the normal application. The procedural textures it uses are all quite expensive and are really done that way to test the code. It is not recommended to have the engine render to a procedural texture unless thats absolutely what you need to do.
The questions you need to ask yourself at this stage in order to set the right flags are:
Flag: CS_TEXTURE_PROC_ALONE_HINT
If you can get away with having a set of textures devoted specifically to the procedural texture subsystem or none at all this is a big performance bonus on some configurations, while incurring no performance penalty on others. So I would strongly recommend setting this flag under these circumstances.
When using this flag, the texture manager used by the procedural texture may or may not be different from the main texture manager. So you have to test for this. Without this flag, they are always the same (but this may be a major performance hit).
The first distinction to draw when dealing with procedural textures in Crystal Space is whether or not the texture manager is going to be shared with the main renderer. If you are running at a screen depth of bigger than 8-bit it is better for the software procedural textures to have their own texture manager.
The reason for this is that the software texture manager's native format is really 8-bit. When a true colour image is registered and prepared with the software texture manager, a texture specific 256 colour palette is calculated and the image converted to utilize this palette. When the software renderer is in 15/16/32 bit modes it is only the final framebuffer writing stage which has anything to do with these true colour pixel formats, and only in the sense the palette points to 15/16/32 bit colours.
The implication for this is that if the procedural textures have their own texture manager they can render at 8-bit and utilize a fully 8-bit texture manager. This means that the 8-bit frame buffer can directly update the textures image without any conversions or palette recalculations. However this adds the restriction that you cannot use the texture handles received from registering images with the procedural textures' texture manager with the main renderer as its texture manager would know nothing about them.
To overcome this and the number of texture images you wish to use with both texture managers is small, then just re-register the images with the main texture manager and be careful to use the right texture handle with the correct texture manager. Unfortunately if you wish to use the engine, for example, to render to both textures and the engine will use the same texture handles on both textures, you will have to share the texture manager between the procedural texture renderers and the main screen renderer.
This is quite a performance hit if the screen depth is deeper than 8-bit. In these circumstances the procedural textures buffer will have the same depth as the screen's because the texture manager has set the palette to point at colours at screen depth. Once it is written to, a new palette will have to be calculated and the buffer re-converted to 8-bit.
Note that it is quite workable to have procedural textures bearing this flag co-existing with other procedural textures which do not. Bear in mind, however, that texture handles can only be used with the texture manager with which they were registered so you can not use the same texture handle with procedural textures which differ in this flag setting.
For these reasons it is necessary to be careful with which texture manager you are dealing with, as noted above.
With the back buffer implementation, this flag has no effect as it always utilizes the same texture manager as the main renderer. With the software implementation, this flag has the same effect as with the pure software version, as detailed above.
Flag: CS_TEXTURE_PROC_PERSISTENT
If you only want to redraw part of the texture, you can normally pass the
desired rectangle to the Print()
function. However, if the area you
want to redraw is not rectangular, for example if you want to write some
text over the existing texture, you have to use this flag. This will
guarantee that whatever you draw on the texture, it will still be there when
you start to draw on the texture again. In the example you would use this
flag, then draw the text on the existing texture and, if possible, pass a
rectangle that fits the size of the text to Print()
.
This flag has no effect for the software drivers as the buffer is always persistent.
With the hardware backbuffer implementation, the image you render to the backbuffer is of course overwritten by the main renderer. If you set this flag then the backbuffer drivers will rewrite the texture to the backbuffer when you call BeginDraw so you can carry on working as usual as if it was always there.
Flag: CS_TEXTURE_NOMIPMAPPING
Flag: CS_TEXTURE_PROC_MIPMAP_ON_SYNC
Naturally, it would be better if you did not specify mip-mapping, as this
would be very expensive to do each time you update the procedural texture, so
if you can possibly avoid it, do so by specifying
`CS_TEXTURE_NOMIPMAPPING'. Otherwise the next best approach is to
specify it to mip map on sync. This means that mipmaps won't be calculated
automatically, but you must tell the texture to do this. You can command to
refresh mip mapping with the method iTexturehandle->ProcTextureSync()
.
If none of these flags is specified, mipmapping is done automatically.
Hopefully this issue should not arise, because it would be unwise to refresh procedural textures each frame automatically when the texture is not visible (Although `dtsimple' pretty much does so.) Also the procedural textures are all implemented at the graphics driver level and the engine (which has all the visibility determination code) doesn't know anything about procedural textures, so if you did require to determine visibility before refreshing then currently you would have to implement your own little visibility test. Unless there is a huge demand or a really compelling reason to change the current situation, I don't expect this to change.
The biggest thing to definitely do when rendering to procedural textures is to
do it before you render to the main screen. This is because with OpenGL and
the procedural texture buffer may be the backbuffer. Lastly, of
course, try and utilize the iGraphics3D->Print(csRect*)
ability to just
update a small portion of the buffer.
Nothing particularly special needs to be done. Destroy the texture handle as
you would an ordinary texture. The only thing to bear in mind is that the
interfaces to the buffers are destroyed also, so if for some reason you
absolutely need to hang on to them for a while you just need to call
IncRef()
.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |