Added aqua_speed for rite geo 50 tryker
[ryzomcore.git] / nel / tools / 3d / textures_tool / main.cpp
blobcccb62bee68adbd5a3f47630981dc51d2ef22409
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "nel/misc/file.h"
19 #include "nel/misc/common.h"
20 #include "nel/misc/bitmap.h"
21 #include "nel/misc/path.h"
22 #include "nel/misc/cmd_args.h"
23 #include "nel/misc/vector_2d.h"
24 #include "nel/misc/uv.h"
25 #include "nel/misc/algo.h"
27 struct CPoint
29 CPoint(sint _x, sint _y) :x(_x), y(_y)
33 CPoint operator + (const CPoint &p) const
35 return CPoint(x + p.x, y + p.y);
38 sint x;
39 sint y;
42 const CPoint Up(0, -1);
43 const CPoint Down(0, 1);
44 const CPoint Left(-1, 0);
45 const CPoint Right(1, 0);
47 uint TextureSize = 4096;
49 const NLMISC::CRGBA DiscardColor = NLMISC::CRGBA::Red;
50 const NLMISC::CRGBA KeepColor = NLMISC::CRGBA::Blue;
52 typedef std::vector<CPoint> CPoints;
54 struct CFace
56 std::vector<uint> indices;
59 struct CObject
61 std::string name;
62 std::vector<NLMISC::CUV> textureCoords;
63 std::vector<CFace> faces;
65 void display()
67 nlinfo("Object %s processed with %u vertices and %u faces", name.c_str(), (uint)textureCoords.size(), (uint)faces.size());
71 bool fillPoint(NLMISC::CBitmap &bitmap, sint width, CPoints &points)
73 if (points.empty()) return false;
75 // take last point in queue
76 CPoint p(points.back());
77 points.pop_back();
79 NLMISC::CRGBA c = bitmap.getPixelColor(p.x, p.y);
81 if (c == NLMISC::CRGBA::White)
83 // white is used for background
85 // replace with color we want to discard
86 bitmap.setPixelColor(p.x, p.y, DiscardColor);
88 uint w = bitmap.getWidth();
89 uint h = bitmap.getHeight();
91 // put adjacent pixels in queue to process later
92 if (p.y > 0) points.push_back(p + Up);
93 if (p.y < h-1) points.push_back(p + Down);
94 if (p.x > 0) points.push_back(p + Left);
95 if (p.x < w-1) points.push_back(p + Right);
97 else if (c == NLMISC::CRGBA::Black)
99 // black is used for vertices
101 // increase them by border width
102 for (sint y = -width; y <= width; ++y)
104 for (sint x = -width; x <= width; ++x)
106 bitmap.setPixelColor(p.x + x, p.y + y, KeepColor);
111 return true;
114 void drawEdge(NLMISC::CBitmap &bitmap, const CObject &object, const CFace &face, uint index0, uint index1)
116 NLMISC::CUV uv0 = object.textureCoords[face.indices[index0]];
117 NLMISC::CUV uv1 = object.textureCoords[face.indices[index1]];
119 std::vector<std::pair<sint, sint> > pixels;
121 // draw the triangle with vertices UV coordinates
122 NLMISC::drawFullLine(uv0.U, uv0.V, uv1.U, uv1.V, pixels);
124 // for each pixels, set them to black
125 for (uint j = 0, jlen = pixels.size(); j < jlen; ++j)
127 bitmap.setPixelColor(pixels[j].first, pixels[j].second, NLMISC::CRGBA::Black);
131 int main(int argc, char **argv)
133 NLMISC::CApplicationContext applicationContext;
135 // Parse Command Line.
136 //====================
137 NLMISC::CCmdArgs args;
139 args.setDescription("Textures tool");
140 args.addArg("c", "colorize", "color", "Colorize textures using a color (in HTML hexdecimal format like #rrggbb)");
141 args.addArg("f", "fill", "color or image", "Fill background part with color or image");
142 args.addArg("u", "uvmap", "", "Generate a UV Map texture from OBJ file");
143 args.addArg("w", "width", "width of border", "Width of the border to fill (default 0)");
144 args.addArg("s", "size", "size of output bitmap", "Width and height of generated bitmap (default 4096)");
145 args.addArg("b", "background", "background color", "Color to use to fill background");
146 args.addArg("o", "output", "filename", "Output filename");
147 args.addAdditionalArg("filename", "File to process", true, true);
149 if (!args.parse(argc, argv)) return 1;
151 std::string filename = args.getAdditionalArg("filename").front();
153 std::string output = args.haveArg("o") ? args.getArg("o").front() : "";
155 if (args.haveArg("s"))
157 // size of generated bitmap
158 NLMISC::fromString(args.getArg("s").front(), TextureSize);
161 if (args.haveArg("c"))
163 // colorize
164 NLMISC::CIFile file;
166 NLMISC::CRGBA color;
167 color.fromString(args.getArg("c").front());
169 if (file.open(filename))
171 NLMISC::CBitmap bitmap;
173 if (bitmap.load(file))
175 NLMISC::CObjectVector<uint8> &pixels = bitmap.getPixels();
177 NLMISC::CRGBA *pRGBA = (NLMISC::CRGBA*)&pixels[0];
179 uint32 size = bitmap.getSize();
181 for (uint j = 0; j < size; ++j)
183 pRGBA->modulateFromColorRGBOnly(*pRGBA, color);
184 ++pRGBA;
187 NLMISC::COFile out;
189 if (out.open(output))
191 bitmap.writePNG(out, 24);
197 if (args.haveArg("f"))
199 // fill areas in a bitmap with another texture or color
201 // for example :
202 // textures_tool -f normal.png -w 2 -b #000000 uvmap.png -o test_normal.png
203 // will use a copy 1024x1024 texture map on a 4096x4096 UV Map preserving the different areas
205 std::string foregroundColorOrFilename = args.getArg("f").front();
207 NLMISC::CRGBA foregroundColor = NLMISC::CRGBA::Black, backgroundColor = NLMISC::CRGBA::Black;
209 NLMISC::CBitmap textureBitmap;
211 bool useTexture = false;
213 // f parameter is required
214 if (NLMISC::CFile::fileExists(foregroundColorOrFilename))
216 // load texture
217 NLMISC::CIFile textureFile;
219 if (!textureFile.open(foregroundColorOrFilename))
221 nlwarning("Unable to open %s", foregroundColorOrFilename.c_str());
222 return 1;
225 // decode texture
226 if (!textureBitmap.load(textureFile))
228 nlwarning("Unable to decode %s", foregroundColorOrFilename.c_str());
229 return 1;
232 useTexture = true;
234 else
236 // parse color from argument
237 foregroundColor.fromString(foregroundColorOrFilename);
240 if (args.haveArg("b"))
242 // parse HTML color from argument
243 backgroundColor.fromString(args.getArg("b").front());
246 sint width = 0;
248 if (args.haveArg("w"))
250 // parse width of borders
251 NLMISC::fromString(args.getArg("w").front(), width);
254 // load bitmap
255 NLMISC::CIFile file;
257 if (!file.open(filename))
259 nlwarning("Unable to open %s", filename.c_str());
260 return 1;
263 // decode bitmap
264 NLMISC::CBitmap inBitmap;
266 if (!inBitmap.load(file))
268 nlwarning("Unable to decode %s", filename.c_str());
269 return 1;
272 CPoints Points;
274 // we can't have more than width * height points, so allocate memory for all of them
275 Points.reserve(inBitmap.getWidth() * inBitmap.getHeight());
277 // first point to process
278 Points.push_back(CPoint(0, 0));
280 // process all points from 0, 0
281 while(fillPoint(inBitmap, width, Points)) { }
283 // create a new bitmap for output
284 NLMISC::CBitmap outBitmap;
285 outBitmap.resize(inBitmap.getWidth(), inBitmap.getHeight());
287 // copy points colors to new bitmap
288 for (sint y = 0, h = inBitmap.getHeight(); y < h; ++y)
290 for (sint x = 0, w = inBitmap.getWidth(); x < w; ++x)
292 if (inBitmap.getPixelColor(x, y) != DiscardColor)
294 // we copy this point, repeat texture image if using it
295 outBitmap.setPixelColor(x, y, useTexture ? textureBitmap.getPixelColor(x % textureBitmap.getWidth(), y % textureBitmap.getHeight()) : foregroundColor);
297 else
299 // put a background color
300 outBitmap.setPixelColor(x, y, backgroundColor);
305 // save output bitmap
306 NLMISC::COFile outFile;
308 if (outFile.open(output))
310 outBitmap.writePNG(outFile, 24);
314 if (args.haveArg("u"))
316 NLMISC::CIFile objFile;
318 if (!objFile.open(filename))
320 nlwarning("Unable to open %s", filename.c_str());
321 return 1;
324 CObject object;
326 char buffer[1024];
328 while (!objFile.eof())
330 objFile.getline(buffer, 1024);
331 buffer[1023] = '\0';
333 std::string line(buffer);
335 if (line.size() > 1022)
337 nlwarning("More than 1022 bytes on a line!");
338 return 1;
341 if (line.size() < 3) continue;
343 // texture coordinate
344 if (line.substr(0, 3) == "vt ")
346 // vertex texture
347 std::vector<std::string> tokens;
348 NLMISC::explode(line, std::string(" "), tokens);
350 if (tokens.size() == 3)
352 float u, v;
353 NLMISC::fromString(tokens[1], u);
354 NLMISC::fromString(tokens[2], v);
356 // V coordinates are inverted
357 object.textureCoords.push_back(NLMISC::CUV(u * (float)TextureSize, (1.f - v) * (float)TextureSize));
359 else
361 nlwarning("Not 3 arguments for VT");
364 else if (line.substr(0, 2) == "f ")
366 // face
367 std::vector<std::string> tokens;
368 NLMISC::explode(line, std::string(" "), tokens);
370 CFace face;
371 face.indices.resize(tokens.size()-1);
373 bool faceValid = true;
375 for (uint i = 1, ilen = tokens.size(); i < ilen; ++i)
377 std::vector<std::string> tokens2;
378 NLMISC::explode(tokens[i], std::string("/"), tokens2);
380 if (tokens2.size() == 3)
382 if (NLMISC::fromString(tokens2[1], face.indices[i - 1]))
384 // we want indices start from 0 instead of 1
385 --face.indices[i - 1];
387 else
389 faceValid = false;
392 else
394 nlwarning("Not 3 arguments for indices");
398 if (faceValid) object.faces.push_back(face);
400 else if (line.substr(0, 2) == "o ")
402 // object
403 object.name = line.substr(2);
404 object.display();
408 object.display();
410 objFile.close();
412 // draw UV Map
413 // create a new bitmap for output
414 NLMISC::CBitmap outBitmap;
415 outBitmap.resize(TextureSize, TextureSize);
417 // white background
418 memset(&outBitmap.getPixels()[0], 255, TextureSize * TextureSize * 4);
420 // process all faces
421 for (uint i = 0, ilen = object.faces.size(); i < ilen; ++i)
423 const CFace &face = object.faces[i];
425 // pixels of a face
426 for (uint k = 1, klen = face.indices.size(); k < klen; ++k)
428 drawEdge(outBitmap, object, face, k - 1, k);
431 // link last and fist pixels
432 drawEdge(outBitmap, object, face, face.indices.size()-1, 0);
435 // save output bitmap
436 NLMISC::COFile outFile;
438 if (outFile.open(output))
440 outBitmap.writePNG(outFile, 24);
444 return 0;