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