Rigs of Rods 2023.09
Soft-body Physics Simulation
Loading...
Searching...
No Matches
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
34using namespace Ogre;
35
36void 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
52void 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)
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
235stop:
236 delete[] GlyphTexCoords;
237
238 destBuffer->unlock();
239
240 // Free the memory allocated for the buffer
241 free(buffer);
242 buffer = 0;
243}
Central state/object manager and communications hub.
#define TOSTRING(x)
Definition Application.h:57
void LOG(const char *msg)
Legacy alias - formerly a macro.
void WriteToTexture(const String &str, TexturePtr destTexture, Ogre::Box destRectangle, Ogre::Font *Reffont, const ColourValue &color, int fontSize, int fontDPI, char justify, bool wordwrap)
void SaveImage(TexturePtr TextureToSave, String filename)