1 #include "wl_def.h"
2 #include "am_map.h"
3 #include "id_sd.h"
4 #include "id_in.h"
5 #include "id_vl.h"
6 #include "id_vh.h"
7 #include "w_wad.h"
8 #include "v_font.h"
9 #include "v_palette.h"
10 #include "v_video.h"
11 #include "r_data/r_translate.h"
12 #include "textures/textures.h"
13 #include "templates.h"
14 
15 int	    pa=MENU_CENTER,px,py;
16 
17 //==========================================================================
18 
VWB_DrawPropString(FFont * font,const char * string,EColorRange translation,bool stencil,BYTE stencilcolor)19 void VWB_DrawPropString(FFont *font, const char* string, EColorRange translation, bool stencil, BYTE stencilcolor)
20 {
21 	int		    width, height;
22 	FTexture	*source;
23 	byte	    ch;
24 	int cx = px, cy = py;
25 
26 	height = font->GetHeight();
27 	FRemapTable *remap = font->GetColorTranslation(translation);
28 
29 	while ((ch = (byte)*string++)!=0)
30 	{
31 		if(ch == '\n')
32 		{
33 			cy += height;
34 			cx = px;
35 			continue;
36 		}
37 
38 		source = font->GetChar(ch, &width);
39 		if(source)
40 			VWB_DrawGraphic(source, cx, cy, (MenuOffset)pa, remap, stencil, stencilcolor);
41 		cx += width;
42 	}
43 }
44 
45 // Prints a string with word wrapping
VWB_DrawPropStringWrap(unsigned int wrapWidth,unsigned int wrapHeight,FFont * font,const char * string,EColorRange translation,bool stencil,BYTE stencilcolor)46 void VWB_DrawPropStringWrap(unsigned int wrapWidth, unsigned int wrapHeight, FFont *font, const char* string, EColorRange translation, bool stencil, BYTE stencilcolor)
47 {
48 	const char* lineStart = string;
49 	const char* lastBreak = string;
50 	unsigned int lastBreakX = 0;
51 	unsigned int cx = 0;
52 	char ch;
53 
54 	while ((ch = (byte)*string++)!=0)
55 	{
56 		if(ch == '\n')
57 		{
58 			cx = 0;
59 			continue;
60 		}
61 		else if(ch == ' ' || ch == '\t')
62 		{
63 			lastBreak = string;
64 			lastBreakX = cx;
65 		}
66 
67 		cx += font->GetCharWidth(ch);
68 		if(cx > wrapWidth)
69 		{
70 			FString part(lineStart, static_cast<int>(lastBreak-lineStart));
71 			VWB_DrawPropString(font, part, translation, stencil, stencilcolor);
72 
73 			lineStart = lastBreak;
74 			cx -= lastBreakX;
75 			lastBreakX = 0;
76 			py += font->GetHeight();
77 
78 			if((unsigned)py >= wrapHeight)
79 				break;
80 		}
81 	}
82 
83 	// Flush the rest of the string.
84 	VWB_DrawPropString(font, lineStart, translation, stencil, stencilcolor);
85 	py += font->GetHeight();
86 }
87 
VW_MeasurePropString(FFont * font,const char * string,word & width,word & height,word * finalWidth)88 void VW_MeasurePropString (FFont *font, const char *string, word &width, word &height, word *finalWidth)
89 {
90 	int w = 0;
91 
92 	height = font->GetHeight();
93 	for(width = 0;*string;++string)
94 	{
95 		if(*string == '\n')
96 		{
97 			w = 0;
98 			height += font->GetHeight();
99 			continue;
100 		}
101 
102 		w += font->GetCharWidth(*((byte *)string));
103 		if(w > width)
104 			width = w;
105 	}
106 
107 	if(finalWidth)
108 		*finalWidth = w;
109 }
110 
111 /*
112 =============================================================================
113 
114 				Double buffer management routines
115 
116 =============================================================================
117 */
118 
119 #if SDL_VERSION_ATLEAST(2,0,0)
Blit8BitSurfaceToTexture(SDL_Texture * tex,SDL_Surface * surf)120 void Blit8BitSurfaceToTexture(SDL_Texture *tex, SDL_Surface *surf)
121 {
122 	void* pixels;
123 	int pitch;
124 	if(!SDL_LockTexture(tex, NULL, &pixels, &pitch))
125 	{
126 		if(!SDL_LockSurface(surf))
127 		{
128 			const SDL_Color* colors = surf->format->palette->colors;
129 			DWORD* dest = reinterpret_cast<DWORD*>(pixels);
130 			BYTE* src = reinterpret_cast<BYTE*>(surf->pixels);
131 			for(unsigned int y = 0;y < screenHeight;++y)
132 			{
133 				for(unsigned int x = 0;x < screenWidth;++x, ++src)
134 					*dest++ = (colors[*src].r<<16)|(colors[*src].g<<8)|(colors[*src].b);
135 				src += (screenWidth-surf->pitch);
136 				dest += (screenWidth-pitch/4);
137 			}
138 			SDL_UnlockSurface(surf);
139 		}
140 		else
141 			Printf("Can't lock surface!\n");
142 		SDL_UnlockTexture(tex);
143 	}
144 	else
145 		Printf("Can't lock texture!\n");
146 }
147 #endif
148 
VH_UpdateScreen()149 void VH_UpdateScreen()
150 {
151 	screen->Update();
152 	screen->Lock(false);
153 }
154 
155 /*
156 =============================================================================
157 
158 						WOLFENSTEIN STUFF
159 
160 =============================================================================
161 */
162 
163 //==========================================================================
164 
165 /*
166 ===================
167 =
168 = FizzleFade
169 =
170 = returns true if aborted
171 =
172 = It uses maximum-length Linear Feedback Shift Registers (LFSR) counters.
173 = You can find a list of them with lengths from 3 to 168 at:
174 = http://www.xilinx.com/support/documentation/application_notes/xapp052.pdf
175 = Many thanks to Xilinx for this list!!!
176 =
177 ===================
178 */
179 
180 // XOR masks for the pseudo-random number sequence starting with n=17 bits
181 static const uint32_t rndmasks[] = {
182 					// n    XNOR from (starting at 1, not 0 as usual)
183 	0x00012000,     // 17   17,14
184 	0x00020400,     // 18   18,11
185 	0x00040023,     // 19   19,6,2,1
186 	0x00090000,     // 20   20,17
187 	0x00140000,     // 21   21,19
188 	0x00300000,     // 22   22,21
189 	0x00420000,     // 23   23,18
190 	0x00e10000,     // 24   24,23,22,17
191 	0x01200000,     // 25   25,22      (this is enough for 8191x4095)
192 };
193 
194 static unsigned int rndbits_y;
195 static unsigned int rndmask;
196 
197 // Returns the number of bits needed to represent the given value
log2_ceil(uint32_t x)198 static int log2_ceil(uint32_t x)
199 {
200 	int n = 0;
201 	uint32_t v = 1;
202 	while(v < x)
203 	{
204 		n++;
205 		v <<= 1;
206 	}
207 	return n;
208 }
209 
VH_Startup()210 void VH_Startup()
211 {
212 	int rndbits_x = log2_ceil(screenWidth);
213 	rndbits_y = log2_ceil(screenHeight);
214 
215 	int rndbits = rndbits_x + rndbits_y;
216 	if(rndbits < 17)
217 		rndbits = 17;       // no problem, just a bit slower
218 	else if(rndbits > 25)
219 		rndbits = 25;       // fizzle fade will not fill whole screen
220 
221 	rndmask = rndmasks[rndbits - 17];
222 
223 	AM_ChangeResolution();
224 }
225 
226 byte *fizzleSurface = NULL;
FizzleFadeStart()227 void FizzleFadeStart()
228 {
229 	screen->Lock(false);
230 	fizzleSurface = new byte[SCREENHEIGHT*SCREENPITCH];
231 	memcpy(fizzleSurface, screen->GetBuffer(), SCREENHEIGHT*SCREENPITCH);
232 	screen->Unlock();
233 }
FizzleFade(int x1,int y1,unsigned width,unsigned height,unsigned frames,bool abortable)234 bool FizzleFade (int x1, int y1,
235 	unsigned width, unsigned height, unsigned frames, bool abortable)
236 {
237 	unsigned x, y, frame, pixperframe;
238 	int32_t  rndval=0;
239 
240 	assert(fizzleSurface != NULL);
241 
242 	pixperframe = width * height / frames;
243 
244 	IN_StartAck ();
245 
246 	frame = GetTimeCount();
247 	screen->Lock(false);
248 	byte * const srcptr = new byte[SCREENHEIGHT*SCREENPITCH];
249 	memcpy(srcptr, screen->GetBuffer(), SCREENHEIGHT*SCREENPITCH);
250 	screen->Unlock();
251 
252 	do
253 	{
254 		IN_ProcessEvents();
255 
256 		if(abortable && IN_CheckAck ())
257 		{
258 			VH_UpdateScreen();
259 			delete[] fizzleSurface;
260 			delete[] srcptr;
261 			fizzleSurface = NULL;
262 			return true;
263 		}
264 
265 		byte *destptr = fizzleSurface;
266 
267 		if(destptr != NULL)
268 		{
269 			for(unsigned p = 0; p < pixperframe; p++)
270 			{
271 				//
272 				// seperate random value into x/y pair
273 				//
274 
275 				x = rndval >> rndbits_y;
276 				y = rndval & ((1 << rndbits_y) - 1);
277 
278 				//
279 				// advance to next random element
280 				//
281 
282 				rndval = (rndval >> 1) ^ (rndval & 1 ? 0 : rndmask);
283 
284 				if(x >= width || y >= height)
285 				{
286 					if(rndval == 0)     // entire sequence has been completed
287 						goto finished;
288 					p--;
289 					continue;
290 				}
291 
292 				//
293 				// copy one pixel
294 				//
295 				*(destptr + (y1 + y) * SCREENPITCH + x1 + x)
296 					= *(srcptr + (y1 + y) * SCREENPITCH + x1 + x);
297 
298 				if(rndval == 0)		// entire sequence has been completed
299 					goto finished;
300 			}
301 
302 			memcpy(screen->GetBuffer(), destptr, SCREENHEIGHT*SCREENPITCH);
303 			VH_UpdateScreen();
304 		}
305 		else
306 		{
307 			// No surface, so only enhance rndval
308 			for(unsigned p = 0; p < pixperframe; p++)
309 			{
310 				rndval = (rndval >> 1) ^ (rndval & 1 ? 0 : rndmask);
311 				if(rndval == 0)
312 					goto finished;
313 			}
314 		}
315 
316 		frame++;
317 		Delay(frame - GetTimeCount());        // don't go too fast
318 	} while (1);
319 
320 finished:
321 	VH_UpdateScreen();
322 	delete[] fizzleSurface;
323 	delete[] srcptr;
324 	fizzleSurface = NULL;
325 	return false;
326 }
327 
328 //==========================================================================
329 
VWB_Clear(int color,int x1,int y1,int x2,int y2)330 void VWB_Clear(int color, int x1, int y1, int x2, int y2)
331 {
332 	screen->Clear(x1, y1, x2, y2, color, GPalette.BaseColors[color]);
333 }
334 
VWB_DrawFill(FTexture * tex,int ix,int iy,int ix2,int iy2,bool local)335 void VWB_DrawFill(FTexture *tex, int ix, int iy, int ix2, int iy2, bool local)
336 {
337 	screen->FlatFill(ix, iy, ix2, iy2, tex, local);
338 }
339 
VWB_DrawGraphic(FTexture * tex,int ix,int iy,double wd,double hd,MenuOffset menu,FRemapTable * remap,bool stencil,BYTE stencilcolor)340 void VWB_DrawGraphic(FTexture *tex, int ix, int iy, double wd, double hd, MenuOffset menu, FRemapTable *remap, bool stencil, BYTE stencilcolor)
341 {
342 	double x = ix, y = iy;
343 
344 	screen->Lock(false);
345 	if(menu)
346 		MenuToRealCoords(x, y, wd, hd, menu);
347 	else
348 		screen->VirtualToRealCoords(x, y, wd, hd, 320, 200, true, true);
349 
350 	if(stencil)
351 	{
352 		screen->DrawTexture(tex, x, y,
353 			DTA_DestWidthF, wd,
354 			DTA_DestHeightF, hd,
355 			DTA_Translation, remap,
356 			DTA_FillColor, GPalette.BaseColors[stencilcolor].d,
357 			TAG_DONE);
358 	}
359 	else
360 	{
361 		screen->DrawTexture(tex, x, y,
362 			DTA_DestWidthF, wd,
363 			DTA_DestHeightF, hd,
364 			DTA_Translation, remap,
365 			TAG_DONE);
366 	}
367 	screen->Unlock();
368 }
369 
VWB_DrawGraphic(FTexture * tex,int ix,int iy,MenuOffset menu,FRemapTable * remap,bool stencil,BYTE stencilcolor)370 void VWB_DrawGraphic(FTexture *tex, int ix, int iy, MenuOffset menu, FRemapTable *remap, bool stencil, BYTE stencilcolor)
371 {
372 	if(!tex)
373 		return;
374 
375 	VWB_DrawGraphic(tex, ix, iy, tex->GetScaledWidthDouble(), tex->GetScaledHeightDouble(),
376 		menu, remap, stencil, stencilcolor);
377 }
378 
CA_CacheScreen(FTexture * tex,bool noaspect)379 void CA_CacheScreen(FTexture* tex, bool noaspect)
380 {
381 	screen->Lock(false);
382 	screen->Clear(0, 0, SCREENWIDTH, SCREENHEIGHT, GPalette.BlackIndex, 0);
383 	if(noaspect)
384 	{
385 		screen->DrawTexture(tex, 0, 0,
386 			DTA_DestWidth, SCREENWIDTH,
387 			DTA_DestHeight, SCREENHEIGHT,
388 			TAG_DONE);
389 	}
390 	else
391 	{
392 		screen->DrawTexture(tex, 0, 0,
393 			DTA_Fullscreen, true,
394 			TAG_DONE);
395 	}
396 	screen->Unlock();
397 }
398