1 /*
2 Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
3
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
7
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely.
11 */
12 /********************************************************************************
13 * *
14 * Test of the overlay used for moved pictures, test more closed to real life. *
15 * Running trojan moose :) Coded by Mike Gorchak. *
16 * *
17 ********************************************************************************/
18
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <string.h>
22
23 #ifdef __EMSCRIPTEN__
24 #include <emscripten/emscripten.h>
25 #endif
26
27 #include "SDL.h"
28
29 #define MOOSEPIC_W 64
30 #define MOOSEPIC_H 88
31
32 #define MOOSEFRAME_SIZE (MOOSEPIC_W * MOOSEPIC_H)
33 #define MOOSEFRAMES_COUNT 10
34
35 SDL_Color MooseColors[84] = {
36 {49, 49, 49}
37 , {66, 24, 0}
38 , {66, 33, 0}
39 , {66, 66, 66}
40 ,
41 {66, 115, 49}
42 , {74, 33, 0}
43 , {74, 41, 16}
44 , {82, 33, 8}
45 ,
46 {82, 41, 8}
47 , {82, 49, 16}
48 , {82, 82, 82}
49 , {90, 41, 8}
50 ,
51 {90, 41, 16}
52 , {90, 57, 24}
53 , {99, 49, 16}
54 , {99, 66, 24}
55 ,
56 {99, 66, 33}
57 , {99, 74, 33}
58 , {107, 57, 24}
59 , {107, 82, 41}
60 ,
61 {115, 57, 33}
62 , {115, 66, 33}
63 , {115, 66, 41}
64 , {115, 74, 0}
65 ,
66 {115, 90, 49}
67 , {115, 115, 115}
68 , {123, 82, 0}
69 , {123, 99, 57}
70 ,
71 {132, 66, 41}
72 , {132, 74, 41}
73 , {132, 90, 8}
74 , {132, 99, 33}
75 ,
76 {132, 99, 66}
77 , {132, 107, 66}
78 , {140, 74, 49}
79 , {140, 99, 16}
80 ,
81 {140, 107, 74}
82 , {140, 115, 74}
83 , {148, 107, 24}
84 , {148, 115, 82}
85 ,
86 {148, 123, 74}
87 , {148, 123, 90}
88 , {156, 115, 33}
89 , {156, 115, 90}
90 ,
91 {156, 123, 82}
92 , {156, 132, 82}
93 , {156, 132, 99}
94 , {156, 156, 156}
95 ,
96 {165, 123, 49}
97 , {165, 123, 90}
98 , {165, 132, 82}
99 , {165, 132, 90}
100 ,
101 {165, 132, 99}
102 , {165, 140, 90}
103 , {173, 132, 57}
104 , {173, 132, 99}
105 ,
106 {173, 140, 107}
107 , {173, 140, 115}
108 , {173, 148, 99}
109 , {173, 173, 173}
110 ,
111 {181, 140, 74}
112 , {181, 148, 115}
113 , {181, 148, 123}
114 , {181, 156, 107}
115 ,
116 {189, 148, 123}
117 , {189, 156, 82}
118 , {189, 156, 123}
119 , {189, 156, 132}
120 ,
121 {189, 189, 189}
122 , {198, 156, 123}
123 , {198, 165, 132}
124 , {206, 165, 99}
125 ,
126 {206, 165, 132}
127 , {206, 173, 140}
128 , {206, 206, 206}
129 , {214, 173, 115}
130 ,
131 {214, 173, 140}
132 , {222, 181, 148}
133 , {222, 189, 132}
134 , {222, 189, 156}
135 ,
136 {222, 222, 222}
137 , {231, 198, 165}
138 , {231, 231, 231}
139 , {239, 206, 173}
140 };
141
142 Uint8 MooseFrame[MOOSEFRAMES_COUNT][MOOSEFRAME_SIZE*2];
143 SDL_Texture *MooseTexture;
144 SDL_Rect displayrect;
145 int window_w;
146 int window_h;
147 SDL_Window *window;
148 SDL_Renderer *renderer;
149 int paused = 0;
150 int i;
151 SDL_bool done = SDL_FALSE;
152 Uint32 pixel_format = SDL_PIXELFORMAT_YV12;
153 int fpsdelay;
154
155 /* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
156 static void
quit(int rc)157 quit(int rc)
158 {
159 SDL_Quit();
160 exit(rc);
161 }
162
163 /* All RGB2YUV conversion code and some other parts of code has been taken from testoverlay.c */
164
165 /* NOTE: These RGB conversion functions are not intended for speed,
166 only as examples.
167 */
168
169 void
RGBtoYUV(Uint8 * rgb,int * yuv,int monochrome,int luminance)170 RGBtoYUV(Uint8 * rgb, int *yuv, int monochrome, int luminance)
171 {
172 if (monochrome) {
173 #if 1 /* these are the two formulas that I found on the FourCC site... */
174 yuv[0] = (int)(0.299 * rgb[0] + 0.587 * rgb[1] + 0.114 * rgb[2]);
175 yuv[1] = 128;
176 yuv[2] = 128;
177 #else
178 yuv[0] = (int)(0.257 * rgb[0]) + (0.504 * rgb[1]) + (0.098 * rgb[2]) + 16;
179 yuv[1] = 128;
180 yuv[2] = 128;
181 #endif
182 } else {
183 #if 1 /* these are the two formulas that I found on the FourCC site... */
184 yuv[0] = (int)(0.299 * rgb[0] + 0.587 * rgb[1] + 0.114 * rgb[2]);
185 yuv[1] = (int)((rgb[2] - yuv[0]) * 0.565 + 128);
186 yuv[2] = (int)((rgb[0] - yuv[0]) * 0.713 + 128);
187 #else
188 yuv[0] = (0.257 * rgb[0]) + (0.504 * rgb[1]) + (0.098 * rgb[2]) + 16;
189 yuv[1] = 128 - (0.148 * rgb[0]) - (0.291 * rgb[1]) + (0.439 * rgb[2]);
190 yuv[2] = 128 + (0.439 * rgb[0]) - (0.368 * rgb[1]) - (0.071 * rgb[2]);
191 #endif
192 }
193
194 if (luminance != 100) {
195 yuv[0] = yuv[0] * luminance / 100;
196 if (yuv[0] > 255)
197 yuv[0] = 255;
198 }
199 }
200
201 void
ConvertRGBtoYV12(Uint8 * rgb,Uint8 * out,int w,int h,int monochrome,int luminance)202 ConvertRGBtoYV12(Uint8 *rgb, Uint8 *out, int w, int h,
203 int monochrome, int luminance)
204 {
205 int x, y;
206 int yuv[3];
207 Uint8 *op[3];
208
209 op[0] = out;
210 op[1] = op[0] + w*h;
211 op[2] = op[1] + w*h/4;
212 for (y = 0; y < h; ++y) {
213 for (x = 0; x < w; ++x) {
214 RGBtoYUV(rgb, yuv, monochrome, luminance);
215 *(op[0]++) = yuv[0];
216 if (x % 2 == 0 && y % 2 == 0) {
217 *(op[1]++) = yuv[2];
218 *(op[2]++) = yuv[1];
219 }
220 rgb += 3;
221 }
222 }
223 }
224
225 void
ConvertRGBtoNV12(Uint8 * rgb,Uint8 * out,int w,int h,int monochrome,int luminance)226 ConvertRGBtoNV12(Uint8 *rgb, Uint8 *out, int w, int h,
227 int monochrome, int luminance)
228 {
229 int x, y;
230 int yuv[3];
231 Uint8 *op[2];
232
233 op[0] = out;
234 op[1] = op[0] + w*h;
235 for (y = 0; y < h; ++y) {
236 for (x = 0; x < w; ++x) {
237 RGBtoYUV(rgb, yuv, monochrome, luminance);
238 *(op[0]++) = yuv[0];
239 if (x % 2 == 0 && y % 2 == 0) {
240 *(op[1]++) = yuv[1];
241 *(op[1]++) = yuv[2];
242 }
243 rgb += 3;
244 }
245 }
246 }
247
248 static void
PrintUsage(char * argv0)249 PrintUsage(char *argv0)
250 {
251 SDL_Log("Usage: %s [arg] [arg] [arg] ...\n", argv0);
252 SDL_Log("\n");
253 SDL_Log("Where 'arg' is any of the following options:\n");
254 SDL_Log("\n");
255 SDL_Log(" -fps <frames per second>\n");
256 SDL_Log(" -nodelay\n");
257 SDL_Log(" -format <fmt> (one of the: YV12, IYUV, YUY2, UYVY, YVYU)\n");
258 SDL_Log(" -scale <scale factor> (initial scale of the overlay)\n");
259 SDL_Log(" -help (shows this help)\n");
260 SDL_Log("\n");
261 SDL_Log("Press ESC to exit, or SPACE to freeze the movie while application running.\n");
262 SDL_Log("\n");
263 }
264
265 void
loop()266 loop()
267 {
268 SDL_Event event;
269
270 while (SDL_PollEvent(&event)) {
271 switch (event.type) {
272 case SDL_WINDOWEVENT:
273 if (event.window.event == SDL_WINDOWEVENT_RESIZED) {
274 SDL_RenderSetViewport(renderer, NULL);
275 displayrect.w = window_w = event.window.data1;
276 displayrect.h = window_h = event.window.data2;
277 }
278 break;
279 case SDL_MOUSEBUTTONDOWN:
280 displayrect.x = event.button.x - window_w / 2;
281 displayrect.y = event.button.y - window_h / 2;
282 break;
283 case SDL_MOUSEMOTION:
284 if (event.motion.state) {
285 displayrect.x = event.motion.x - window_w / 2;
286 displayrect.y = event.motion.y - window_h / 2;
287 }
288 break;
289 case SDL_KEYDOWN:
290 if (event.key.keysym.sym == SDLK_SPACE) {
291 paused = !paused;
292 break;
293 }
294 if (event.key.keysym.sym != SDLK_ESCAPE) {
295 break;
296 }
297 case SDL_QUIT:
298 done = SDL_TRUE;
299 break;
300 }
301 }
302
303 #ifndef __EMSCRIPTEN__
304 SDL_Delay(fpsdelay);
305 #endif
306
307 if (!paused) {
308 i = (i + 1) % MOOSEFRAMES_COUNT;
309
310 SDL_UpdateTexture(MooseTexture, NULL, MooseFrame[i], MOOSEPIC_W*SDL_BYTESPERPIXEL(pixel_format));
311 }
312 SDL_RenderClear(renderer);
313 SDL_RenderCopy(renderer, MooseTexture, NULL, &displayrect);
314 SDL_RenderPresent(renderer);
315
316 #ifdef __EMSCRIPTEN__
317 if (done) {
318 emscripten_cancel_main_loop();
319 }
320 #endif
321 }
322
323 int
main(int argc,char ** argv)324 main(int argc, char **argv)
325 {
326 Uint8 *RawMooseData;
327 SDL_RWops *handle;
328 SDL_Window *window;
329 int j;
330 int fps = 12;
331 int fpsdelay;
332 int nodelay = 0;
333 #ifdef TEST_NV12
334 Uint32 pixel_format = SDL_PIXELFORMAT_NV12;
335 #else
336 Uint32 pixel_format = SDL_PIXELFORMAT_YV12;
337 #endif
338 int scale = 5;
339
340 /* Enable standard application logging */
341 SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
342
343 if (SDL_Init(SDL_INIT_VIDEO) < 0) {
344 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError());
345 return 3;
346 }
347
348 while (argc > 1) {
349 if (strcmp(argv[1], "-fps") == 0) {
350 if (argv[2]) {
351 fps = atoi(argv[2]);
352 if (fps == 0) {
353 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
354 "The -fps option requires an argument [from 1 to 1000], default is 12.\n");
355 quit(10);
356 }
357 if ((fps < 0) || (fps > 1000)) {
358 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
359 "The -fps option must be in range from 1 to 1000, default is 12.\n");
360 quit(10);
361 }
362 argv += 2;
363 argc -= 2;
364 } else {
365 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
366 "The -fps option requires an argument [from 1 to 1000], default is 12.\n");
367 quit(10);
368 }
369 } else if (strcmp(argv[1], "-nodelay") == 0) {
370 nodelay = 1;
371 argv += 1;
372 argc -= 1;
373 } else if (strcmp(argv[1], "-scale") == 0) {
374 if (argv[2]) {
375 scale = atoi(argv[2]);
376 if (scale == 0) {
377 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
378 "The -scale option requires an argument [from 1 to 50], default is 5.\n");
379 quit(10);
380 }
381 if ((scale < 0) || (scale > 50)) {
382 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
383 "The -scale option must be in range from 1 to 50, default is 5.\n");
384 quit(10);
385 }
386 argv += 2;
387 argc -= 2;
388 } else {
389 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
390 "The -fps option requires an argument [from 1 to 1000], default is 12.\n");
391 quit(10);
392 }
393 } else if ((strcmp(argv[1], "-help") == 0)
394 || (strcmp(argv[1], "-h") == 0)) {
395 PrintUsage(argv[0]);
396 quit(0);
397 } else {
398 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unrecognized option: %s.\n", argv[1]);
399 quit(10);
400 }
401 break;
402 }
403
404 RawMooseData = (Uint8 *) malloc(MOOSEFRAME_SIZE * MOOSEFRAMES_COUNT);
405 if (RawMooseData == NULL) {
406 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Can't allocate memory for movie !\n");
407 free(RawMooseData);
408 quit(1);
409 }
410
411 /* load the trojan moose images */
412 handle = SDL_RWFromFile("moose.dat", "rb");
413 if (handle == NULL) {
414 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Can't find the file moose.dat !\n");
415 free(RawMooseData);
416 quit(2);
417 }
418
419 SDL_RWread(handle, RawMooseData, MOOSEFRAME_SIZE, MOOSEFRAMES_COUNT);
420
421 SDL_RWclose(handle);
422
423 /* Create the window and renderer */
424 window_w = MOOSEPIC_W * scale;
425 window_h = MOOSEPIC_H * scale;
426 window = SDL_CreateWindow("Happy Moose",
427 SDL_WINDOWPOS_UNDEFINED,
428 SDL_WINDOWPOS_UNDEFINED,
429 window_w, window_h,
430 SDL_WINDOW_RESIZABLE);
431 if (!window) {
432 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set create window: %s\n", SDL_GetError());
433 free(RawMooseData);
434 quit(4);
435 }
436
437 renderer = SDL_CreateRenderer(window, -1, 0);
438 if (!renderer) {
439 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set create renderer: %s\n", SDL_GetError());
440 free(RawMooseData);
441 quit(4);
442 }
443
444 MooseTexture = SDL_CreateTexture(renderer, pixel_format, SDL_TEXTUREACCESS_STREAMING, MOOSEPIC_W, MOOSEPIC_H);
445 if (!MooseTexture) {
446 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set create texture: %s\n", SDL_GetError());
447 free(RawMooseData);
448 quit(5);
449 }
450 /* Uncomment this to check vertex color with a YUV texture */
451 /* SDL_SetTextureColorMod(MooseTexture, 0xff, 0x80, 0x80); */
452
453 for (i = 0; i < MOOSEFRAMES_COUNT; i++) {
454 Uint8 MooseFrameRGB[MOOSEFRAME_SIZE*3];
455 Uint8 *rgb;
456 Uint8 *frame;
457
458 rgb = MooseFrameRGB;
459 frame = RawMooseData + i * MOOSEFRAME_SIZE;
460 for (j = 0; j < MOOSEFRAME_SIZE; ++j) {
461 rgb[0] = MooseColors[frame[j]].r;
462 rgb[1] = MooseColors[frame[j]].g;
463 rgb[2] = MooseColors[frame[j]].b;
464 rgb += 3;
465 }
466 switch (pixel_format) {
467 case SDL_PIXELFORMAT_YV12:
468 ConvertRGBtoYV12(MooseFrameRGB, MooseFrame[i], MOOSEPIC_W, MOOSEPIC_H, 0, 100);
469 break;
470 case SDL_PIXELFORMAT_NV12:
471 ConvertRGBtoNV12(MooseFrameRGB, MooseFrame[i], MOOSEPIC_W, MOOSEPIC_H, 0, 100);
472 break;
473 default:
474 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unsupported pixel format\n");
475 break;
476 }
477 }
478
479 free(RawMooseData);
480
481 /* set the start frame */
482 i = 0;
483 if (nodelay) {
484 fpsdelay = 0;
485 } else {
486 fpsdelay = 1000 / fps;
487 }
488
489 displayrect.x = 0;
490 displayrect.y = 0;
491 displayrect.w = window_w;
492 displayrect.h = window_h;
493
494 /* Ignore key up events, they don't even get filtered */
495 SDL_EventState(SDL_KEYUP, SDL_IGNORE);
496
497 /* Loop, waiting for QUIT or RESIZE */
498 #ifdef __EMSCRIPTEN__
499 emscripten_set_main_loop(loop, nodelay ? 0 : fps, 1);
500 #else
501 while (!done) {
502 loop();
503 }
504 #endif
505
506 SDL_DestroyRenderer(renderer);
507 quit(0);
508 return 0;
509 }
510
511 /* vi: set ts=4 sw=4 expandtab: */
512