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