1 /*
2 * Copyright 2011-2012 Arx Libertatis Team (see the AUTHORS file)
3 *
4 * This file is part of Arx Libertatis.
5 *
6 * Arx Libertatis is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Arx Libertatis is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Arx Libertatis. If not, see <http://www.gnu.org/licenses/>.
18 */
19 /* Based on:
20 ===========================================================================
21 ARX FATALIS GPL Source Code
22 Copyright (C) 1999-2010 Arkane Studios SA, a ZeniMax Media company.
23
24 This file is part of the Arx Fatalis GPL Source Code ('Arx Fatalis Source Code').
25
26 Arx Fatalis Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
27 License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
28
29 Arx Fatalis Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
30 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
31
32 You should have received a copy of the GNU General Public License along with Arx Fatalis Source Code. If not, see
33 <http://www.gnu.org/licenses/>.
34
35 In addition, the Arx Fatalis Source Code is also subject to certain additional terms. You should have received a copy of these
36 additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Arx
37 Fatalis Source Code. If not, please request a copy in writing from Arkane Studios at the address below.
38
39 If you have questions concerning this license or the applicable additional terms, you may contact in writing Arkane Studios, c/o
40 ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
41 ===========================================================================
42 */
43
44 #include "graphics/data/CinematicTexture.h"
45
46 #include <stddef.h>
47 #include <string>
48 #include <cstdlib>
49
50 #include <boost/foreach.hpp>
51
52 #include "graphics/Math.h"
53 #include "graphics/Renderer.h"
54 #include "graphics/texture/Texture.h"
55
56 #include "io/resource/ResourcePath.h"
57 #include "io/resource/PakReader.h"
58 #include "io/log/Logger.h"
59
60 static const int MaxW = 256;
61 static const int MaxH = 256;
62
63 using std::string;
64
65 void FreeGrille(CinematicGrid * grille);
66
67 static void ReajustUV(CinematicBitmap* bi);
68
69 /*-----------------------------------------------------------*/
~CinematicBitmap()70 CinematicBitmap::~CinematicBitmap()
71 {
72 FreeGrille(&grid);
73 }
74
75 /*-----------------------------------------------------------*/
AllocGrille(CinematicGrid * grille,int nbx,int nby,float tx,float ty,float dx,float dy,int echelle)76 bool AllocGrille(CinematicGrid * grille, int nbx, int nby, float tx, float ty, float dx, float dy, int echelle)
77 {
78 grille->echelle = echelle;
79 int oldnbx = nbx + 1;
80 int oldnby = nby + 1;
81 nbx *= echelle;
82 nby *= echelle;
83 float olddx = dx;
84 float olddy = dy;
85 dx /= ((float)echelle);
86 dy /= ((float)echelle);
87
88 grille->nbuvs = 0;
89 grille->nbinds = 0;
90 grille->nbuvsmalloc = grille->nbvertexs = (nbx + 1) * (nby + 1);
91 grille->nbfaces = (nbx * nby) << 1;
92 grille->nbindsmalloc = grille->nbfaces;
93 grille->vertexs = (Vec3f *)malloc(grille->nbvertexs * sizeof(Vec3f));
94 grille->uvs = (C_UV *)malloc(grille->nbvertexs * sizeof(C_UV));
95 grille->inds = (C_IND *)malloc(grille->nbindsmalloc * sizeof(C_IND));
96
97 //vertexs
98 grille->nbx = nbx;
99 grille->nby = nby;
100 tx *= .5f;
101 ty *= .5f;
102 float depx = -tx;
103 float depy = -ty;
104
105 Vec3f * v = grille->vertexs;
106 float olddyy = olddy;
107
108 while (oldnby--)
109 {
110 nby = echelle;
111
112 if (!oldnby) nby = 1;
113
114 while (nby--)
115 {
116
117 float olddxx = olddx;
118 float depxx = depx;
119 float dxx = dx;
120 int oldnbxx = oldnbx;
121
122 while (oldnbxx--)
123 {
124 nbx = echelle;
125
126 if (!oldnbxx) nbx = 1;
127
128 while(nbx--) {
129 *v = Vec3f(depxx, depy, 0.f);
130 depxx += dxx;
131 v++;
132 }
133
134 olddxx += olddx;
135
136 if (olddxx > (tx * 2.f))
137 {
138 dxx = tx - depxx;
139 dxx /= (float)echelle;
140 }
141
142 }
143
144 depy += dy;
145 }
146
147 olddyy += olddy;
148
149 if (olddyy > (ty * 2.f))
150 {
151 dy = ty - depy;
152 dy /= (float)echelle;
153 }
154
155 }
156
157 return true;
158 }
159 /*-----------------------------------------------------------*/
AddMaterial(CinematicGrid * grille,Texture2D * tex)160 int AddMaterial(CinematicGrid * grille, Texture2D* tex)
161 {
162 int matIdx = grille->mats.size();
163 grille->mats.resize(matIdx + 1);
164
165 int deb;
166 if (matIdx == 0)
167 deb = 0;
168 else
169 deb = grille->mats[matIdx-1].startind + grille->mats[matIdx-1].nbind;
170
171 grille->mats[matIdx].tex = tex;
172 grille->mats[matIdx].startind = deb;
173 grille->mats[matIdx].nbind = 0;
174
175 return matIdx;
176 }
177
FreeGrille(CinematicGrid * grille)178 void FreeGrille(CinematicGrid * grille) {
179
180 free(grille->vertexs), grille->vertexs = NULL;
181 free(grille->uvs), grille->uvs = NULL;
182 free(grille->inds), grille->inds = NULL;
183
184 BOOST_FOREACH(C_INDEXED & mat, grille->mats) {
185 delete mat.tex;
186 }
187
188 grille->mats.clear();
189 }
190
GetIndNumCube(CinematicGrid * grille,int cx,int cy,int * i1,int * i2,int * i3,int * i4)191 void GetIndNumCube(CinematicGrid * grille, int cx, int cy, int * i1, int * i2, int * i3, int * i4)
192 {
193 *i1 = cy * (grille->nbx + 1) + cx;
194 *i2 = *i1 + 1;
195 *i3 = *i1 + (grille->nbx + 1);
196 *i4 = *i3 + 1;
197 }
198 /*-----------------------------------------------------------*/
AddPoly(CinematicGrid * grille,int matIdx,int i0,int i1,int i2)199 void AddPoly(CinematicGrid * grille, int matIdx, int i0, int i1, int i2) {
200
201 if (grille->nbinds == grille->nbindsmalloc)
202 {
203 grille->nbindsmalloc += 100;
204 grille->inds = (C_IND *)realloc((void *)grille->inds, grille->nbindsmalloc * sizeof(C_IND));
205 }
206
207 grille->inds[grille->nbinds].i1 = checked_range_cast<unsigned short>(i0);
208 grille->inds[grille->nbinds].i2 = checked_range_cast<unsigned short>(i1);
209 grille->inds[grille->nbinds++].i3 = checked_range_cast<unsigned short>(i2);
210 grille->mats[matIdx].nbind += 3;
211
212 }
213 /*-----------------------------------------------------------*/
AddQuadUVs(CinematicGrid * grille,int depcx,int depcy,int tcx,int tcy,int bitmapposx,int bitmapposy,int bitmapwx,int bitmapwy,Texture2D * tex)214 void AddQuadUVs(CinematicGrid * grille, int depcx, int depcy, int tcx, int tcy, int bitmapposx, int bitmapposy, int bitmapwx, int bitmapwy, Texture2D* tex)
215 {
216 int matIdx = AddMaterial(grille, tex);
217 grille->mats[matIdx].bitmapdepx = bitmapposx;
218 grille->mats[matIdx].bitmapdepy = bitmapposy;
219 grille->mats[matIdx].bitmapw = bitmapwx;
220 grille->mats[matIdx].bitmaph = bitmapwy;
221 grille->mats[matIdx].nbvertexs = (tcx + 1) * (tcy + 1);
222
223 if ((grille->nbuvs + (4 *(tcx * tcy))) > grille->nbuvsmalloc)
224 {
225 grille->nbuvsmalloc += 4 * (tcx * tcy);
226 grille->uvs = (C_UV *)realloc((void *)grille->uvs, grille->nbuvsmalloc * sizeof(C_UV));
227 }
228
229 float v = 0.f;
230 float du = 0.999999f / (float)tcx;
231 float dv = 0.999999f / (float)tcy;
232 tcy++;
233 tcx++;
234 int tcyy = tcy;
235 int depcyy = depcy;
236
237 while (tcyy--)
238 {
239 float u = 0.f;
240 int depcxx = depcx;
241 int tcxx = tcx;
242
243 while (tcxx--)
244 {
245 int i0, i1, i2, i3;
246 GetIndNumCube(grille, depcxx, depcyy, &i0, &i1, &i2, &i3);
247
248 //uvs
249 grille->uvs[grille->nbuvs].indvertex = i0;
250 grille->uvs[grille->nbuvs].uv.x = u;
251 grille->uvs[grille->nbuvs++].uv.y = v;
252 depcxx++;
253 u += du;
254 }
255
256 depcyy++;
257 v += dv;
258 }
259
260 tcx--;
261 tcy--;
262
263 while (tcy--)
264 {
265 int depcxx = depcx;
266 int tcxx = tcx;
267
268 while (tcxx--)
269 {
270 int i0, i1, i2, i3;
271 GetIndNumCube(grille, depcxx, depcy, &i0, &i1, &i2, &i3);
272
273 AddPoly(grille, matIdx, i0, i1, i2);
274 AddPoly(grille, matIdx, i1, i2, i3);
275 depcxx++;
276 }
277
278 depcy++;
279 }
280 }
281
CreateCinematicBitmap(const res::path & path,int scale)282 CinematicBitmap* CreateCinematicBitmap(const res::path & path, int scale) {
283
284 int nbx, nby, w, h, num;
285 CinematicBitmap * bi;
286
287 string name = path.basename();
288 if(name.empty()) {
289 return 0;
290 }
291
292 bi = new CinematicBitmap();
293 if (!bi)
294 return 0;
295
296 LogDebug("loading cinematic texture " << path);
297
298 size_t size = 0;
299
300 res::path filename = path;
301 filename.set_ext("bmp");
302 char * data = resources->readAlloc(filename, size);
303 if(!data) {
304 filename.set_ext("tga");
305 data = resources->readAlloc(filename, size);
306 }
307
308 if(!data)
309 {
310 LogError << path << " not found";
311 return 0;
312 }
313
314 Image cinematicImage;
315 cinematicImage.LoadFromMemory(data, size);
316
317 free(data);
318
319 unsigned int width = cinematicImage.GetWidth();
320 unsigned int height = cinematicImage.GetHeight();
321 nbx = width / MaxW;
322 nby = height / MaxH;
323
324 if (width % MaxW)
325 nbx++;
326
327 if (height % MaxH)
328 nby++;
329
330 bi->w = width;
331 bi->h = height;
332
333 bi->nbx = nbx;
334 bi->nby = nby;
335
336 AllocGrille(&bi->grid, nbx, nby, (float)bi->w, (float)bi->h, (float)((bi->w > MaxW) ? MaxW : bi->w), (float)((bi->h > MaxH) ? MaxH : bi->h), scale);
337
338 num = 0;
339 h = bi->h;
340 float dy = -(float)(bi->h >> 1);
341
342 while (nby)
343 {
344 float dx = -(float)(bi->w >> 1);
345
346 int h2;
347
348 if ((h - MaxH) < 0) h2 = h;
349 else h2 = MaxH;
350
351 w = bi->w;
352 int nbxx = nbx;
353
354 while (nbxx)
355 {
356 int w2 = (w - MaxW) < 0 ? w : MaxW;
357
358 Texture2D* tex = GRenderer->CreateTexture2D();
359 tex->Init(w2, h2, cinematicImage.GetFormat());
360 tex->GetImage().Copy(cinematicImage, 0, 0, bi->w - w, bi->h - h, w2, h2);
361 tex->Upload();
362
363 AddQuadUVs(&bi->grid, (bi->nbx - nbxx) * scale, (bi->nby - nby) * scale, scale, scale, bi->w - w, bi->h - h, w2, h2, tex);
364
365 dx += (float)w2;
366 w -= MaxW;
367
368 num++;
369 nbxx--;
370 }
371
372 dy += (float)h2;
373 h -= MaxH;
374 nby--;
375 }
376
377 bi->grid.echelle = scale;
378
379 ReajustUV(bi);
380
381 return bi;
382 }
383
384 /*-----------------------------------------------------------*/
ReajustUV(CinematicBitmap * cb)385 static void ReajustUV(CinematicBitmap* cb) {
386
387 C_UV* uvs = cb->grid.uvs;
388
389 for(std::vector<C_INDEXED>::iterator mat = cb->grid.mats.begin(); mat != cb->grid.mats.end(); ++mat)
390 {
391 Texture2D* tex = mat->tex;
392
393 if (!tex)
394 return;
395
396 int w, h;
397
398 w = tex->getStoredSize().x;
399 h = tex->getStoredSize().y;
400
401 if ((w != (int)mat->bitmapw) || (h != (int)mat->bitmaph))
402 {
403 float dx = (.999999f * (float)mat->bitmapw) / ((float)w);
404 float dy = (.999999f * (float)mat->bitmaph) / ((float)h);
405
406 int nb2 = mat->nbvertexs;
407
408 while (nb2--)
409 {
410 uvs->uv.x *= dx;
411 uvs->uv.y *= dy;
412 uvs++;
413 }
414 }
415 else
416 {
417 uvs += mat->nbvertexs;
418 }
419 }
420 }
421