1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     Simple.cpp
4 
5   Copyright (C)2009-2012 Nintendo Co., Ltd.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law. They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Rev: 48673 $
14  *---------------------------------------------------------------------------*/
15 
16 #include <nn.h>
17 #include <nn/camera.h>
18 #include <nn/y2r.h>
19 
20 #include "demo.h"
21 #include "applet.h"
22 
23 // ======================================================================================
24 // Function Declarations
25 namespace
26 {
27     // ----------------------------------------
28     // Sample initialization, finalization and input processes
29     void Initialize(void);
30     void Finalize(void);
31     void ProcessUserInput(nn::hid::PadReader* pPadReader);
32 
33     // ----------------------------------------
34     // Functions for applet control
35     void InitializeApplet(void);
36     void FinalizeApplet(void);
37 
38     // ----------------------------------------
39     // Functions for camera thread control
40     void InitializeCameraThread(void);
41     void FinalizeCameraThread(void);
42     void PrepareTransitionCallback(void);
43     void AfterTransitionCallback(void);
44 
45     // ----------------------------------------
46     // Camera/Y2R control functions
47     void SetupCamera(void);
48     nn::Result InitializeCameraSetting(void);
49     void InitializeY2r(void);
50     void InitializeResource(void);
51     void FinalizeResource(void);
52     void CameraThreadFunc(uptr param);
53     void CameraRecvFunc(void);
54     void CameraVsyncFunc(void);
55     void StartCameraCapture(void);
56     void StopCameraCapture(void);
57     bool Y2rConversion(void);
58     void PlaySound(nn::camera::ShutterSoundType soundType);
59 
60     // ----------------------------------------
61     // Rendering Functions
62     void InitializeGx(void);
63     void FinalizeGx(void);
64     void DrawFrame(void);
65     void DrawDisplay0(void);
66     void DrawDisplay1(void);
67     void UpdateCameraTexture(void);
68     void DeleteCameraTexture(void);
69 }
70 
71 // ======================================================================================
72 // Variables for controlling Camera/Y2R
73 namespace
74 {
75     // Dynamic allocation heap
76     nn::fnd::ExpHeap s_AppHeap;
77 
78     // ----------------------------------------
79     // Image size
80     // ----------------------------------------
81     // Image to be captured by the camera
82     const nn::camera::CTR::Size CAPTURE_SIZE = nn::camera::SIZE_DS_LCDx4;
83     const s32 CAPTURE_WIDTH = 512;  // Width of DS x 2
84     const s32 CAPTURE_HEIGHT = 384; // Height of DS x 2
85     // If higher resolution has priority over wider angle of view, set to highest resolution VGA (640x480).
86     //
87     //   const nn::camera::CTR::Size CAPTURE_SIZE = nn::camera::SIZE_VGA;
88     //   const s32 CAPTURE_WIDTH = 640;  // VGA width
89     //   const s32 CAPTURE_HEIGHT = 480; // VGA height
90 
91     // An image after trimming
92     //   Must be a multiple of 8 no greater than 1024.
93     //   To simplify the specification of the size for the Y2R conversion result, here we match the horizontal width to the texture size.
94     //
95     const s32 TRIMMING_WIDTH = 512;
96     const s32 TRIMMING_HEIGHT = 240;    // CTR upper screen height
97 
98     // Image to apply as texture
99     //   For the texture size, both the width and height must be a power of 2.
100     const s32 TEXTURE_WIDTH = 512;
101     const s32 TEXTURE_HEIGHT = 256;
102 
103     // ----------------------------------------
104     // Camera/Y2R settings
105     // ----------------------------------------
106     // Port and camera that are used
107     const nn::camera::Port CAMERA_PORT = nn::camera::PORT_CAM1;                // Port 1
108     const nn::camera::CameraSelect SELECT_CAMERA = nn::camera::SELECT_OUT1;    // External camera (R)
109 
110     // When using external camera (L)
111     // const nn::camera::Port CAMERA_PORT = nn::camera::PORT_CAM2;              // Port 2
112     // const nn::camera::CameraSelect SELECT_CAMERA = nn::camera::SELECT_OUT2;  // External camera (L)
113 
114     // When using the internal camera
115     // const nn::camera::Port CAMERA_PORT = nn::camera::PORT_CAM1;              // Port 1
116     // const nn::camera::CameraSelect SELECT_CAMERA = nn::camera::SELECT_IN1;   // Internal camera
117 
118     // Alignment of the buffer for transferring after Y2R conversion
119     //   The buffer that receives the data converted by Y2R to RGB must have a physically contiguous address that is also aligned to 4 bytes.
120     //
121     //   However, when the alignment is less than 64 bytes, the transfer speed may drop.
122     const s32 ALIGNMENT_SIZE = 64;
123 
124     // Y2R input format
125     //   The image data that is input from the camera is in YUV4:2:2 format, which is a format that can be processed in batch mode.
126     //
127     const nn::y2r::InputFormat Y2R_INPUT_FORMAT = nn::y2r::INPUT_YUV422_BATCH;
128 
129     // Y2R output format
130     //   This application is set to RGB 24bit.
131     //   If you want to complete the conversion more quickly, you need to reduce the data size, so another option is set RGB 16bit (nn::y2r::OUTPUT_RGB_16_565).
132     //
133     //    If you do this, the texture type
134     //   must be changed to GL_UNSIGNED_SHORT_5_6_5.
135     const nn::y2r::OutputFormat Y2R_OUTPUT_FORMAT = nn::y2r::OUTPUT_RGB_24;
136 
137     // Output buffer array
138     //   Since we want to apply the converted image as-is as a texture, set to 8x8 block format, which is the sort order that supports DMP_NATIVE.
139     //
140     const nn::y2r::BlockAlignment Y2R_BLOCK_ALIGNMENT = nn::y2r::BLOCK_8_BY_8;
141 
142     // Index of definitions for frame rates that can be set in this sample.
143     enum FrameRateIndex
144     {
145         FRAME_RATE_INDEX_5,
146         FRAME_RATE_INDEX_10,
147         FRAME_RATE_INDEX_15,
148         FRAME_RATE_INDEX_20,
149         FRAME_RATE_INDEX_30,
150 
151         FRAME_RATE_INDEX_NUM
152     };
153 
154     // Structure related to the frame rate
155     struct FrameRateInfo
156     {
157         s32 frameRate;                      // Frame rate
158         nn::camera::FrameRate settingValue; // Enumerated type of the frame rate used for settings
159         NN_PADDING3;
160     };
161 
162     FrameRateInfo s_FrameRateInfo[FRAME_RATE_INDEX_NUM] = {
163         {  5, nn::camera::FRAME_RATE_5  },   //  5 fps
164         { 10, nn::camera::FRAME_RATE_10 },   // 10 fps
165         { 15, nn::camera::FRAME_RATE_15 },   // 15 fps
166         { 20, nn::camera::FRAME_RATE_20 },   // 20 fps
167         { 30, nn::camera::FRAME_RATE_30 }    // 30 fps
168     };
169 
170     // Index of the frame rate to be set
171     //   Use 15 fps as the default frame rate
172     int s_FrameRateIndex = FRAME_RATE_INDEX_15;
173 
174     // -------------------------------------
175     // Camera/Y2R transfer
176     // -------------------------------------
177     // Related to the buffer for transferring YUV data
178     s32 s_YuvTransferUnit;  // Transfer size for one time
179     s32 s_YuvBufferSize;    // Total size to transfer (size for one frame)
180     nn::y2r::StandardCoefficient s_Coefficient;    // The Y2R conversion coefficient applied to the data output by the camera.
181 
182     const s32 YUV_BUFFER_NUM = 3;                  // Number of buffers for transferring (triple buffer)
183     u8* s_pYuvBuffer[YUV_BUFFER_NUM] = { NULL };   // Buffer for transferring data
184 
185     // Buffer index
186     s32 s_YuvBufferIndexCapturing;      // Buffer to read the image captured by the camera
187     s32 s_YuvBufferIndexLatestCaptured; // Buffer where the read from the camera was completed
188     s32 s_YuvBufferIndexTransmitting;   // Buffer which is transferring to the Y2R circuit
189 
190     nn::os::CriticalSection s_CsYuvSwap;    // For exclusively controlling the Yuv buffer
191 
192     // Related to the buffer for transferring RGB data
193     s32 s_RgbBufferSize;            // Total size to transfer (size for one frame)
194     u8* s_pRgbBuffer = NULL;        // Buffer for transferring data
195 
196     // Counter for stabilizing auto exposure
197     //   For the first four frames immediately after the cameras are activated, the obtained images may be extremely dark.
198     //   The number of frames until auto-exposure stabilizes, together with these four frames, is around 14 frames indoors and around 30 frames outdoors.
199     //
200     //
201     s32 s_FrameCountForStabilize = 0;
202     const s32 FRAME_NUM_FOR_STABILIZE = 30;
203 
204     // Counter for frame count display
205     s32 s_FrameCountForDisplay = 1;
206 
207     // The thread that processes camera events
208     nn::os::Thread s_CameraThread;
209     // Priority of the main thread
210     s32 s_MainThreadPriority;
211 
212     // -------------------------------------
213     // Event
214     // -------------------------------------
215     // Notification of completed data transfer from the camera to the buffer
216     nn::os::Event s_CameraRecvEvent;
217 
218     // Can also be used for buffer error notification when sending data from camera to buffer, and when the main thread starts the camera thread.
219     nn::os::Event s_CameraBufferErrorEvent;
220 
221     // Notification of a camera V blank interrupt with camera capture
222     nn::os::Event s_CameraVsyncEvent;
223 
224     // Notification of completion of conversion and transfer with Y2R
225     nn::os::Event s_Y2rEndEvent;
226 
227     // Event to wait for the camera thread to enter the wait state.
228     nn::os::LightEvent s_CameraThreadSleepAckEvent;
229 
230     // Event to cancel the camera thread wait state.
231     nn::os::LightEvent s_CameraThreadAwakeEvent;
232 
233 
234     // -------------------------------------
235     // Flags
236     // -------------------------------------
237     // Flag determining whether camera initialization has completed.
238     bool s_IsCameraInitialized = false;
239 
240     // Flag to put the camera thread into the wait state.
241     bool s_IsCameraThreadSleep = false;
242 
243     // Flag used to stop the camera thread
244     bool s_IsCameraThreadEnd = false;
245 
246     // Flag when converting the frame rate
247     bool s_SwitchFrameRateFlag = false;
248 
249     // Flag indicating whether there are any images waiting for Y2R conversion.
250     bool s_ExistYuvImage = false;
251 
252     // -------------------------------------
253     // Rendering variables
254     // -------------------------------------
255     // 2D graphics demo frame work
256     demo::RenderSystemDrawing s_RenderSystem;
257 
258     // Memory size used to allocate graphics in FCRAM
259     const s32 MEMORY_SIZE_FCRAM_GX = 0x400000;
260 
261     // Address of the memory to allocate for graphics
262     void* s_AddrForGxHeap = NULL;
263 
264     // ID of texture generated from camera image.
265     GLuint s_TextureId = 0;
266 
267 } //Namespace
268 
269 // ======================================================================================
270 // Main
271 // ======================================================================================
nnMain(void)272 extern "C" void nnMain(void)
273 {
274     // Initialization
275     Initialize();
276 
277     NN_LOG("---------- Camera demo start -----------\n");
278     NN_LOG("Up   : Up frame rate\n");
279     NN_LOG("Down : Down frame rate\n");
280     NN_LOG("R    : Play shutter sound (photo)\n");
281     NN_LOG("A    : Play shutter sound (movie start)\n");
282     NN_LOG("B    : Play shutter sound (movie end)\n");
283     NN_LOG("----------------------------------------\n");
284 
285     //-----------------------------------------------------
286     // Main loop
287     nn::hid::PadReader padReader;
288     while (1)
289     {
290         if (s_ExistYuvImage)
291         {
292             s_ExistYuvImage = false;
293             // Only when a completion event for transferring from the camera is signaled
294             // Performs Y2R conversion
295             if (Y2rConversion())
296             {
297                 // Update texture if conversion was successful.
298                 UpdateCameraTexture();
299             }
300             else
301             {
302                 // Invalidate texture if conversion failed.
303                 DeleteCameraTexture();
304             }
305         }
306 
307         // Updates the LCD rendering
308         DrawFrame();
309 
310         // ----------------------------------------
311         // Applet related process
312         TransitionHandler::Process();
313 
314         if (TransitionHandler::IsExitRequired())
315         {
316             break; // Exit main loop if the application ends
317         }
318 
319         // If camera initialization has ended
320         if (s_IsCameraInitialized)
321         {
322             // Confirm input from the user
323             ProcessUserInput(&padReader);
324         }
325     } //while
326 
327     // Finalization
328     Finalize();
329 
330     NN_LOG("----------- Camera demo end ------------\n");
331     nn::applet::CloseApplication();
332 } //nnMain()
333 
334 // ====================================================================================
335 // Applet control functions
336 namespace
337 {
338     //------------------------------------------------------------
339     // Function for applet process initialization
340     //------------------------------------------------------------
InitializeApplet(void)341     void InitializeApplet(void)
342     {
343         TransitionHandler::Initialize();
344         TransitionHandler::EnableSleep();
345     } //InitializeApplet()
346 
347     //------------------------------------------------------------
348     // Function for applet process finalization
349     //------------------------------------------------------------
FinalizeApplet(void)350     void FinalizeApplet(void)
351     {
352         TransitionHandler::DisableSleep();
353         TransitionHandler::Finalize();
354     } //FinalizeApplet()
355 
356 } //Namespace
357 
358 // ====================================================================================
359 // Sample initialization, finalization and input processes
360 namespace
361 {
362     //------------------------------------------------------------
363     // Initialization
364     //------------------------------------------------------------
Initialize(void)365     void Initialize(void)
366     {
367         InitializeApplet(); // Applet process
368 
369         if (TransitionHandler::IsExitRequired())
370         {
371             // Ends application when the power button is pressed during startup
372             FinalizeApplet();
373             nn::applet::CloseApplication();
374         }
375 
376         // Heap memory
377         s_AppHeap.Initialize(
378             nn::os::GetDeviceMemoryAddress(),   // Start address
379             nn::os::GetDeviceMemorySize());    // Memory size
380 
381         InitializeGx(); // Rendering
382 
383         // Force close when HID initialization fails
384         NN_PANIC_IF_FAILED(nn::hid::Initialize()); // HID library
385 
386         // Start thread for camera processing
387         InitializeCameraThread();
388     }
389 
390     //------------------------------------------------------------
391     // Finalization
392     //------------------------------------------------------------
Finalize(void)393     void Finalize(void)
394     {
395         // Finalize thread for camera processing.
396         FinalizeCameraThread();
397 
398         nn::hid::Finalize();
399 
400         FinalizeGx();
401         FinalizeApplet();
402 
403         s_AppHeap.Finalize();
404     }
405 
406     //------------------------------------------------------------
407     // User input processing functions
408     //------------------------------------------------------------
ProcessUserInput(nn::hid::PadReader * pPadReader)409     void ProcessUserInput(nn::hid::PadReader *pPadReader)
410     {
411         nn::hid::PadStatus padStatus;
412         pPadReader->ReadLatest(&padStatus);  // Get gamepad values
413         if (padStatus.trigger & nn::hid::BUTTON_UP) // +Control Pad up
414         {
415             // Ignored if currently in conversion processing
416             if (!s_SwitchFrameRateFlag)
417             {
418                 // Increase frame rate
419                 if (s_FrameRateIndex < FRAME_RATE_INDEX_NUM - 1)
420                 {
421                     s_FrameRateIndex++;
422                     NN_LOG("Change frame rate to %2d...", s_FrameRateInfo[s_FrameRateIndex].frameRate);
423                     s_SwitchFrameRateFlag = true;
424                 }
425             }
426         }
427         else if (padStatus.trigger & nn::hid::BUTTON_DOWN) // +Control Pad down
428         {
429             // Ignored if currently in conversion processing
430             if (!s_SwitchFrameRateFlag)
431             {
432                 // Decrease frame rate
433                 if (s_FrameRateIndex > 0)
434                 {
435                     s_FrameRateIndex--;
436                     NN_LOG("Change frame rate to %2d...", s_FrameRateInfo[s_FrameRateIndex].frameRate);
437                     s_SwitchFrameRateFlag = true;
438                 }
439             }
440         }
441         else if (padStatus.trigger & nn::hid::BUTTON_R) // R Button
442         {
443             // Still image/Photo sound playback/Temporarily extinguish camera light
444             PlaySound(nn::camera::SHUTTER_SOUND_TYPE_NORMAL);
445         }
446         else if (padStatus.trigger & nn::hid::BUTTON_A) // A Button
447         {
448             // Video/Photo start sound playback/Start blinking camera light
449             PlaySound(nn::camera::SHUTTER_SOUND_TYPE_MOVIE);
450         }
451         else if (padStatus.trigger & nn::hid::BUTTON_B) // B Button
452         {
453             // Video/Photo end sound playback/End blinking camera light
454             PlaySound(nn::camera::SHUTTER_SOUND_TYPE_MOVIE_END);
455         }
456         else
457         {
458             // Because there is not input from the pad, there is no particular processing
459         }
460     } // ProcessUserInput
461 } //Namespace
462 
463 // ======================================================================================
464 // Functions for camera thread control
465 // ======================================================================================
466 namespace
467 {
468     //------------------------------------------------------------
469     // Sleep/Preparation before transition. (Called from main thread.)
470     //------------------------------------------------------------
PrepareTransitionCallback(void)471     void PrepareTransitionCallback(void)
472     {
473         // If camera thread is not finalized, transition to wait state.
474         if (!s_IsCameraThreadEnd)
475         {
476             // Notify camera thread to transition to wait state (to CameraThreadFunc).
477             s_IsCameraThreadSleep = true;
478 
479             // Signal so that the camera thread does not block with WaitAny (to CameraThreadFunc)
480             s_CameraBufferErrorEvent.Signal();
481 
482             // Wait for camera thread to transition to wait state (from CameraThreadFunc).
483             s_CameraThreadSleepAckEvent.Wait();
484         }
485     }
486 
487     //------------------------------------------------------------
488     // Sleep/Recovery after transition. (Called from main thread.)
489     //------------------------------------------------------------
AfterTransitionCallback(void)490     void AfterTransitionCallback(void)
491     {
492         // If camera thread is not finalized, cancel the wait state.
493         // If recovering in order to finalize the application, here you finalize the camera thread without canceling.
494         if (!s_IsCameraThreadEnd && !TransitionHandler::IsExitRequired())
495         {
496             // Signal to start the camera thread (to CameraThreadFunc)
497             s_CameraThreadAwakeEvent.Signal();
498         }
499     }
500 
501     //-----------------------------------------------------
502     // Start camera thread.
503     //-----------------------------------------------------
InitializeCameraThread(void)504     void InitializeCameraThread(void)
505     {
506         s_CameraThreadSleepAckEvent.Initialize(false);
507         s_CameraThreadAwakeEvent.Initialize(false);
508         s_CameraBufferErrorEvent.Initialize(false); // Use when recovering from wait state.
509         TransitionHandler::SetPrepareSleepCallback(PrepareTransitionCallback);
510         TransitionHandler::SetAfterSleepCallback(AfterTransitionCallback);
511         TransitionHandler::SetPrepareHomeButtonCallback(PrepareTransitionCallback);
512         TransitionHandler::SetAfterHomeButtonCallback(AfterTransitionCallback);
513 
514         // Remember the priority of the main thread so you can change the priority later.
515         s_MainThreadPriority = nn::os::Thread::GetCurrentPriority();
516 
517         // Create a thread for camera processing.
518         //   While initializing, the priority is set lower than the main thread.
519         //   After initialization has completed, the priority changes to be higher than the main thread.
520         s_CameraThread.StartUsingAutoStack(
521             CameraThreadFunc,
522             NULL,
523             4096,
524             s_MainThreadPriority + 3);
525     }
526 
527     //-----------------------------------------------------
528     // Finalization of camera thread
529     //-----------------------------------------------------
FinalizeCameraThread(void)530     void FinalizeCameraThread(void)
531     {
532         // Destroy the thread for camera processing
533         s_IsCameraThreadEnd = true;         // Set the end flag
534         s_CameraThreadAwakeEvent.Signal();  // Signal so that it does not stop with the sleep state
535         s_CameraBufferErrorEvent.Signal();  // Signal so that the camera thread does not stop with WaitAny
536         s_CameraThread.Join();              // Wait for thread to end
537         s_CameraThread.Finalize();          // Discard thread
538 
539         TransitionHandler::SetPrepareSleepCallback(NULL);
540         TransitionHandler::SetAfterSleepCallback(NULL);
541         TransitionHandler::SetPrepareHomeButtonCallback(NULL);
542         TransitionHandler::SetAfterHomeButtonCallback(NULL);
543         s_CameraThreadSleepAckEvent.Finalize();
544         s_CameraThreadAwakeEvent.Finalize();
545     }
546 }
547 
548 // ======================================================================================
549 // Camera/Y2R control functions
550 // ======================================================================================
551 namespace
552 {
553     //-----------------------------------------------------
554     // Camera initialization
555     //-----------------------------------------------------
SetupCamera()556     void SetupCamera()
557     {
558         // Until camera capture starts,
559         // the following functions must execute in order.
560         //   (1) nn::camera::Initialize()   Initializes the camera library
561         //   (2) nn::camera::Activate()     Starts the camera to be used
562         //   (3) nn::camera::SetReceiving() Starts transfer
563         //   (4) nn::camera::StartCapture() Starts capture
564 
565         nn::Result result;
566 
567         // Camera library initialization
568         while (true)
569         {
570             // Exit if the end flag is set.
571             if (s_IsCameraThreadEnd)
572             {
573                 return;
574             }
575 
576             result = nn::camera::Initialize();
577             if (result.IsSuccess())
578             {
579                 break;
580             }
581             else if (result == nn::camera::ResultFatalError())
582             {
583                 // Camera restart process failed
584                 NN_PANIC("Camera has broken.\n");
585             }
586             else if (result == nn::camera::ResultUsingOtherProcess())
587             {
588                 // Camera is being used by another process
589                 NN_PANIC("Camera is using by other process.\n");
590             }
591             else if (result == nn::camera::ResultAlreadyInitialized())
592             {
593                 // Because initialization was already done, no particular process is performed
594                 NN_LOG("Camera is already initialized.\n");
595                 break;
596             }
597             else if (result == nn::camera::ResultIsSleeping())
598             {
599                 // If there is a request to enter the wait state, block until end.
600                 if (s_IsCameraThreadSleep)
601                 {
602                     s_IsCameraThreadSleep = false;
603                     // Notify that the camera thread has entered the wait state (to Sleep, Home)
604                     s_CameraThreadSleepAckEvent.Signal();
605 
606                     // Wait until the thread recovery signal arrives (from Sleep, Home)
607                     s_CameraThreadAwakeEvent.Wait();
608                 }
609                 else
610                 {
611                     // Even if there is no request, block for a period of time in order to create an interval to retry.
612                     nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMilliSeconds(10));
613                 }
614                 // Retry
615                 NN_LOG("ShellClose: Retry camera initialization\n");
616             }
617         }
618 
619         // Initialize camera settings
620         while (true)
621         {
622             // Exit if the end flag is set.
623             if (s_IsCameraThreadEnd)
624             {
625                 nn::camera::Finalize();
626                 return;
627             }
628             result = InitializeCameraSetting();
629             if (result.IsSuccess())
630             {
631                 break;
632             }
633             else if (result == nn::camera::ResultFatalError())
634             {
635                 NN_PANIC("Camera has broken.\n");
636             }
637             else if (result == nn::camera::ResultIsSleeping())
638             {
639                 // If there is a request to enter the wait state, block until end.
640                 if (s_IsCameraThreadSleep)
641                 {
642                     s_IsCameraThreadSleep = false;
643                     // Notify that the camera thread has entered the wait state (to Sleep, Home)
644                     s_CameraThreadSleepAckEvent.Signal();
645 
646                     // Wait until the thread recovery signal arrives (from Sleep, Home)
647                     s_CameraThreadAwakeEvent.Wait();
648                 }
649                 else
650                 {
651                     // Even if there is no request, block for a period of time in order to create an interval to retry.
652                     nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMilliSeconds(10));
653                 }
654                 // Retry
655                 NN_LOG("ShellClose: Retry camera setting\n");
656             }
657         }
658 
659         InitializeY2r();        // Y2R library-related initialization
660         InitializeResource();   // Resource settings
661 
662         // Initialization has completed, so priority changes to become higher than the main thread.
663         nn::os::Thread::ChangeCurrentPriority(s_MainThreadPriority - 3);
664 
665         s_IsCameraInitialized = true;
666     }
667 
668     //-----------------------------------------------------
669     // Camera default setting
670     //-----------------------------------------------------
InitializeCameraSetting(void)671     nn::Result InitializeCameraSetting(void)
672     {
673         // Set the image size for the camera to capture
674         NN_UTIL_RETURN_IF_FAILED(
675             nn::camera::SetSize(
676                 SELECT_CAMERA,           // Camera that is the target for the settings
677                 CAPTURE_SIZE,            // Resolution of the camera to be set
678                 nn::camera::CONTEXT_A)); // Context where settings are reflected
679 
680         // Set trimming
681         //   If trimming is being performed, these are the various trimming-related actions.
682         //   Function calls must be made before call to StartCapture().
683         //
684         nn::camera::SetTrimming(CAMERA_PORT, true);  // Enable trimming
685 
686         // Trims the specified sized from the center of the captured image
687         nn::camera::SetTrimmingParamsCenter(
688             CAMERA_PORT,        // Port targeted for settings
689             TRIMMING_WIDTH,     // Width of the image to be trimmed
690             TRIMMING_HEIGHT,    // Height of the image to be trimmed
691             CAPTURE_WIDTH,      // Width of the camera resolution
692             CAPTURE_HEIGHT);    // Height of the camera resolution
693 
694         // Set number of bytes to transfer
695         //   A number of bytes is set in this demo, but if a number of lines is to be set for the number of bytes to transfer, you can get the maximum number of bytes to send using nn::camera::GetMaxLines() , and then use nn::camera::SetTransferLines() to set the value.
696         //
697         //   However, there are conditions for the number of bytes being sent, so read the details in section "6.4.3 Capture Settings" in the Programming Manual System.
698         //
699         //
700         s_YuvTransferUnit = nn::camera::GetMaxBytes(
701             TRIMMING_WIDTH,     // Width of the image to transfer (width after trimming when trimmed)
702             TRIMMING_HEIGHT);   // Height of the image to transfer (height after trimming when trimmed)
703         nn::camera::SetTransferBytes(
704             CAMERA_PORT,        // Targeted port
705             s_YuvTransferUnit,  // Number of bytes to transfer
706             TRIMMING_WIDTH,     // Width of the image to transfer (width after trimming when trimmed)
707             TRIMMING_HEIGHT);   // Height of the image to transfer (height after trimming when trimmed)
708 
709         // Get the Y2R conversion coefficient suited to the data output by the camera.
710         //   This value is used when initializing Y2R.
711         //   It is unnecessary if you are not using Y2R.
712         NN_UTIL_RETURN_IF_FAILED(nn::camera::GetSuitableY2rStandardCoefficient(&s_Coefficient));
713 
714         // The three settings below (noise elimination, auto exposure and auto white balance) all are 'true' by default for all cameras, but explicitly perform the configuration.
715         //
716 
717         // Noise filter
718         NN_UTIL_RETURN_IF_FAILED(nn::camera::SetNoiseFilter(SELECT_CAMERA, true));        // Enabled
719 
720         // Auto exposure feature
721         NN_UTIL_RETURN_IF_FAILED(nn::camera::SetAutoExposure(SELECT_CAMERA, true));       // Enabled
722 
723         // White balance auto adjustment feature
724         NN_UTIL_RETURN_IF_FAILED(nn::camera::SetAutoWhiteBalance(SELECT_CAMERA, true));   // Enabled
725 
726         // Start camera
727         //   After the camera module has been started by this function you can begin image capture by calling the StartCapture function.
728         //
729         NN_UTIL_RETURN_IF_FAILED(nn::camera::Activate(SELECT_CAMERA));
730 
731         return nn::ResultSuccess();
732     }  //SetupCamera()
733 
734     //------------------------------------------------------------
735     // Initial settings for the Y2R library
736     //------------------------------------------------------------
InitializeY2r(void)737     void InitializeY2r(void)
738     {
739         // Initialization of the Y2R library
740         if (!nn::y2r::Initialize())
741         {
742             NN_PANIC("Y2R is using by other process.\n");
743         }
744 
745         // Stop the library explicitly because it cannot be configured during a conversion.
746         nn::y2r::StopConversion();
747         while (nn::y2r::IsBusyConversion())
748         {
749             // Wait until conversion ends
750             nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMicroSeconds(100));
751         }
752 
753         // Event initialization
754         s_Y2rEndEvent.Initialize(false);
755 
756         // Input format settings
757         nn::y2r::SetInputFormat(Y2R_INPUT_FORMAT);
758 
759         // Output format settings
760         nn::y2r::SetOutputFormat(Y2R_OUTPUT_FORMAT);
761 
762         // Set angle of rotation for output data
763         nn::y2r::SetRotation(nn::y2r::ROTATION_NONE);   // No rotation
764 
765         // Set alpha value for output data
766         //   Since alpha is not used with RGB 24bit, initialize explicitly.
767         nn::y2r::SetAlpha(0xFF);
768 
769         // Set the order of the output buffer data
770         nn::y2r::SetBlockAlignment(Y2R_BLOCK_ALIGNMENT);
771 
772         // Set whether we will receive a notification when the Y2R conversion/transfer is complete.
773         nn::y2r::SetTransferEndInterrupt(true);
774         nn::y2r::GetTransferEndEvent(&s_Y2rEndEvent);
775 
776         // Set width of 1 line of input data
777         nn::y2r::SetInputLineWidth(TRIMMING_WIDTH);
778 
779         // Set number of vertical lines of input data
780         nn::y2r::SetInputLines(TRIMMING_HEIGHT);
781 
782         // Set standard conversion coefficients
783         //   The camera module installed on the CTR system may change in the future.
784         //For this reason, instead of specifying a specific conversion coefficient, we recommend using the GetSuitableY2rStandardCoefficient function to get the conversion coefficient that matches the camera, and using this to set the value.
785         //
786         //
787         nn::y2r::SetStandardCoefficient(s_Coefficient);
788     }  //InitializeY2r()
789 
790     //------------------------------------------------------------
791     // Allocate the necessary resources for camera and Y2R processing
792     //------------------------------------------------------------
InitializeResource(void)793     void InitializeResource(void)
794     {
795         // Initialize the critical session
796         s_CsYuvSwap.Initialize();
797 
798         // Initialize the event to acquire from the camera library
799         s_CameraRecvEvent.Initialize(false);
800         s_CameraVsyncEvent.Initialize(false);
801 
802         // Event for buffer error notification
803         //   When camera data transfer fails (when FIFO overflowed)
804         //   A buffer error notification is made.
805         nn::camera::GetBufferErrorInterruptEvent(&s_CameraBufferErrorEvent, CAMERA_PORT);
806 
807         // Event for camera V blank notification
808         //   During V-blanks, frame rates are calculated and camera settings are changed.
809         //
810         nn::camera::GetVsyncInterruptEvent(&s_CameraVsyncEvent, CAMERA_PORT);
811 
812         // Allocate a buffer for transferring camera image data (YUV data).
813         s_YuvBufferSize = nn::camera::GetFrameBytes(TRIMMING_WIDTH, TRIMMING_HEIGHT);
814         for (s32 i = 0; i < YUV_BUFFER_NUM; i++)
815         {
816             NN_ASSERT(!s_pYuvBuffer[i]);
817             s_pYuvBuffer[i] = static_cast<u8*>(s_AppHeap.Allocate(s_YuvBufferSize, ALIGNMENT_SIZE));
818             std::memset(s_pYuvBuffer[i], 0, s_YuvBufferSize);
819         }
820         s_YuvBufferIndexCapturing = 0;
821         s_YuvBufferIndexLatestCaptured = YUV_BUFFER_NUM - 1;
822         s_YuvBufferIndexTransmitting = YUV_BUFFER_NUM - 1;
823 
824         // Allocate a buffer for transferring the camera image Y2R conversion result (RGB data).
825         s_RgbBufferSize = nn::y2r::GetOutputImageSize(TEXTURE_WIDTH, TEXTURE_HEIGHT,
826             Y2R_OUTPUT_FORMAT);
827         NN_ASSERT(!s_pRgbBuffer);
828         s_pRgbBuffer = static_cast<u8*>(s_AppHeap.Allocate(s_RgbBufferSize, ALIGNMENT_SIZE));
829         std::memset(s_pRgbBuffer, 0, s_RgbBufferSize);
830     } //InitializeResource()
831 
832     //------------------------------------------------------------
833     // Free the necessary resources for camera and Y2R processing
834     //------------------------------------------------------------
FinalizeResource(void)835     void FinalizeResource(void)
836     {
837         // Free heap.
838         for (s32 i = 0; i < YUV_BUFFER_NUM; i++)
839         {
840             NN_ASSERT(s_pYuvBuffer[i]);
841             s_AppHeap.Free(s_pYuvBuffer[i]);
842             s_pYuvBuffer[i] = NULL;
843         }
844         NN_ASSERT(s_pRgbBuffer);
845         s_AppHeap.Free(s_pRgbBuffer);
846         s_pRgbBuffer = NULL;
847 
848         // Destroys events obtained from the camera library.
849         s_CameraRecvEvent.Finalize();
850         s_CameraBufferErrorEvent.Finalize();
851         s_CameraVsyncEvent.Finalize();
852 
853         // Destroys the critical section
854         s_CsYuvSwap.Finalize();
855     }  //FinalizeResource()
856 
857 
858 
859     //------------------------------------------------------------
860     // The thread that processes camera events
861     //------------------------------------------------------------
CameraThreadFunc(uptr param NN_IS_UNUSED_VAR)862     void CameraThreadFunc(uptr param NN_IS_UNUSED_VAR)
863     {
864         // Camera initialization
865         SetupCamera();
866 
867         // Exit if a request to finalize the thread comes during camera initialization.
868         if (s_IsCameraThreadEnd)
869         {
870             return;
871         }
872 
873         // Start camera for firs time and capture settings
874         StartCameraCapture();
875 
876         // ----------------------------------------
877         // Processing by event
878         enum
879         {
880             EVENT_RECV,     // Transfer from the camera is complete
881             EVENT_ERROR,    // Restart due to buffer error or malfunction
882             EVENT_VSYNC,    // V-Blank interrupt
883 
884             EVENT_MAX
885         };
886         nn::os::WaitObject* pEvent[EVENT_MAX];
887 
888         // Register each event
889         pEvent[EVENT_RECV] = &s_CameraRecvEvent;
890         pEvent[EVENT_ERROR] = &s_CameraBufferErrorEvent;
891         pEvent[EVENT_VSYNC] = &s_CameraVsyncEvent;
892 
893         while (1)
894         {
895             // Standby for one of the events registered above
896             //   The call to SetReceiving() clears the event notifying the completion of transfer, so only one of the events for reconfiguring the transfer settings can be executed at a time.
897             //
898             //
899             if (s_IsCameraThreadEnd)
900             {
901                 NN_LOG("before WaitAny\n");
902             }
903             s32 eventType = nn::os::WaitObject::WaitAny(pEvent, EVENT_MAX);
904             if (s_IsCameraThreadEnd)
905             {
906                 NN_LOG("after WaitAny\n");
907             }
908 
909             // ----------------------------------------
910             // End the thread
911             if (s_IsCameraThreadEnd)
912             {
913                 StopCameraCapture();
914                 break;
915             }
916             // ----------------------------------------
917             // Thread waits
918             if (s_IsCameraThreadSleep)
919             {
920                 s_IsCameraThreadSleep = false;
921 
922                 // Stop camera capture
923                 StopCameraCapture();
924 
925                 // Notify that the camera thread has entered the sleep wait state (to Sleep, Home)
926                 s_CameraThreadSleepAckEvent.Signal();
927 
928                 // Standby until the thread sleep recovery signal arrives (from Sleep, Home)
929                 NN_LOG("-Sleep camera thread.\n");
930                 s_CameraThreadAwakeEvent.Wait();
931                 NN_LOG("-Awake camera thread.\n");
932 
933                 // ----------------------------------------
934                 // Process after sleep recovery
935                 // Cleared once because a Vsync event may have been signaled
936                 s_CameraVsyncEvent.ClearSignal();
937 
938                 // Reset the counter for waiting for auto exposure stabilization
939                 s_FrameCountForStabilize = 0;
940 
941                 // Use the buffer error mechanism to resume capture.
942                 s_CameraBufferErrorEvent.Signal();
943                 continue;
944             }
945 
946             switch (eventType)
947             {
948             case EVENT_RECV:
949                 // Complete transfer from camera
950                 {
951                     // Set transfer for the next frame's portion
952                     CameraRecvFunc();
953 
954                     // Request Y2R conversion execution
955                     s_ExistYuvImage = true;
956                 }
957                 break;
958 
959             case EVENT_ERROR:
960                 // Restart due to buffer error, malfunction. Restart after sleep/transition.
961                 {
962                     // Capture stops when there is an error, so reconfigure the transfer settings and resume capture operations.
963                     //
964                     StartCameraCapture();
965                 }
966                 break;
967 
968             case EVENT_VSYNC:
969                 // V-Blank interrupt
970                 {
971                     //   Regardless of the frame rate, change the camera settings when nothing is being transferred and a V-blank interrupt is generated.
972                     //
973                     CameraVsyncFunc();
974                 }
975                 break;
976 
977             default:
978                 {
979                     NN_LOG("Illegal event\n");
980                 }
981                 break;
982             } //Switch
983 
984         } //while
985 
986         {
987             // Finalization of CAMERA/Y2R
988             //   If you do not perform finalization with the following procedure, there is a possibility that sound noise will be generated in the HOME Menu.
989             //
990             nn::y2r::StopConversion();                      // (1) Stop Y2R conversion
991             nn::camera::StopCapture(CAMERA_PORT);           // (2) Stop capture
992             nn::camera::Activate(nn::camera::SELECT_NONE);  // (3) Set all cameras to standby state
993             nn::camera::Finalize();                         // (4) End camera
994             nn::y2r::Finalize();                            //     End Y2R
995         }
996         {
997             // Free the resources used for CAMERA/Y2R
998             FinalizeResource();
999         }
1000     } //CameraThreadFunc()
1001 
1002     //------------------------------------------------------------
1003     // Main data transfer processing
1004     //------------------------------------------------------------
CameraRecvFunc(void)1005     void CameraRecvFunc(void)
1006     {
1007         {
1008             // Switch the write buffer
1009             //   Block so that this does not overlap with the process of switching the read buffer (Y2rConversion).
1010             //
1011             nn::os::CriticalSection::ScopedLock sl(s_CsYuvSwap);
1012             s_YuvBufferIndexLatestCaptured = s_YuvBufferIndexCapturing;
1013             do
1014             {
1015                 // Switch the ring buffer index
1016                 if ((++s_YuvBufferIndexCapturing) >= YUV_BUFFER_NUM)
1017                 {
1018                     s_YuvBufferIndexCapturing = 0;
1019                 }
1020             } while (s_YuvBufferIndexCapturing == s_YuvBufferIndexTransmitting);
1021         }
1022 
1023         // Set next frame transfer
1024         nn::camera::SetReceiving(
1025             &s_CameraRecvEvent,                         // Event signaled when transfer completes
1026             s_pYuvBuffer[s_YuvBufferIndexCapturing],    // Transfer destination of the loaded image data
1027             CAMERA_PORT,                                // Target port for loading
1028             s_YuvBufferSize,                            // Size of one frame's portion (size that for transfer completion)
1029             s_YuvTransferUnit);                         // Size to be transferred at one time
1030     } //CameraRecvFunc()
1031 
CameraVsyncFunc(void)1032     void CameraVsyncFunc(void)
1033     {
1034         if (s_FrameCountForStabilize < FRAME_NUM_FOR_STABILIZE)
1035         {
1036             // Counter for waiting for auto exposure stabilization
1037             s_FrameCountForStabilize++;
1038         }
1039         s_FrameCountForDisplay++;   // Increase frame count for display
1040 
1041         // Change frame rate
1042         if (s_SwitchFrameRateFlag)
1043         {
1044             // Stop camera capture
1045             //   Capture operations must be stopped before camera settings are changed.
1046             StopCameraCapture();
1047 
1048             // Change frame rate
1049             nn::Result result = nn::camera::SetFrameRate(
1050                 SELECT_CAMERA,
1051                 s_FrameRateInfo[s_FrameRateIndex].settingValue);
1052             if (result.IsSuccess())
1053             {
1054                 // Disable frame rate change flag
1055                 s_SwitchFrameRateFlag = false;
1056                 NN_LOG("Success!\n");
1057             }
1058             else if (result == nn::camera::ResultFatalError())
1059             {
1060                 NN_DBG_PRINT_RESULT(result);
1061                 NN_PANIC("Error:Camera has broken.\n");
1062             }
1063             else
1064             {
1065                 // If there is some other error, don't do anything in particular and try again when the next V-blank event occurs.
1066                 //
1067                 NN_LOG("Retry to change frame rate.\n");
1068             }
1069             // Start camera capture
1070             StartCameraCapture();
1071         } // if (s_SwitchFrameRateFlag)
1072     }
1073 
1074     //------------------------------------------------------------
1075     // Start camera capture
1076     //------------------------------------------------------------
StartCameraCapture(void)1077     void StartCameraCapture(void)
1078     {
1079         // Clears the buffer, error flag
1080         nn::camera::ClearBuffer(CAMERA_PORT);
1081 
1082         // Data transfer process
1083         CameraRecvFunc();
1084 
1085         // Start capture
1086         nn::camera::StartCapture(CAMERA_PORT);
1087 
1088     } // StartCameraCapture()
1089 
1090     //------------------------------------------------------------
1091     // Stop camera capture
1092     //------------------------------------------------------------
StopCameraCapture(void)1093     void StopCameraCapture(void)
1094     {
1095         // Stop capture
1096         nn::camera::StopCapture(CAMERA_PORT);
1097 
1098         // Calculate the time (milliseconds) for one frame from the set frame rate
1099         s32 timeout = 1000 / s_FrameRateInfo[s_FrameRateIndex].frameRate;
1100         s32 cnt = 0;
1101         while (nn::camera::IsBusy(CAMERA_PORT))
1102         {
1103             // Depending on the timing when the system is closed, IsBusy() might be in a
1104             // state where it is always 'true.' For that reason, transition to sleep.
1105             // If this state takes place in the implementation, you will not be able to
1106             // exit the loop and transition to sleep.
1107             // Here, a timeout is used to avoid an infinite loop.
1108             // Normally, IsBusy is 'true' for at most 1 frame, so set the timeout time somewhat large at 1 frame.
1109             //
1110             nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMilliSeconds(1));
1111             if (++cnt > timeout)
1112             {
1113                 NN_LOG("Busy timeout\n");
1114                 break;
1115             }
1116         }
1117         // Clears the buffer, error flag
1118         nn::camera::ClearBuffer(CAMERA_PORT);
1119     } // StopCameraCapture()
1120 
1121     //------------------------------------------------------------
1122     // Transfer and convert to Y2R
1123     //------------------------------------------------------------
Y2rConversion(void)1124     bool Y2rConversion(void)
1125     {
1126         // *** BEGIN WARNING ***
1127         // Due to a hardware bug, when the camera and Y2R are being used at the same time, there is a possibility that the recovery from a camera buffer error could cause Y2R transfers to hang, depending on the timing of that recovery.
1128         //
1129         //
1130         // In this case, the conversion completion event obtained by nn::y2r::GetTransferEndEvent might never be signaled.
1131         //
1132         // For details on when this problem occurs and how to deal with it, see the Function Reference Manual for the Y2R library.
1133         //
1134         // In this sample, a timeout is inserted in the wait for the above event, and when a timeout occurs, a retry is performed.
1135         //
1136         // *** END WARNING ***
1137 
1138         {
1139             // Switch the camera read buffer.
1140             //   Block so that this does not overlap with the process of switching the write buffer (CameraRecvFunc).
1141             nn::os::CriticalSection::ScopedLock sl(s_CsYuvSwap);
1142 
1143             // Set the buffer that has completed acquisition from the camera as the conversion target
1144             s_YuvBufferIndexTransmitting = s_YuvBufferIndexLatestCaptured;
1145         }
1146 
1147         // Offset so that the trimmed image is applied in the center of the texture
1148         s32 rgbBufferOffset;
1149         s32 centeringImageHeight = (TEXTURE_HEIGHT - TRIMMING_HEIGHT) / 2;
1150         rgbBufferOffset = nn::y2r::GetOutputImageSize(TEXTURE_WIDTH, centeringImageHeight,
1151             Y2R_OUTPUT_FORMAT);
1152 
1153         s32 cnt = 0;
1154         while (true)
1155         {
1156             // Transfer settings for the Y2R input image (YUV)
1157             //   Writes YUV data to Y2R. Transfers are measured in lines of data.
1158             nn::y2r::SetSendingYuv(
1159                 s_pYuvBuffer[s_YuvBufferIndexTransmitting], // Transfer data
1160                 s_YuvBufferSize,                            // Total transfer size
1161                 nn::camera::GetLineBytes(TRIMMING_WIDTH));  // Transfer size for one time (1 line)
1162 
1163             // Transfer setting for the output image (RGB) from Y2R
1164             //   Load RGB data from Y2R. For the per-time transfer size, in order to boost performance we recommend specifying a size of 8 lines' worth.
1165             //
1166             s16 yuvTransferUnit = TRIMMING_WIDTH * 8 * GetOutputFormatBytes(Y2R_OUTPUT_FORMAT);
1167             nn::y2r::SetReceiving(
1168                 s_pRgbBuffer + rgbBufferOffset, // Load destination for the converted RGB data
1169                 s_RgbBufferSize,                // Total transfer size
1170                 yuvTransferUnit);               // The size of a single transfer.
1171 
1172             // Start Y2R conversion
1173             nn::y2r::StartConversion();
1174 
1175             // Standby for notification of Y2R conversion completion event
1176             //   Waits for Y2R conversion completion because data transfer is aborted if the transfer for the next conversion is performed before conversion of the first image has completed.
1177             //
1178             //   To deal with a bug that causes Y2R to hang, a timeout is inserted that is longer than the time for the conversion to complete.
1179             //
1180             //   See the y2r function reference for the approximate time it takes for conversion.
1181             if (s_Y2rEndEvent.Wait(nn::fnd::TimeSpan::FromMilliSeconds(10)))
1182             {
1183                 // Conversion succeeded
1184                 return true;
1185             }
1186             else
1187             {
1188                 // Conversion failed
1189 
1190                 NN_LOG("Y2R may have hung up.\n");
1191 
1192                 nn::y2r::StopConversion();  // Force conversion to end
1193 
1194                 // Although it is very rare for problems to occur over and over, a process is inserted to explicitly exit the loop.
1195                 //
1196                 if (++cnt >= 2)
1197                 {
1198                     // Destroy the conversion at this time
1199                     return false;
1200                 }
1201                 // Timed out, so retry.
1202             }
1203         } //while(true)
1204     } //Y2rConversion()
1205 
1206     //------------------------------------------------------------
1207     // Control of the camera operation sound playback and the camera light
1208     //------------------------------------------------------------
PlaySound(nn::camera::ShutterSoundType soundType)1209     void PlaySound(nn::camera::ShutterSoundType soundType)
1210     {
1211         nn::Result result = nn::camera::PlayShutterSound(soundType);
1212         if (result.IsSuccess())
1213         {
1214             switch (soundType)
1215             {
1216             case nn::camera::SHUTTER_SOUND_TYPE_NORMAL:
1217                 {
1218                     NN_LOG("Play shutter sound.\n");
1219                 }
1220                 break;
1221 
1222             case nn::camera::SHUTTER_SOUND_TYPE_MOVIE:
1223                 {
1224                     NN_LOG("Play movie start sound.\n");
1225                 }
1226                 break;
1227 
1228             case nn::camera::SHUTTER_SOUND_TYPE_MOVIE_END:
1229                 {
1230                     NN_LOG("Play movie end sound.\n");
1231                 }
1232                 break;
1233 
1234             default:
1235                 break;
1236             }
1237         }
1238         else if (result == nn::camera::CTR::ResultFatalError())
1239         {
1240             NN_PANIC("Camera has broken.\n");
1241         }
1242         else if (result == nn::camera::CTR::ResultIsSleeping())
1243         {
1244             // Because this is called from a thread the returns ACCEPT to a sleep request, this error does not actually get returned here.
1245             //
1246         }
1247         else
1248         {
1249             // Unexpected errors
1250             NN_DBG_PRINT_RESULT(result);
1251             NN_PANIC("Unknown error.\n");
1252         }
1253     } // PlaySound
1254 } //Namespace
1255 
1256 // ====================================================================================
1257 // Rendering Functions
1258 namespace
1259 {
1260     //------------------------------------------------------------
1261     // Rendering initialization function
1262     //------------------------------------------------------------
InitializeGx(void)1263     void InitializeGx(void)
1264     {
1265         NN_ASSERT(!s_AddrForGxHeap);
1266         s_AddrForGxHeap = s_AppHeap.Allocate(MEMORY_SIZE_FCRAM_GX);
1267         s_RenderSystem.Initialize(reinterpret_cast<uptr>(s_AddrForGxHeap), MEMORY_SIZE_FCRAM_GX);
1268     } // InitializeGx()
1269 
1270     //------------------------------------------------------------
1271     // Rendering end function
1272     //------------------------------------------------------------
FinalizeGx(void)1273     void FinalizeGx(void)
1274     {
1275         s_RenderSystem.Finalize();
1276         NN_ASSERT(s_AddrForGxHeap);
1277         s_AppHeap.Free(s_AddrForGxHeap);
1278         s_AddrForGxHeap = NULL;
1279     } // FinalizeGx()
1280 
1281     //------------------------------------------------------------
1282     // Function to render the upper and lower screens
1283     //------------------------------------------------------------
DrawFrame(void)1284     void DrawFrame(void)
1285     {
1286         // Update the upper screen
1287         DrawDisplay0();
1288 
1289         // Update the lower screen
1290         DrawDisplay1();
1291 
1292         s_RenderSystem.WaitVsync(NN_GX_DISPLAY_BOTH);
1293     } // DrawFrame
1294 
1295     //------------------------------------------------------------
1296     // Update the render content for the upper screen
1297     //------------------------------------------------------------
DrawDisplay0(void)1298     void DrawDisplay0(void)
1299     {
1300         // Made the upper screen the render target
1301         s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0);
1302 
1303         // Make the background black
1304         s_RenderSystem.SetClearColor(NN_GX_DISPLAY0, 0.0f, 0.0f, 0.0f, 0.0f);
1305         // Clear the previous rendering
1306         s_RenderSystem.Clear();
1307 
1308         // Render if there is a camera image texture.
1309         if (s_TextureId != 0)
1310         {
1311             // ----------------------------------------
1312             // Render the camera image texture
1313             f32 windowCoordinateX = (nn::gx::DISPLAY0_HEIGHT - TEXTURE_WIDTH) / 2.0f;
1314             f32 windowCoordinateY = (nn::gx::DISPLAY0_WIDTH - TEXTURE_HEIGHT) / 2.0f;
1315 
1316             s_RenderSystem.FillTexturedRectangle(
1317                 s_TextureId,                              // Texture ID
1318                 windowCoordinateX, windowCoordinateY,   // Coordinate (x,y) of the upper left vertex of a rectangle in the window coordinate system
1319                 TEXTURE_WIDTH, TEXTURE_HEIGHT,          // Length (x,y) of the rectangle side in the window coordinate system
1320                 TEXTURE_WIDTH, TEXTURE_HEIGHT,          // Image size (x,y)
1321                 TEXTURE_WIDTH, TEXTURE_HEIGHT);         // Texture size (x,y)
1322         }
1323 
1324         const char* pMessage = NULL;
1325         u32 numOfChar = 0;
1326 
1327         if (!s_IsCameraInitialized)
1328         {
1329             // Display message until camera initialization has completed.
1330             const char message[] = "Initializing camera.";
1331             pMessage = message;
1332             numOfChar = sizeof(message) / sizeof(message[0]);
1333         }
1334         else if (s_FrameCountForStabilize < FRAME_NUM_FOR_STABILIZE)
1335         {
1336             // Display message until the camera auto exposure stabilizes
1337             const char message[] = "Stabilizing auto exposure.";
1338             pMessage = message;
1339             numOfChar = sizeof(message) / sizeof(message[0]);
1340         }
1341 
1342         // Display if there is a message to display.
1343         if (pMessage)
1344         {
1345             f32 fontSize = 8.0f;
1346             f32 textX = (nn::gx::DISPLAY0_HEIGHT - (fontSize * numOfChar)) / 2.0f;
1347             f32 textY = nn::gx::DISPLAY0_WIDTH / 2.0f;
1348             s_RenderSystem.SetFontSize(fontSize);
1349 
1350             s_RenderSystem.SetColor(1.0f, 0.0f, 0.0f);  // Set character body color to red
1351             for (s32 i = -1; i <= 1; i++)
1352             {
1353                 for (s32 j = -1; j <= 1; j++)
1354                 {
1355                     if (!((i == 0) && (j == 0)))
1356                     {
1357                         s_RenderSystem.DrawText(textX + i, textY + j, pMessage);
1358                     }
1359                 }
1360             }
1361 
1362             s_RenderSystem.SetColor(1.0f, 1.0f, 1.0f);  // Set font color to white
1363             s_RenderSystem.DrawText(textX, textY, pMessage);
1364         }
1365 
1366         s_RenderSystem.SwapBuffers();
1367     } // DrawDisplay0
1368 
1369     //------------------------------------------------------------
1370     // Update render content for lower screen
1371     //------------------------------------------------------------
DrawDisplay1(void)1372     void DrawDisplay1(void)
1373     {
1374         // Made the upper screen the render target
1375         s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY1);
1376 
1377         // Make the background black
1378         s_RenderSystem.SetClearColor(NN_GX_DISPLAY1, 0.0f, 0.0f, 0.0f, 0.0f);
1379         // Clear the previous rendering
1380         s_RenderSystem.Clear();
1381         // Set font color to white
1382         s_RenderSystem.SetColor(1.0f, 1.0f, 1.0f);
1383 
1384         // ----------------------------------------
1385         // Display all information
1386         f32 fontSize = 8.0f;
1387         f32 margin = fontSize / 2;
1388         f32 textY = margin;
1389         f32 textX = margin;
1390         s_RenderSystem.SetFontSize(fontSize);
1391 
1392         // Count of the number of frames
1393         s_RenderSystem.DrawText(textX, textY, "Counts: %d", s_FrameCountForDisplay);
1394 
1395         // Render the set frame rate
1396         textX = nn::gx::DISPLAY1_HEIGHT - margin - (fontSize * 6); // 6 character's worth
1397         s_RenderSystem.DrawText(textX, textY, "%2d fps",
1398             s_FrameRateInfo[s_FrameRateIndex].frameRate);
1399 
1400         // Using the Demo
1401         textX = margin;
1402         textY = nn::gx::DISPLAY1_WIDTH - (fontSize + margin);
1403         s_RenderSystem.DrawText(textX, textY, "B    : Play shutter sound (Movie end)");
1404         textY -= fontSize;
1405         s_RenderSystem.DrawText(textX, textY, "A    : Play shutter sound (Movie start)");
1406         textY -= fontSize;
1407         s_RenderSystem.DrawText(textX, textY, "R    : Play shutter sound (Photo)");
1408         textY -= 2 * fontSize;
1409         s_RenderSystem.DrawText(textX, textY, "Down : Down frame rate");
1410         textY -= fontSize;
1411         s_RenderSystem.DrawText(textX, textY, "Up   : Up frame rate");
1412 
1413         s_RenderSystem.SwapBuffers();
1414     } // DrawDisplay1()
1415 
UpdateCameraTexture(void)1416     void UpdateCameraTexture(void)
1417     {
1418         // ----------------------------------------
1419         // Create texture from the camera image
1420 
1421         // Destroy old texture.
1422         DeleteCameraTexture();
1423 
1424         // Texture target settings
1425         GLenum textureTarget = GL_TEXTURE_2D | NN_GX_MEM_FCRAM | GL_NO_COPY_FCRAM_DMP;
1426 
1427         // Texture format/type settings
1428         //   There are restrictions on the texture format and type combinations.
1429         //   Also, the internal format of the texture must be the same as the texture format.
1430         //   For details, see the section on textures in the Programming Manual: Basic Graphics.
1431         //
1432         GLenum textureFormat = GL_RGB_NATIVE_DMP;       // Format
1433         GLenum textureInternalFormat = textureFormat;   // Internal format
1434 
1435         // If the Y2R output format is OUTPUT_RGB_16_565, then the texture type must be GL_UNSIGNED_SHORT_5_6_5.
1436         //
1437         GLenum textureType = GL_UNSIGNED_BYTE;          // Type
1438 
1439         // Create the texture
1440         s_RenderSystem.GenerateTexture(
1441             textureTarget,          // Texture target
1442             textureInternalFormat,  // Internal format of the texture
1443             TEXTURE_WIDTH,          // Texture width
1444             TEXTURE_HEIGHT,         // Texture height
1445             textureFormat,          // Texture format
1446             textureType,            // Texture type
1447             s_pRgbBuffer,           // The pointer to the texture data
1448             s_TextureId);             // Texture object
1449     }
1450 
DeleteCameraTexture(void)1451     void DeleteCameraTexture(void)
1452     {
1453         if (s_TextureId != 0)
1454         {
1455             if (s_RenderSystem.DeleteTexture(s_TextureId))
1456             {
1457                 s_TextureId = 0;
1458             }
1459             else
1460             {
1461                 NN_PANIC("  Failed to delete texture. (id = %d)\n", s_TextureId);
1462             }
1463         }
1464     }
1465 } // Namespace
1466