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