RigsofRods
Soft-body Physics Simulation
WriteTextToTexture.cpp
Go to the documentation of this file.
1 /*
2  This source file is part of Rigs of Rods
3  Copyright 2005-2012 Pierre-Michel Ricordel
4  Copyright 2007-2012 Thomas Fischer
5 
6  For more information, see http://www.rigsofrods.org/
7 
8  Rigs of Rods is free software: you can redistribute it and/or modify
9  it under the terms of the GNU General Public License version 3, as
10  published by the Free Software Foundation.
11 
12  Rigs of Rods is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with Rigs of Rods. If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 #include "WriteTextToTexture.h"
22 
23 #include "Application.h"
24 
25 #include <Overlay/OgreFont.h>
26 #include <OgreHardwarePixelBuffer.h>
27 #include <OgreMaterial.h>
28 #include <OgreTechnique.h>
29 #include <OgreTexture.h>
30 #include <OgreTextureManager.h>
31 #include <Overlay/OgreFontManager.h>
32 
33 // source: ogre wiki: http://www.ogre3d.org/tikiwiki/tiki-index.php?page=HowTo%3A+Write+text+on+texture
34 using namespace Ogre;
35 
36 void SaveImage(TexturePtr TextureToSave, String filename)
37 {
38  HardwarePixelBufferSharedPtr readbuffer;
39  readbuffer = TextureToSave->getBuffer(0, 0);
40  readbuffer->lock(HardwareBuffer::HBL_NORMAL);
41  const PixelBox& readrefpb = readbuffer->getCurrentLock();
42  uchar* readrefdata = static_cast<uchar*>(readrefpb.data);
43 
44  Image img;
45  img = img.loadDynamicImage(readrefdata, TextureToSave->getWidth(),
46  TextureToSave->getHeight(), TextureToSave->getFormat());
47  img.save(filename);
48 
49  readbuffer->unlock();
50 }
51 
52 void WriteToTexture(const String& str, TexturePtr destTexture, Ogre::Box destRectangle, Ogre::Font* Reffont, const ColourValue& color, int fontSize, int fontDPI, char justify, bool wordwrap)
53 {
54  using namespace Ogre;
55 
56  if (destTexture->getHeight() < destRectangle.bottom)
57  destRectangle.bottom = destTexture->getHeight();
58  if (destTexture->getWidth() < destRectangle.right)
59  destRectangle.right = destTexture->getWidth();
60 
61  // Find our scaled up (or down) font.
62  std::string fontname = "WTTFont_" + TOSTRING(fontSize + fontDPI) + "_" + Reffont->getSource();
63  FontPtr font = FontManager::getSingleton().getByName(fontname);
64 
65  // Font not found, let's created it :)
66  if (font.isNull())
67  {
68  font = FontManager::getSingleton().create(fontname, "General");
69  font->setType(FT_TRUETYPE);
70  font->setSource(Reffont->getSource());
71 
72  font->setTrueTypeSize(fontSize);
73  font->setTrueTypeResolution(fontDPI);
74  font->load();
75  LOG("[WriteToTexture] Created font: " + fontname);
76  }
77 
78  TexturePtr fontTexture = (TexturePtr)TextureManager::getSingleton().getByName(font->getMaterial()->getTechnique(0)->getPass(0)->getTextureUnitState(0)->getTextureName());
79 
80  HardwarePixelBufferSharedPtr fontBuffer = fontTexture->getBuffer();
81  HardwarePixelBufferSharedPtr destBuffer = destTexture->getBuffer();
82 
83  PixelBox destPb = destBuffer->lock(destRectangle, HardwareBuffer::HBL_NORMAL);
84 
85  // The font texture buffer was created write only...so we cannot read it back :o). One solution is to copy the buffer instead of locking it. (Maybe there is a way to create a font texture which is not write_only ?)
86 
87  // create a buffer
88  size_t nBuffSize = fontBuffer->getSizeInBytes();
89  uint8* buffer = (uint8*)calloc(nBuffSize, sizeof(uint8));
90 
91  // create pixel box using the copy of the buffer
92  PixelBox fontPb(fontBuffer->getWidth(), fontBuffer->getHeight(), fontBuffer->getDepth(), fontBuffer->getFormat(), buffer);
93  fontBuffer->blitToMemory(fontPb);
94 
95  uint8* fontData = static_cast<uint8*>(fontPb.data);
96  uint8* destData = static_cast<uint8*>(destPb.data);
97 
98  const size_t fontPixelSize = PixelUtil::getNumElemBytes(fontPb.format);
99  const size_t destPixelSize = PixelUtil::getNumElemBytes(destPb.format);
100 
101  const size_t fontRowPitchBytes = fontPb.rowPitch * fontPixelSize;
102  const size_t destRowPitchBytes = destPb.rowPitch * destPixelSize;
103 
104  Box* GlyphTexCoords;
105  GlyphTexCoords = new Box[str.size()];
106 
107  Ogre::Font::UVRect glypheTexRect;
108  size_t charheight = 0;
109  size_t charwidth = 0;
110 
111  for (unsigned int i = 0; i < str.size(); i++)
112  {
113  if ((str[i] != '\t') && (str[i] != '\n') && (str[i] != ' '))
114  {
115  glypheTexRect = font->getGlyphTexCoords(str[i]);
116  GlyphTexCoords[i].left = glypheTexRect.left * fontTexture->getSrcWidth();
117  GlyphTexCoords[i].top = glypheTexRect.top * fontTexture->getSrcHeight();
118  GlyphTexCoords[i].right = glypheTexRect.right * fontTexture->getSrcWidth();
119  GlyphTexCoords[i].bottom = glypheTexRect.bottom * fontTexture->getSrcHeight();
120 
121  if (GlyphTexCoords[i].getHeight() > charheight)
122  charheight = GlyphTexCoords[i].getHeight();
123  if (GlyphTexCoords[i].getWidth() > charwidth)
124  charwidth = GlyphTexCoords[i].getWidth();
125  }
126  }
127 
128  size_t cursorX = 0;
129  size_t cursorY = 0;
130  size_t lineend = destRectangle.getWidth();
131  bool carriagreturn = true;
132  for (unsigned int strindex = 0; strindex < str.size(); strindex++)
133  {
134  switch (str[strindex])
135  {
136  case ' ': cursorX += charwidth;
137  break;
138  case '\t': cursorX += charwidth * 3;
139  break;
140  case '\n': cursorY += charheight;
141  carriagreturn = true;
142  break;
143  default:
144  {
145  //wrapping
146  if ((cursorX + GlyphTexCoords[strindex].getWidth() > lineend) && !carriagreturn)
147  {
148  cursorY += charheight;
149  carriagreturn = true;
150  }
151 
152  //justify
153  if (carriagreturn)
154  {
155  size_t l = strindex;
156  size_t textwidth = 0;
157  size_t wordwidth = 0;
158 
159  while (l < str.size() && str[l] != '\n')
160  {
161  wordwidth = 0;
162 
163  switch (str[l])
164  {
165  case ' ': wordwidth = charwidth;
166  ++l;
167  break;
168  case '\t': wordwidth = charwidth * 3;
169  ++l;
170  break;
171  case '\n': l = str.size();
172  }
173 
174  if (wordwrap)
175  while (l < str.size() && str[l] != ' ' && str[l] != '\t' && str[l] != '\n')
176  {
177  wordwidth += GlyphTexCoords[l].getWidth();
178  ++l;
179  }
180  else
181  {
182  wordwidth += GlyphTexCoords[l].getWidth();
183  l++;
184  }
185 
186  if ((textwidth + wordwidth) <= destRectangle.getWidth())
187  textwidth += (wordwidth);
188  else
189  break;
190  }
191 
192  if ((textwidth == 0) && (wordwidth > destRectangle.getWidth()))
193  textwidth = destRectangle.getWidth();
194 
195  switch (justify)
196  {
197  case 'c': cursorX = (destRectangle.getWidth() - textwidth) / 2;
198  lineend = destRectangle.getWidth() - cursorX;
199  break;
200 
201  case 'r': cursorX = (destRectangle.getWidth() - textwidth);
202  lineend = destRectangle.getWidth();
203  break;
204 
205  default: cursorX = 0;
206  lineend = textwidth;
207  break;
208  }
209 
210  carriagreturn = false;
211  }
212 
213  //abort - net enough space to draw
214  if ((cursorY + charheight) > destRectangle.getHeight())
215  goto stop;
216 
217  //draw pixel by pixel
218  for (size_t i = 0; i < GlyphTexCoords[strindex].getHeight(); i++)
219  for (size_t j = 0; j < GlyphTexCoords[strindex].getWidth(); j++)
220  {
221  float alpha = color.a * (fontData[(i + GlyphTexCoords[strindex].top) * fontRowPitchBytes + (j + GlyphTexCoords[strindex].left) * fontPixelSize + 1] / 255.0);
222  float invalpha = 1.0 - alpha;
223  size_t offset = (i + cursorY) * destRowPitchBytes + (j + cursorX) * destPixelSize;
224  ColourValue pix;
225  PixelUtil::unpackColour(&pix, destPb.format, &destData[offset]);
226  pix = (pix * invalpha) + (color * alpha);
227  PixelUtil::packColour(pix, destPb.format, &destData[offset]);
228  }
229 
230  cursorX += GlyphTexCoords[strindex].getWidth();
231  }//default
232  }//switch
233  }//for
234 
235 stop:
236  delete[] GlyphTexCoords;
237 
238  destBuffer->unlock();
239 
240  // Free the memory allocated for the buffer
241  free(buffer);
242  buffer = 0;
243 }
TOSTRING
#define TOSTRING(x)
Definition: Application.h:56
SaveImage
void SaveImage(TexturePtr TextureToSave, String filename)
Definition: WriteTextToTexture.cpp:36
Application.h
Central state/object manager and communications hub.
WriteToTexture
void WriteToTexture(const String &str, TexturePtr destTexture, Ogre::Box destRectangle, Ogre::Font *Reffont, const ColourValue &color, int fontSize, int fontDPI, char justify, bool wordwrap)
Definition: WriteTextToTexture.cpp:52
Ogre
Definition: ExtinguishableFireAffector.cpp:35
WriteTextToTexture.h