├── cmake ├── bin2s_header.h.in ├── FindCTRULIB.cmake ├── FindFFMPEG.cmake └── Tools3DS.cmake ├── include ├── audio.h ├── gpu.h ├── gpu_math.h ├── color_converter.h ├── video.h └── movie.h ├── CMakeLists.txt ├── data └── shader.pica ├── ffmpeg-configure3ds ├── source ├── audio.c ├── gpu_math.c ├── video.c ├── movie.c ├── main.c ├── color_converter.c └── gpu.c ├── README.md ├── .gitignore ├── DevkitArm3DS.cmake ├── Makefile └── LICENSE.md /cmake/bin2s_header.h.in: -------------------------------------------------------------------------------- 1 | extern const u8 @__BIN_FILE_NAME@_end[]; 2 | extern const u8 @__BIN_FILE_NAME@[]; 3 | extern const u32 @__BIN_FILE_NAME@_size; 4 | -------------------------------------------------------------------------------- /include/audio.h: -------------------------------------------------------------------------------- 1 | /** 2 | *@file audio.h 3 | *@author Lectem 4 | *@date 14/06/2015 5 | */ 6 | #pragma once 7 | 8 | #include "movie.h" 9 | 10 | int audio_open_stream(MovieState * mv); 11 | void audio_close_stream(MovieState * mvS); 12 | -------------------------------------------------------------------------------- /include/gpu.h: -------------------------------------------------------------------------------- 1 | /** 2 | *@file gpu.h 3 | *@author Lectem 4 | *@date 11/07/2015 5 | */ 6 | #pragma once 7 | 8 | 9 | #include "movie.h" 10 | 11 | void gpuInit(); 12 | 13 | 14 | void gpuExit(); 15 | 16 | 17 | void gpuRenderFrame(MovieState *mvS); 18 | 19 | void gpuEndFrame(); -------------------------------------------------------------------------------- /include/gpu_math.h: -------------------------------------------------------------------------------- 1 | /** 2 | *@file gpu_math.h 3 | *@author Lectem 4 | *@date 11/07/2015 5 | */ 6 | #pragma once 7 | 8 | void initOrthographicMatrix(float *m, float left, float right, float bottom, float top, float near, float far); 9 | void SetUniformMatrix(u32 startreg, float* m); 10 | -------------------------------------------------------------------------------- /include/color_converter.h: -------------------------------------------------------------------------------- 1 | /** 2 | *@file color_converter.h 3 | *@author Lectem 4 | *@date 18/06/2015 5 | */ 6 | #pragma once 7 | 8 | #include "movie.h" 9 | #include <3ds.h> 10 | 11 | int initColorConverter(MovieState* mvS); 12 | 13 | int colorConvert(MovieState* mvS); 14 | 15 | int exitColorConvert(MovieState* mvS); 16 | 17 | -------------------------------------------------------------------------------- /include/video.h: -------------------------------------------------------------------------------- 1 | /** 2 | *@file video.h 3 | *@author Lectem 4 | *@date 14/06/2015 5 | */ 6 | #pragma once 7 | 8 | 9 | #include 10 | #include "movie.h" 11 | 12 | int video_open_stream(MovieState *mv); 13 | 14 | void video_close_stream(MovieState *mv); 15 | 16 | 17 | void display(AVFrame *pFrame); 18 | 19 | void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame); -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | project(3DAmneSic C CXX ASM) 3 | 4 | list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake) 5 | include(Tools3DS) 6 | 7 | find_package(CTRULIB REQUIRED) 8 | find_package(FFMPEG REQUIRED) 9 | 10 | file(GLOB_RECURSE SOURCE_FILES 11 | source/* 12 | include/* 13 | ) 14 | 15 | add_executable(3DAmneSic ${SOURCE_FILES}) 16 | target_link_libraries(3DAmneSic ${FFMPEG_swresample_LIBRARY} ${FFMPEG_swscale_LIBRARY} ${FFMPEG_avformat_LIBRARY} ${FFMPEG_avcodec_LIBRARY} ${FFMPEG_avutil_LIBRARY} m 3ds::ctrulib) 17 | target_include_directories(3DAmneSic PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include ${FFMPEG_INCLUDE_DIR}) 18 | if(3DS) 19 | target_embed_shader(3DAmneSic data/shader.pica) 20 | add_3dsx_target(3DAmneSic 3DAmneSic "A WIP media player !" Lectem) 21 | add_netload_target(run 3DAmneSic) 22 | endif() -------------------------------------------------------------------------------- /data/shader.pica: -------------------------------------------------------------------------------- 1 | ; Really simple & stupid PICA200 shader 2 | ; Taken from picasso example 3 | 4 | ; Uniforms 5 | .fvec projection[4] 6 | 7 | ; Constants 8 | .constf myconst(0.0, 1.0, -1.0, 0.0) 9 | .alias ones myconst.yyyy ; (1.0,1.0,1.0,1.0) 10 | 11 | ; Outputs : here only position and color 12 | .out outpos position 13 | .out outclr color 14 | .out outtex0 texcoord0 15 | .out outtex1 texcoord1 16 | .out outtex2 texcoord2 17 | 18 | ; Inputs : here we have only vertices 19 | .alias inpos v0 20 | .alias incolor v1 21 | .alias intex0 v2 22 | 23 | .proc main 24 | ; r0 = (inpos.x, inpos.y, inpos.z, 1.0) 25 | mov r0.xyz, inpos 26 | mov r0.w, ones 27 | 28 | ; outpos = projection * r1 29 | ;dp4 outpos.x, projection[0], r0 30 | ;dp4 outpos.y, projection[1], r0 31 | ;dp4 outpos.z, projection[2], r0 32 | ;dp4 outpos.w, projection[3], r0 33 | mov outpos, r0 34 | mov outtex0, intex0 35 | mov outtex1, intex0 36 | mov outtex2, intex0 37 | ; Set vertex color to white rgba => (1.0,1.0,1.0,1.0) 38 | mov outclr, incolor 39 | end 40 | .end -------------------------------------------------------------------------------- /ffmpeg-configure3ds: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export PATH=$DEVKITARM/bin:$PATH 4 | export ARCH="-march=armv6k -mtune=mpcore -mfloat-abi=hard" 5 | 6 | ./configure --prefix=$DEVKITPRO/portlibs/3ds/ \ 7 | --enable-cross-compile \ 8 | --cross-prefix=$DEVKITARM/bin/arm-none-eabi- \ 9 | --disable-shared \ 10 | --disable-runtime-cpudetect \ 11 | --disable-armv5te \ 12 | --disable-programs \ 13 | --disable-doc \ 14 | --disable-everything \ 15 | --enable-decoder=mpeg4,h264,aac,ac3,mp3 \ 16 | --enable-demuxer=mov,h264 \ 17 | --enable-filter=rotate,transpose \ 18 | --enable-protocol=file \ 19 | --enable-static \ 20 | --enable-small \ 21 | --arch=armv6k \ 22 | --cpu=mpcore \ 23 | --disable-armv6t2 \ 24 | --disable-neon \ 25 | --target-os=none \ 26 | --extra-cflags=" -DARM11 -D_3DS -mword-relocations -fomit-frame-pointer -ffast-math $ARCH" \ 27 | --extra-cxxflags=" -DARM11 -D_3DS -mword-relocations -fomit-frame-pointer -ffast-math -fno-rtti -fno-exceptions -std=gnu++11 $ARCH" \ 28 | --extra-ldflags=" -specs=3dsx.specs $ARCH -L$DEVKITARM/lib -L$DEVKITPRO/libctru/lib -L$DEVKITPRO/portlibs/3ds/lib -lctru " \ 29 | --disable-bzlib \ 30 | --disable-iconv \ 31 | --disable-lzma \ 32 | --disable-sdl \ 33 | --disable-securetransport \ 34 | --disable-xlib \ 35 | --disable-zlib 36 | #--enable-lto -------------------------------------------------------------------------------- /include/movie.h: -------------------------------------------------------------------------------- 1 | /** 2 | *@file movie.h 3 | *@author Lectem 4 | *@date 14/06/2015 5 | */ 6 | #pragma once 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "3ds.h" 12 | 13 | 14 | typedef enum{ 15 | CONVERT_COL_SWSCALE =0, 16 | CONVERT_COL_Y2R =1, 17 | }CONVERT_COLOR_METHOD; 18 | 19 | typedef struct MovieState { 20 | AVFormatContext * pFormatCtx ; 21 | int videoStream,audioStream; 22 | 23 | // video codec 24 | AVCodecContext *pCodecCtxOrig ; 25 | AVCodecContext *pCodecCtx ; 26 | AVCodec *pCodec ; 27 | 28 | // audio codec 29 | AVCodecContext *aCodecCtxOrig; 30 | AVCodecContext *aCodecCtx; 31 | AVCodec *aCodec ; 32 | 33 | // video frame 34 | AVFrame *pFrame ; 35 | AVFrame *outFrame;// 1024x1024 texture 36 | u16 out_bpp; 37 | AVPacket packet; 38 | struct SwsContext *sws_ctx ; 39 | CONVERT_COLOR_METHOD convertColorMethod; 40 | Y2RU_ConversionParams params; 41 | Handle end_event; 42 | bool renderGpu; 43 | } MovieState; 44 | 45 | 46 | int setup(MovieState * mv,char * filename); 47 | void tearup(MovieState *mv); 48 | -------------------------------------------------------------------------------- /source/audio.c: -------------------------------------------------------------------------------- 1 | /** 2 | *@file audio.cpp 3 | *@author Lectem 4 | *@date 14/06/2015 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include "audio.h" 10 | 11 | /** 12 | * open an audio stream 13 | * 14 | * mv->audioStream must be a valid audio stream 15 | * 16 | * @return 0 if opened 17 | * @return -1 on failure 18 | */ 19 | int audio_open_stream(MovieState *mv) 20 | { 21 | if (mv->audioStream == -1) 22 | return -1; 23 | 24 | mv->aCodecCtxOrig = mv->pFormatCtx->streams[mv->audioStream]->codec; 25 | 26 | mv->aCodec = avcodec_find_decoder(mv->aCodecCtxOrig->codec_id); 27 | 28 | if (!mv->aCodec) 29 | { 30 | fprintf(stderr, "Unsupported audio codec!\n"); 31 | return -1; 32 | } 33 | else 34 | { 35 | printf("audio decoder : %s - OK\n", mv->aCodec->name); 36 | } 37 | 38 | // Copy context 39 | mv->aCodecCtx = avcodec_alloc_context3(mv->aCodec); 40 | if (avcodec_copy_context(mv->aCodecCtx, mv->aCodecCtxOrig) != 0) 41 | { 42 | fprintf(stderr, "Couldn't copy audio codec context"); 43 | return -1; // Error copying codec context 44 | } 45 | 46 | if (avcodec_open2(mv->aCodecCtx, mv->aCodec, NULL) < 0) 47 | { 48 | fprintf(stderr, "Couldn't open audio codec context"); 49 | return -1; // Error copying codec context 50 | } 51 | 52 | return 0; 53 | } 54 | 55 | 56 | void audio_close_stream(MovieState *mvS) 57 | { 58 | avcodec_free_context(&mvS->aCodecCtx); 59 | avcodec_close(mvS->aCodecCtxOrig); 60 | } 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 3Damnesic (Abandoned) 2 | 3 | A Work In Progress media player for 3ds using ffmpeg ! 4 | 5 | # Requirements 6 | 7 | * DevkitArm 8 | * Latest ctrulib 9 | * ffmpeg compiled with the following instructions 10 | 11 | # Building 12 | 13 | ## FFMPEG 14 | 15 | * Copy the ffmpeg-configure3ds script in your ffmpeg source folder 16 | * Open a shell/command line in ffmpeg directory 17 | - Windows users please use `sh` before starting the script 18 | * ./ffmpeg-configure3ds 19 | * make install 20 | 21 | This will compile ffmpeg (with only a few features) with devkitArm and install it as a portlib 22 | 23 | ## 3Damnesic 24 | 25 | ### With the Makefile 26 | 27 | Simply use `make`. 28 | 29 | ### With CMake 30 | 31 | * `mkdir cbuild && cd cbuild` 32 | * On *NIX `cmake -DCMAKE_TOOLCHAIN_FILE=DevkitArm3DS.cmake ..` 33 | * On Windows `cmake -DCMAKE_TOOLCHAIN_FILE=DevkitArm3DS.cmake -G"Unix Makefiles" ..` 34 | * `make` 35 | 36 | More information on the [3ds-cmake](https://github.com/Lectem/3ds-cmake) repository. 37 | 38 | # Usage 39 | 40 | At the moment, you have to specify the file path in the main.c file at compilation time. 41 | 42 | 43 | # Features 44 | 45 | * Video 46 | - MPEG4, H.264 47 | - Hardware acceleration with Y2R for YUV -> RGB conversions 48 | 49 | # TODO 50 | 51 | * Audio 52 | * Sync and time adjustment 53 | * File Browser and Menu 54 | * Subtitles 55 | * More formats and track selection 56 | * Use the MVD service for the new3ds 57 | 58 | # Random informations 59 | 60 | Use a video with dimensions multiple of 8 for best performance ! 61 | 62 | Videos up to 1024x1024 are supported (but eh, that won't run fullspeed you know) 63 | - Actually only if width < 800 if you set up the framebuffers to be using RGBA 64 | 65 | Prefer simple MPEG4 to H.264 ! (H.264 is ~4 times slower) 66 | 67 | Some stats (video only, old 3ds) : 68 | 69 | * 400x240 mpeg4 -> 37fps 70 | * 400x240 h264 -> 16fps 71 | 72 | The new3ds is way faster 73 | -------------------------------------------------------------------------------- /cmake/FindCTRULIB.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find ctrulib 2 | # Once done this will define 3 | # LIBCTRU_FOUND - System has ctrulib 4 | # LIBCTRU_INCLUDE_DIRS - The ctrulib include directories 5 | # LIBCTRU_LIBRARIES - The libraries needed to use ctrulib 6 | # 7 | # It also adds an imported target named `3ds::ctrulib`. 8 | # Linking it is the same as target_link_libraries(target ${LIBCTRU_LIBRARIES}) and target_include_directories(target ${LIBCTRU_INCLUDE_DIRS}) 9 | 10 | # DevkitPro paths are broken on windows, so we have to fix those 11 | macro(msys_to_cmake_path MsysPath ResultingPath) 12 | string(REGEX REPLACE "^/([a-zA-Z])/" "\\1:/" ${ResultingPath} "${MsysPath}") 13 | endmacro() 14 | 15 | if(NOT DEVKITPRO) 16 | msys_to_cmake_path("$ENV{DEVKITPRO}" DEVKITPRO) 17 | endif() 18 | 19 | set(CTRULIB_PATHS $ENV{CTRULIB} libctru ctrulib ${DEVKITPRO}/libctru ${DEVKITPRO}/ctrulib) 20 | 21 | find_path(LIBCTRU_INCLUDE_DIR 3ds.h 22 | PATHS ${CTRULIB_PATHS} 23 | PATH_SUFFIXES include libctru/include ) 24 | 25 | find_library(LIBCTRU_LIBRARY NAMES ctru libctru.a 26 | PATHS ${CTRULIB_PATHS} 27 | PATH_SUFFIXES lib libctru/lib ) 28 | 29 | set(LIBCTRU_LIBRARIES ${LIBCTRU_LIBRARY} ) 30 | set(LIBCTRU_INCLUDE_DIRS ${LIBCTRU_INCLUDE_DIR} ) 31 | 32 | include(FindPackageHandleStandardArgs) 33 | # handle the QUIETLY and REQUIRED arguments and set LIBCTRU_FOUND to TRUE 34 | # if all listed variables are TRUE 35 | find_package_handle_standard_args(CTRULIB DEFAULT_MSG 36 | LIBCTRU_LIBRARY LIBCTRU_INCLUDE_DIR) 37 | 38 | mark_as_advanced(LIBCTRU_INCLUDE_DIR LIBCTRU_LIBRARY ) 39 | if(CTRULIB_FOUND) 40 | set(CTRULIB ${LIBCTRU_INCLUDE_DIR}/..) 41 | message(STATUS "setting CTRULIB to ${CTRULIB}") 42 | 43 | add_library(3ds::ctrulib STATIC IMPORTED GLOBAL) 44 | set_target_properties(3ds::ctrulib PROPERTIES 45 | IMPORTED_LOCATION "${LIBCTRU_LIBRARY}" 46 | INTERFACE_INCLUDE_DIRECTORIES "${LIBCTRU_INCLUDE_DIR}" 47 | ) 48 | endif() 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ###PROJECT SPECIFIC 2 | 3 | #3DS 4 | *.3dsx 5 | *.smdh 6 | 7 | #Other 8 | *.mp4 9 | cbuild 10 | build* 11 | perfresults.txt 12 | netload.bat 13 | 14 | ### C template 15 | # Object files 16 | *.o 17 | *.ko 18 | *.obj 19 | *.elf 20 | 21 | # Precompiled Headers 22 | *.gch 23 | *.pch 24 | 25 | # Libraries 26 | *.lib 27 | *.a 28 | *.la 29 | *.lo 30 | 31 | # Shared objects (inc. Windows DLLs) 32 | *.dll 33 | *.so 34 | *.so.* 35 | *.dylib 36 | 37 | # Executables 38 | *.exe 39 | *.out 40 | *.app 41 | *.i*86 42 | *.x86_64 43 | *.hex 44 | 45 | # Debug files 46 | *.dSYM/ 47 | 48 | 49 | ### JetBrains template 50 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion 51 | 52 | *.iml 53 | 54 | ## Directory-based project format: 55 | .idea/ 56 | # if you remove the above rule, at least ignore the following: 57 | 58 | # User-specific stuff: 59 | # .idea/workspace.xml 60 | # .idea/tasks.xml 61 | # .idea/dictionaries 62 | 63 | # Sensitive or high-churn files: 64 | # .idea/dataSources.ids 65 | # .idea/dataSources.xml 66 | # .idea/sqlDataSources.xml 67 | # .idea/dynamic.xml 68 | # .idea/uiDesigner.xml 69 | 70 | # Gradle: 71 | # .idea/gradle.xml 72 | # .idea/libraries 73 | 74 | # Mongo Explorer plugin: 75 | # .idea/mongoSettings.xml 76 | 77 | ## File-based project format: 78 | *.ipr 79 | *.iws 80 | 81 | ## Plugin-specific files: 82 | 83 | # IntelliJ 84 | /out/ 85 | 86 | # mpeltonen/sbt-idea plugin 87 | .idea_modules/ 88 | 89 | # JIRA plugin 90 | atlassian-ide-plugin.xml 91 | 92 | # Crashlytics plugin (for Android Studio and IntelliJ) 93 | com_crashlytics_export_strings.xml 94 | crashlytics.properties 95 | crashlytics-build.properties 96 | 97 | ### Archives template 98 | # It's better to unpack these files and commit the raw source because 99 | # git has its own built in compression methods. 100 | *.7z 101 | *.jar 102 | *.rar 103 | *.zip 104 | *.gz 105 | *.bzip 106 | *.bz2 107 | *.xz 108 | *.lzma 109 | *.cab 110 | 111 | #packing-only formats 112 | *.iso 113 | *.tar 114 | 115 | #package management formats 116 | *.dmg 117 | *.xpi 118 | *.gem 119 | *.egg 120 | *.deb 121 | *.rpm 122 | *.msi 123 | *.msm 124 | *.msp 125 | 126 | 127 | -------------------------------------------------------------------------------- /DevkitArm3DS.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_SYSTEM_NAME Generic) 2 | set(CMAKE_SYSTEM_PROCESSOR armv6k) 3 | set(3DS TRUE) # To be used for multiplatform projects 4 | 5 | # DevkitPro Paths are broken on windows, so we have to fix those 6 | macro(msys_to_cmake_path MsysPath ResultingPath) 7 | if(WIN32) 8 | string(REGEX REPLACE "^/([a-zA-Z])/" "\\1:/" ${ResultingPath} "${MsysPath}") 9 | else() 10 | set(${ResultingPath} "${MsysPath}") 11 | endif() 12 | endmacro() 13 | 14 | msys_to_cmake_path("$ENV{DEVKITPRO}" DEVKITPRO) 15 | if(NOT IS_DIRECTORY ${DEVKITPRO}) 16 | message(FATAL_ERROR "Please set DEVKITPRO in your environment") 17 | endif() 18 | 19 | msys_to_cmake_path("$ENV{DEVKITARM}" DEVKITARM) 20 | if(NOT IS_DIRECTORY ${DEVKITARM}) 21 | message(FATAL_ERROR "Please set DEVKITARM in your environment") 22 | endif() 23 | 24 | include(CMakeForceCompiler) 25 | # Prefix detection only works with compiler id "GNU" 26 | # CMake will look for prefixed g++, cpp, ld, etc. automatically 27 | if(WIN32) 28 | set(CMAKE_C_COMPILER "${DEVKITARM}/bin/arm-none-eabi-gcc.exe") 29 | set(CMAKE_CXX_COMPILER "${DEVKITARM}/bin/arm-none-eabi-g++.exe") 30 | set(CMAKE_AR "${DEVKITARM}/bin/arm-none-eabi-gcc-ar.exe" CACHE STRING "") 31 | set(CMAKE_RANLIB "${DEVKITARM}/bin/arm-none-eabi-gcc-ranlib.exe" CACHE STRING "") 32 | else() 33 | set(CMAKE_C_COMPILER "${DEVKITARM}/bin/arm-none-eabi-gcc") 34 | set(CMAKE_CXX_COMPILER "${DEVKITARM}/bin/arm-none-eabi-g++") 35 | set(CMAKE_AR "${DEVKITARM}/bin/arm-none-eabi-gcc-ar" CACHE STRING "") 36 | set(CMAKE_RANLIB "${DEVKITARM}/bin/arm-none-eabi-gcc-ranlib" CACHE STRING "") 37 | endif() 38 | 39 | set(WITH_PORTLIBS ON CACHE BOOL "use portlibs ?") 40 | 41 | if(WITH_PORTLIBS) 42 | set(CMAKE_FIND_ROOT_PATH ${DEVKITARM} ${DEVKITPRO} ${DEVKITPRO}/portlibs/3ds) 43 | else() 44 | set(CMAKE_FIND_ROOT_PATH ${DEVKITARM} ${DEVKITPRO}) 45 | endif() 46 | 47 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 48 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 49 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 50 | set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) 51 | 52 | SET(BUILD_SHARED_LIBS OFF CACHE INTERNAL "Shared libs not available" ) 53 | 54 | add_definitions(-DARM11 -D_3DS) 55 | 56 | set(ARCH "-march=armv6k -mtune=mpcore -mfloat-abi=hard ") 57 | set(CMAKE_C_FLAGS " -mword-relocations ${ARCH}" CACHE STRING "C flags") 58 | set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}" CACHE STRING "C++ flags") 59 | set(DKA_SUGGESTED_C_FLAGS "-fomit-frame-pointer -ffast-math") 60 | set(DKA_SUGGESTED_CXX_FLAGS "${DKA_SUGGESTED_C_FLAGS} -fno-rtti -fno-exceptions -std=gnu++11") 61 | 62 | set(CMAKE_INSTALL_PREFIX ${DEVKITPRO}/portlibs/3ds 63 | CACHE PATH "Install libraries in the portlibs dir") 64 | 65 | -------------------------------------------------------------------------------- /source/gpu_math.c: -------------------------------------------------------------------------------- 1 | /** 2 | *@file gpu_math.c 3 | *@author Lectem 4 | *@date 11/07/2015 5 | */ 6 | #include <3ds.h> 7 | #include 8 | #include "gpu_math.h" 9 | 10 | 11 | void loadIdentity44(float* m) 12 | { 13 | if(!m)return; 14 | 15 | memset(m, 0x00, 16*4); 16 | m[0]=m[5]=m[10]=m[15]=1.0f; 17 | } 18 | 19 | void multMatrix44(float* m1, float* m2, float* m) //4x4 20 | { 21 | int i, j; 22 | for(i=0;i<4;i++)for(j=0;j<4;j++)m[i+j*4]=(m1[0+j*4]*m2[i+0*4])+(m1[1+j*4]*m2[i+1*4])+(m1[2+j*4]*m2[i+2*4])+(m1[3+j*4]*m2[i+3*4]); 23 | 24 | } 25 | 26 | void initOrthographicMatrix(float *m, float left, float right, float bottom, float top, float near, float far) 27 | { 28 | /* ______________________ 29 | | | 30 | | | 31 | | | 32 | | | 33 | | | 34 | |______________________| ^ 35 | | x 36 | <----- 37 | y 38 | */ 39 | 40 | //Mirror 41 | //right = 400-right; 42 | //left = 400-left; 43 | //top = 240-top; 44 | //bottom = 240-bottom; 45 | 46 | float mp[4*4]; 47 | 48 | mp[0x0] = 2.0f/(right-left); 49 | mp[0x1] = 0.0f; 50 | mp[0x2] = 0.0f; 51 | mp[0x3] = -(right+left)/(right-left); 52 | 53 | mp[0x4] = 0.0f; 54 | mp[0x5] = 2.0f/(top-bottom); 55 | mp[0x6] = 0.0f; 56 | mp[0x7] = -(top+bottom)/(top-bottom); 57 | 58 | mp[0x8] = 0.0f; 59 | mp[0x9] = 0.0f; 60 | mp[0xA] = -2.0f/(far-near); 61 | mp[0xB] = (far+near)/(far-near); 62 | 63 | mp[0xC] = 0.0f; 64 | mp[0xD] = 0.0f; 65 | mp[0xE] = 0.0f; 66 | mp[0xF] = 1.0f; 67 | 68 | float mp2[4*4]; 69 | loadIdentity44(mp2); 70 | mp2[0xA] = 0.5; 71 | mp2[0xB] = -0.5; 72 | 73 | //Convert Z [-1, 1] to [-1, 0] (PICA shiz) 74 | multMatrix44(mp2, mp, m); 75 | 76 | //rotateMatrixZ(m, M_PI/2, false); 77 | } 78 | 79 | 80 | 81 | void SetUniformMatrix(u32 startreg, float* m) 82 | { 83 | float param[16]; 84 | 85 | param[0x0]=m[3]; //w 86 | param[0x1]=m[2]; //z 87 | param[0x2]=m[1]; //y 88 | param[0x3]=m[0]; //x 89 | 90 | param[0x4]=m[7]; 91 | param[0x5]=m[6]; 92 | param[0x6]=m[5]; 93 | param[0x7]=m[4]; 94 | 95 | param[0x8]=m[11]; 96 | param[0x9]=m[10]; 97 | param[0xa]=m[9]; 98 | param[0xb]=m[8]; 99 | 100 | param[0xc]=m[15]; 101 | param[0xd]=m[14]; 102 | param[0xe]=m[13]; 103 | param[0xf]=m[12]; 104 | 105 | GPU_SetFloatUniform(GPU_VERTEX_SHADER, startreg, (u32*)param, 4); 106 | } 107 | -------------------------------------------------------------------------------- /source/video.c: -------------------------------------------------------------------------------- 1 | /** 2 | *@file video.c 3 | *@author Lectem 4 | *@date 14/06/2015 5 | */ 6 | #include <3ds.h> 7 | #include 8 | 9 | 10 | #include "movie.h" 11 | #include "video.h" 12 | 13 | 14 | /** 15 | * open a video stream 16 | * 17 | * mv->videoStream must be a valid audio stream 18 | * 19 | * @return 0 if opened 20 | * @return -1 on failure 21 | */ 22 | int video_open_stream(MovieState *mv) 23 | { 24 | if (mv->videoStream == -1) 25 | return -1; 26 | 27 | // Get a pointer to the codec context for the video stream 28 | mv->pCodecCtxOrig = mv->pFormatCtx->streams[mv->videoStream]->codec; 29 | // Find the decoder for the video stream 30 | mv->pCodec = avcodec_find_decoder(mv->pCodecCtxOrig->codec_id); 31 | if (mv->pCodec == NULL) 32 | { 33 | fprintf(stderr, "Unsupported video codec!\n"); 34 | return -1; // Codec not found 35 | } 36 | else 37 | { 38 | printf("video decoder : %s - OK\n", mv->pCodec->name); 39 | } 40 | // Copy context 41 | mv->pCodecCtx = avcodec_alloc_context3(mv->pCodec); 42 | if (avcodec_copy_context(mv->pCodecCtx, mv->pCodecCtxOrig) != 0) 43 | { 44 | fprintf(stderr, "Couldn't copy video codec context"); 45 | return -1; // Error copying codec context 46 | } 47 | 48 | // Open codec 49 | if (avcodec_open2(mv->pCodecCtx, mv->pCodec, NULL) < 0) 50 | { 51 | printf("Could not open codec\n"); 52 | return -1; 53 | } 54 | return 0; 55 | } 56 | 57 | 58 | void video_close_stream(MovieState *mvS) 59 | { 60 | avcodec_free_context(&mvS->pCodecCtx); 61 | avcodec_close(mvS->pCodecCtxOrig); 62 | } 63 | 64 | 65 | void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame) 66 | { 67 | FILE *pFile; 68 | char szFilename[32]; 69 | int y; 70 | 71 | // Open file 72 | sprintf(szFilename, "frame%d.ppm", iFrame); 73 | pFile = fopen(szFilename, "wb"); 74 | if (pFile == NULL) 75 | return; 76 | 77 | // Write header 78 | fprintf(pFile, "P6\n%d %d\n255\n", width, height); 79 | 80 | // Write pixel data 81 | for (y = 0; y < height; y++) 82 | fwrite(pFrame->data[0] + y * pFrame->linesize[0], 1, width * 3, pFile); 83 | 84 | // Close file 85 | fclose(pFile); 86 | } 87 | 88 | void display(AVFrame *pFrame) 89 | { 90 | // gspWaitForVBlank(); 91 | // gfxSwapBuffers(); 92 | int i, j, c; 93 | const int width = 400 <= pFrame->width ? 400 : pFrame->width; 94 | const int height = 240 <= pFrame->height ? 240 : pFrame->height; 95 | if (gfxGetScreenFormat(GFX_TOP) == GSP_BGR8_OES) 96 | { 97 | 98 | u8 *const src = pFrame->data[0]; 99 | u8 *const fbuffer = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, 0, 0); 100 | 101 | for (i = 0; i < width; ++i) 102 | { 103 | for (j = 0; j < height; ++j) 104 | { 105 | for (c = 0; c < 3; ++c) 106 | { 107 | fbuffer[3 * 240 * i + (239 - j) * 3 + c] = src[1024 * 3 * j + i * 3 + c]; 108 | } 109 | } 110 | } 111 | } 112 | else if (gfxGetScreenFormat(GFX_TOP) == GSP_RGBA8_OES) 113 | { 114 | 115 | u32 *const src = (u32 *) pFrame->data[0]; 116 | u32 *const fbuffer = (u32 *) gfxGetFramebuffer(GFX_TOP, GFX_LEFT, 0, 0); 117 | for (i = 0; i < width; ++i) 118 | { 119 | for (j = 0; j < height; ++j) 120 | { 121 | fbuffer[240 * i + (239 - j)] = src[1024 * j + i]; 122 | } 123 | } 124 | } 125 | else 126 | { 127 | printf("format not supported\n"); 128 | } 129 | } 130 | 131 | void displayGPU() 132 | { 133 | 134 | } 135 | -------------------------------------------------------------------------------- /cmake/FindFFMPEG.cmake: -------------------------------------------------------------------------------- 1 | #.rst: 2 | # FindFFMPEG 3 | # ---------- 4 | # 5 | # Find the native FFMPEG includes and library 6 | # 7 | # This module defines:: 8 | # 9 | # FFMPEG_INCLUDE_DIR, where to find libavcodec/avcodec.h, libavformat/avformat.h ... 10 | # FFMPEG_LIBRARIES, the libraries to link against to use FFMPEG. 11 | # FFMPEG_FOUND, If false, do not try to use FFMPEG. 12 | # 13 | # also defined, but not for general use are:: 14 | # 15 | # FFMPEG_avformat_LIBRARY, where to find the FFMPEG avformat library. 16 | # FFMPEG_avcodec_LIBRARY, where to find the FFMPEG avcodec library. 17 | # 18 | # This is useful to do it this way so that we can always add more libraries 19 | # if needed to ``FFMPEG_LIBRARIES`` if ffmpeg ever changes... 20 | 21 | #============================================================================= 22 | # Copyright: 1993-2008 Ken Martin, Will Schroeder, Bill Lorensen 23 | # 24 | # Distributed under the OSI-approved BSD License (the "License"); 25 | # see accompanying file Copyright.txt for details. 26 | # 27 | # This software is distributed WITHOUT ANY WARRANTY; without even the 28 | # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 29 | # See the License for more information. 30 | #============================================================================= 31 | # (To distribute this file outside of YCM, substitute the full 32 | # License text for the above reference.) 33 | 34 | # Originally from VTK project 35 | 36 | 37 | find_path(FFMPEG_INCLUDE_DIR 38 | NAMES 39 | libavformat/avformat.h 40 | libavcodec/avcodec.h 41 | libavutil/avutil.h 42 | $ENV{FFMPEG_DIR} 43 | $ENV{FFMPEG_DIR}/ffmpeg 44 | $ENV{FFMPEG_DIR}/include/ffmpeg 45 | /usr/local/include/ffmpeg 46 | /usr/include/ffmpeg 47 | ) 48 | 49 | find_library(FFMPEG_avformat_LIBRARY avformat 50 | $ENV{FFMPEG_DIR} 51 | $ENV{FFMPEG_DIR}/lib 52 | $ENV{FFMPEG_DIR}/libavformat 53 | /usr/local/lib 54 | /usr/lib 55 | ) 56 | 57 | find_library(FFMPEG_avcodec_LIBRARY avcodec 58 | $ENV{FFMPEG_DIR} 59 | $ENV{FFMPEG_DIR}/lib 60 | $ENV{FFMPEG_DIR}/libavcodec 61 | /usr/local/lib 62 | /usr/lib 63 | ) 64 | 65 | find_library(FFMPEG_avutil_LIBRARY avutil 66 | $ENV{FFMPEG_DIR} 67 | $ENV{FFMPEG_DIR}/lib 68 | $ENV{FFMPEG_DIR}/libavutil 69 | /usr/local/lib 70 | /usr/lib 71 | ) 72 | 73 | if(NOT DISABLE_SWSCALE) 74 | find_library(FFMPEG_swscale_LIBRARY swscale 75 | $ENV{FFMPEG_DIR} 76 | $ENV{FFMPEG_DIR}/lib 77 | $ENV{FFMPEG_DIR}/libswscale 78 | /usr/local/lib 79 | /usr/lib 80 | ) 81 | endif(NOT DISABLE_SWSCALE) 82 | 83 | find_library(FFMPEG_avdevice_LIBRARY avdevice 84 | $ENV{FFMPEG_DIR} 85 | $ENV{FFMPEG_DIR}/lib 86 | $ENV{FFMPEG_DIR}/libavdevice 87 | /usr/local/lib 88 | /usr/lib 89 | ) 90 | 91 | find_library(_FFMPEG_z_LIBRARY_ z 92 | $ENV{FFMPEG_DIR} 93 | $ENV{FFMPEG_DIR}/lib 94 | /usr/local/lib 95 | /usr/lib 96 | ) 97 | 98 | 99 | 100 | if(FFMPEG_INCLUDE_DIR) 101 | if(FFMPEG_avformat_LIBRARY) 102 | if(FFMPEG_avcodec_LIBRARY) 103 | if(FFMPEG_avutil_LIBRARY) 104 | set(FFMPEG_FOUND "YES") 105 | set(FFMPEG_LIBRARIES ${FFMPEG_avformat_LIBRARY} 106 | ${FFMPEG_avcodec_LIBRARY} 107 | ${FFMPEG_avutil_LIBRARY} 108 | ) 109 | if(FFMPEG_swscale_LIBRARY) 110 | set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} 111 | ${FFMPEG_swscale_LIBRARY} 112 | ) 113 | endif() 114 | if(FFMPEG_avdevice_LIBRARY) 115 | set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} 116 | ${FFMPEG_avdevice_LIBRARY} 117 | ) 118 | endif() 119 | if(_FFMPEG_z_LIBRARY_) 120 | set( FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} 121 | ${_FFMPEG_z_LIBRARY_} 122 | ) 123 | endif() 124 | endif() 125 | endif() 126 | endif() 127 | endif() 128 | 129 | mark_as_advanced( 130 | FFMPEG_INCLUDE_DIR 131 | FFMPEG_avformat_LIBRARY 132 | FFMPEG_avcodec_LIBRARY 133 | FFMPEG_avutil_LIBRARY 134 | FFMPEG_swscale_LIBRARY 135 | FFMPEG_avdevice_LIBRARY 136 | ) 137 | 138 | # Set package properties if FeatureSummary was included 139 | if(COMMAND set_package_properties) 140 | set_package_properties(FFMPEG PROPERTIES DESCRIPTION "A complete, cross-platform solution to record, convert and stream audio and video") 141 | set_package_properties(FFMPEG PROPERTIES URL "http://ffmpeg.org/") 142 | endif() 143 | -------------------------------------------------------------------------------- /source/movie.c: -------------------------------------------------------------------------------- 1 | /** 2 | *@file movie.c 3 | *@author Lectem 4 | *@date 14/06/2015 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "audio.h" 11 | #include "video.h" 12 | #include "movie.h" 13 | 14 | static unsigned int next_pow2(unsigned int v) 15 | { 16 | v--; 17 | v |= v >> 1; 18 | v |= v >> 2; 19 | v |= v >> 4; 20 | v |= v >> 8; 21 | v |= v >> 16; 22 | return v + 1; 23 | } 24 | 25 | 26 | int setup(MovieState *mv, char *filename) 27 | { 28 | 29 | 30 | memset(mv, 0, sizeof(*mv)); 31 | 32 | mv->videoStream = -1; 33 | mv->audioStream = -1; 34 | mv->renderGpu = true; 35 | 36 | mv->convertColorMethod = CONVERT_COL_Y2R; // TODO : check if the format is supported 37 | 38 | int i; 39 | 40 | // Open video file 41 | int averr = avformat_open_input(&mv->pFormatCtx, filename, NULL, NULL); 42 | if (averr != 0) 43 | { 44 | char buf[100]; 45 | av_strerror(averr, buf, 100); 46 | printf("Couldn't open file : %s\n", buf); 47 | return -1; 48 | } 49 | 50 | // Retrieve stream information 51 | if (avformat_find_stream_info(mv->pFormatCtx, NULL) < 0) 52 | { 53 | printf("Couldn't find stream information\n"); 54 | return -1; 55 | } 56 | 57 | printf("dumping info...\n"); 58 | // Dump information about file onto standard error 59 | av_dump_format(mv->pFormatCtx, 0, filename, 0); 60 | printf("\n"); 61 | 62 | 63 | // TODO Use av_find_best_stream ? 64 | // Find the first video and audio streams 65 | mv->videoStream = -1; 66 | for (i = 0; i < mv->pFormatCtx->nb_streams; i++) 67 | { 68 | if (mv->pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO && mv->videoStream < 0) 69 | { 70 | mv->videoStream = i; 71 | } 72 | if (mv->pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO && mv->audioStream < 0) 73 | { 74 | mv->audioStream = i; 75 | } 76 | } 77 | if (mv->videoStream == -1) 78 | { 79 | printf("Didn't find a video stream\n"); 80 | return -1; 81 | } 82 | if (mv->audioStream == -1) 83 | { 84 | printf("Didn't find an audio stream\n"); 85 | return -1; 86 | } 87 | 88 | printf("video stream %d\n", mv->videoStream); 89 | printf("audio stream %d\n\n", mv->audioStream); 90 | 91 | if (video_open_stream(mv))return -1; 92 | if (audio_open_stream(mv))return -1; 93 | 94 | // Allocate video frame 95 | mv->pFrame = av_frame_alloc(); 96 | if (mv->pFrame == NULL) 97 | { 98 | printf("Couldnt alloc pFrame\n"); 99 | return -1; 100 | } 101 | 102 | // Allocate an AVFrame structure 103 | mv->outFrame = av_frame_alloc(); 104 | if (mv->outFrame == NULL) 105 | { 106 | printf("Couldnt alloc outFrame\n"); 107 | return -1; 108 | } 109 | 110 | /** 111 | * Allocate a texture of minimal size to contain the decoded video 112 | * We cannot use 1024x1024 if width <= 512 because of the gap size limit in y2r 113 | */ 114 | mv->outFrame->width = next_pow2(mv->pCodecCtx->width); 115 | mv->outFrame->height = next_pow2(mv->pCodecCtx->height); 116 | if (mv->renderGpu) mv->out_bpp = 4; 117 | else if (gfxGetScreenFormat(GFX_TOP) == GSP_BGR8_OES)mv->out_bpp = 3; 118 | else if (gfxGetScreenFormat(GFX_TOP) == GSP_RGBA8_OES)mv->out_bpp = 4; 119 | mv->outFrame->linesize[0] = mv->outFrame->width * mv->out_bpp; 120 | mv->outFrame->data[0] = linearMemAlign(mv->outFrame->width * mv->outFrame->height * mv->out_bpp, 121 | 0x80);//RGBA next_pow2(width) x 1024 texture 122 | 123 | 124 | if (initColorConverter(mv) < 0) 125 | { 126 | exitColorConvert(mv); 127 | return -1; 128 | } 129 | 130 | /** 131 | * TODO Clean up when fail 132 | */ 133 | return 0; 134 | } 135 | 136 | 137 | void tearup(MovieState *mv) 138 | { 139 | av_free_packet(&mv->packet); 140 | exitColorConvert(mv); 141 | 142 | // Free the RGB image 143 | if (mv->outFrame->data[0])linearFree(mv->outFrame->data[0]); 144 | av_frame_free(&mv->outFrame); 145 | 146 | // Free the YUV frame 147 | av_frame_free(&mv->pFrame); 148 | 149 | // Close the codecs 150 | audio_close_stream(mv); 151 | video_close_stream(mv); 152 | 153 | // Close the video file 154 | avformat_close_input(&mv->pFormatCtx); 155 | } -------------------------------------------------------------------------------- /source/main.c: -------------------------------------------------------------------------------- 1 | #include <3ds.h> 2 | 3 | #include 4 | #include 5 | 6 | #include "movie.h" 7 | #include "gpu.h" 8 | #include "video.h" 9 | #include "color_converter.h" 10 | 11 | 12 | void waitForStart() 13 | { 14 | while (aptMainLoop()) 15 | { 16 | gspWaitForVBlank(); 17 | hidScanInput(); 18 | u32 kDown = hidKeysDown(); 19 | if (kDown & KEY_START)break; 20 | } 21 | } 22 | 23 | 24 | void initServices() 25 | { 26 | hidInit(); 27 | sdmcInit(); 28 | gfxInitDefault(); 29 | consoleInit(GFX_BOTTOM, NULL); 30 | 31 | // gfxInit(GSP_RGBA8_OES,GSP_BGR8_OES,false); 32 | // gfxInit(GSP_BGR8_OES,GSP_BGR8_OES,false); 33 | 34 | printf("Initializing the GPU...\n"); 35 | gpuInit(); 36 | printf("Done.\n"); 37 | } 38 | 39 | void exitServices() 40 | { 41 | gpuExit(); 42 | gfxExit(); 43 | sdmcExit(); 44 | hidExit(); 45 | } 46 | 47 | void waitForStartAndExit() 48 | { 49 | printf("Press start to exit\n"); 50 | waitForStart(); 51 | exitServices(); 52 | } 53 | 54 | 55 | int main(int argc, char *argv[]) 56 | { 57 | // char filename[]="/test400x240-mpeg4-witch.mp4"; 58 | // char filename[]="/test400x240-witch.mp4"; 59 | // char filename[]="/test800x400-witch-900kbps.mp4"; 60 | // char filename[]="/test800x400-witch-1pass.mp4"; 61 | // char filename[]="/test800x400-witch.mp4"; 62 | // char filename[]="/test800x480-witch-mpeg4.mp4"; 63 | // char filename[]="/test320x176-karanokyoukai.mp4"; 64 | char filename[] = "/test.mp4"; 65 | 66 | MovieState mvS; 67 | 68 | initServices(); 69 | 70 | // Register all formats and codecs 71 | av_register_all(); 72 | av_log_set_level(AV_LOG_INFO); 73 | 74 | 75 | printf("Press start to open the file\n"); 76 | waitForStart(); 77 | int ret = setup(&mvS, filename); 78 | if (ret) 79 | { 80 | waitForStartAndExit(); 81 | return -1; 82 | } 83 | 84 | printf("Press start to decompress\n"); 85 | waitForStart(); 86 | // Read frames and save first five frames to disk 87 | int i = 0; 88 | int frameFinished; 89 | 90 | u64 timeBeginning, timeEnd; 91 | u64 timeBefore, timeAfter; 92 | u64 timeDecodeTotal = 0, timeScaleTotal = 0, timeDisplayTotal = 0; 93 | 94 | timeBefore = osGetTime(); 95 | timeBeginning = timeBefore; 96 | bool stop = false; 97 | 98 | while (av_read_frame(mvS.pFormatCtx, &mvS.packet) >= 0 && !stop) 99 | { 100 | // Is this a packet from the video stream? 101 | if (mvS.packet.stream_index == mvS.videoStream) 102 | { 103 | 104 | /********************* 105 | * Decode video frame 106 | *********************/ 107 | 108 | int err = avcodec_decode_video2(mvS.pCodecCtx, mvS.pFrame, &frameFinished, &mvS.packet); 109 | if (err <= 0)printf("decode error\n"); 110 | // Did we get a video frame? 111 | if (frameFinished) 112 | { 113 | err = av_frame_get_decode_error_flags(mvS.pFrame); 114 | if (err) 115 | { 116 | char buf[100]; 117 | av_strerror(err, buf, 100); 118 | } 119 | timeAfter = osGetTime(); 120 | timeDecodeTotal += timeAfter - timeBefore; 121 | 122 | /******************************* 123 | * Conversion of decoded frame 124 | *******************************/ 125 | timeBefore = osGetTime(); 126 | colorConvert(&mvS); 127 | timeAfter = osGetTime(); 128 | 129 | /*********************** 130 | * Display of the frame 131 | ***********************/ 132 | timeScaleTotal += timeAfter - timeBefore; 133 | timeBefore = osGetTime(); 134 | 135 | if (mvS.renderGpu) 136 | { 137 | gpuRenderFrame(&mvS); 138 | gpuEndFrame(); 139 | } 140 | else display(mvS.outFrame); 141 | 142 | timeAfter = osGetTime(); 143 | timeDisplayTotal += timeAfter - timeBefore; 144 | 145 | ++i;//New frame 146 | 147 | hidScanInput(); 148 | u32 kDown = hidKeysDown(); 149 | if (kDown & KEY_START) 150 | stop = true; // break in order to return to hbmenu 151 | if (i % 50 == 0)printf("frame %d\n", i); 152 | timeBefore = osGetTime(); 153 | } 154 | 155 | } 156 | 157 | // Free the packet that was allocated by av_read_frame 158 | av_free_packet(&mvS.packet); 159 | } 160 | timeEnd = timeBefore; 161 | 162 | tearup(&mvS); 163 | 164 | printf("Played %d frames in %f s (%f fps)\n", 165 | i, (timeEnd - timeBeginning) / 1000.0, 166 | i / ((timeEnd - timeBeginning) / 1000.0)); 167 | printf("\tdecode:\t%llu\t%f perframe" 168 | "\n\tscale:\t%llu\t%f perframe" 169 | "\n\tdisplay:\t%llu\t%f perframe\n", 170 | timeDecodeTotal, timeDecodeTotal / (double) i, 171 | timeScaleTotal, timeScaleTotal / (double) i, 172 | timeDisplayTotal, timeDisplayTotal / (double) i); 173 | 174 | waitForStartAndExit(); 175 | return 0; 176 | } 177 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------- 2 | .SUFFIXES: 3 | #--------------------------------------------------------------------------------- 4 | 5 | ifeq ($(strip $(DEVKITARM)),) 6 | $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") 7 | endif 8 | 9 | TOPDIR ?= $(CURDIR) 10 | include $(DEVKITARM)/3ds_rules 11 | 12 | #--------------------------------------------------------------------------------- 13 | # TARGET is the name of the output 14 | # BUILD is the directory where object files & intermediate files will be placed 15 | # SOURCES is a list of directories containing source code 16 | # DATA is a list of directories containing data files 17 | # INCLUDES is a list of directories containing header files 18 | # 19 | # NO_SMDH: if set to anything, no SMDH file is generated. 20 | # APP_TITLE is the name of the app stored in the SMDH file (Optional) 21 | # APP_DESCRIPTION is the description of the app stored in the SMDH file (Optional) 22 | # APP_AUTHOR is the author of the app stored in the SMDH file (Optional) 23 | # ICON is the filename of the icon (.png), relative to the project folder. 24 | # If not set, it attempts to use one of the following (in this order): 25 | # - .png 26 | # - icon.png 27 | # - /default_icon.png 28 | #--------------------------------------------------------------------------------- 29 | TARGET := $(notdir $(CURDIR)) 30 | BUILD := build 31 | SOURCES := source source/UI source/UI/Layouts source/UI/Widgets 32 | DATA := data 33 | INCLUDES := include 34 | 35 | APP_TITLE := 3DAmneSic 36 | APP_DESCRIPTION := A WIP media player ! 37 | APP_AUTHOR := Lectem 38 | 39 | #--------------------------------------------------------------------------------- 40 | # options for code generation 41 | #--------------------------------------------------------------------------------- 42 | ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard 43 | 44 | CFLAGS := -Wall -Os -mword-relocations \ 45 | -fomit-frame-pointer -ffast-math \ 46 | $(ARCH) 47 | 48 | CFLAGS += -O2 $(INCLUDE) -DARM11 -D_3DS 49 | 50 | CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11 51 | 52 | ASFLAGS := $(ARCH) 53 | LDFLAGS = -O2 -flto --specs=3dsx.specs $(ARCH) -Wl,-Map,$(notdir $*.map) 54 | 55 | LIBS := -lavformat -lavcodec -lavutil -lswscale -lswresample -lctru -lm 56 | 57 | #--------------------------------------------------------------------------------- 58 | # list of directories containing libraries, this must be the top level containing 59 | # include and lib 60 | #--------------------------------------------------------------------------------- 61 | LIBDIRS := $(CTRULIB) $(PORTLIBS) 62 | 63 | 64 | #--------------------------------------------------------------------------------- 65 | # no real need to edit anything past this point unless you need to add additional 66 | # rules for different file extensions 67 | #--------------------------------------------------------------------------------- 68 | ifneq ($(BUILD),$(notdir $(CURDIR))) 69 | #--------------------------------------------------------------------------------- 70 | 71 | export OUTPUT := $(CURDIR)/$(TARGET) 72 | export TOPDIR := $(CURDIR) 73 | 74 | export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ 75 | $(foreach dir,$(DATA),$(CURDIR)/$(dir)) 76 | 77 | export DEPSDIR := $(CURDIR)/$(BUILD) 78 | 79 | CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) 80 | CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) 81 | SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) 82 | PICAFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.pica))) 83 | BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) 84 | 85 | #--------------------------------------------------------------------------------- 86 | # use CXX for linking C++ projects, CC for standard C 87 | #--------------------------------------------------------------------------------- 88 | ifeq ($(strip $(CPPFILES)),) 89 | #--------------------------------------------------------------------------------- 90 | export LD := $(CC) 91 | #--------------------------------------------------------------------------------- 92 | else 93 | #--------------------------------------------------------------------------------- 94 | export LD := $(CXX) 95 | #--------------------------------------------------------------------------------- 96 | endif 97 | #--------------------------------------------------------------------------------- 98 | 99 | export OFILES := $(addsuffix .o,$(BINFILES)) $(PICAFILES:.pica=.shbin.o) \ 100 | $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) 101 | 102 | export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ 103 | $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ 104 | -I$(CURDIR)/$(BUILD) 105 | 106 | export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) 107 | 108 | ifeq ($(strip $(ICON)),) 109 | icons := $(wildcard *.png) 110 | ifneq (,$(findstring $(TARGET).png,$(icons))) 111 | export APP_ICON := $(TOPDIR)/$(TARGET).png 112 | else 113 | ifneq (,$(findstring icon.png,$(icons))) 114 | export APP_ICON := $(TOPDIR)/icon.png 115 | endif 116 | endif 117 | else 118 | export APP_ICON := $(TOPDIR)/$(ICON) 119 | endif 120 | 121 | ifeq ($(strip $(NO_SMDH)),) 122 | export _3DSXFLAGS += --smdh=$(CURDIR)/$(TARGET).smdh 123 | endif 124 | 125 | .PHONY: $(BUILD) clean all 126 | 127 | #--------------------------------------------------------------------------------- 128 | all: $(BUILD) 129 | 130 | $(BUILD): 131 | @[ -d $@ ] || mkdir -p $@ 132 | @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile 133 | 134 | #--------------------------------------------------------------------------------- 135 | clean: 136 | @echo clean ... 137 | @rm -fr $(BUILD) $(TARGET).3dsx $(OUTPUT).smdh $(TARGET).elf 138 | 139 | 140 | #--------------------------------------------------------------------------------- 141 | else 142 | 143 | DEPENDS := $(OFILES:.o=.d) 144 | 145 | #--------------------------------------------------------------------------------- 146 | # main targets 147 | #--------------------------------------------------------------------------------- 148 | ifeq ($(strip $(NO_SMDH)),) 149 | $(OUTPUT).3dsx : $(OUTPUT).elf $(OUTPUT).smdh 150 | else 151 | $(OUTPUT).3dsx : $(OUTPUT).elf 152 | endif 153 | 154 | $(OUTPUT).elf : $(OFILES) 155 | 156 | #--------------------------------------------------------------------------------- 157 | # you need a rule like this for each extension you use as binary data 158 | #--------------------------------------------------------------------------------- 159 | %.bin.o : %.bin 160 | #--------------------------------------------------------------------------------- 161 | @echo $(notdir $<) 162 | @$(bin2o) 163 | 164 | #--------------------------------------------------------------------------------- 165 | # rule for assembling GPU shaders 166 | #--------------------------------------------------------------------------------- 167 | %.pica.o: %.pica 168 | @echo $(notdir $<) 169 | $(eval CURBIN := $(patsubst %.pica,%.shbin,$(notdir $<))) 170 | $(eval CURH := $(patsubst %.pica,%.psh.h,$(notdir $<))) 171 | @picasso -h $(CURH) -o $(CURBIN) $< 172 | @bin2s $(CURBIN) | $(AS) -o $@ 173 | @echo "extern const u8" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(CURBIN) | tr . _)`.h 174 | @echo "extern const u8" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(CURBIN) | tr . _)`.h 175 | @echo "extern const u32" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(CURBIN) | tr . _)`.h 176 | 177 | -include $(DEPENDS) 178 | 179 | #--------------------------------------------------------------------------------------- 180 | endif 181 | #--------------------------------------------------------------------------------------- 182 | -------------------------------------------------------------------------------- /source/color_converter.c: -------------------------------------------------------------------------------- 1 | /** 2 | *@file color_converter.c 3 | *@author Lectem 4 | *@date 18/06/2015 5 | */ 6 | #include 7 | #include "color_converter.h" 8 | #include <3ds.h> 9 | 10 | #include 11 | #include <3ds/services/y2r.h> 12 | 13 | static inline double u64_to_double(u64 value) 14 | { 15 | return (((double) (u32) (value >> 32)) * 0x100000000ULL + (u32) value); 16 | } 17 | 18 | int initColorConverterSwscale(MovieState *mvS) 19 | { 20 | enum AVPixelFormat out_fmt = AV_PIX_FMT_BGR24; 21 | if (gfxGetScreenFormat(GFX_TOP) == GSP_RGBA8_OES) out_fmt = AV_PIX_FMT_BGRA; 22 | // initialize SWS context for software scaling 23 | mvS->sws_ctx = sws_getContext(mvS->pCodecCtx->width, mvS->pCodecCtx->height, mvS->pCodecCtx->pix_fmt, 24 | mvS->pCodecCtx->width, mvS->pCodecCtx->height, out_fmt, 25 | 0,//SWS_BILINEAR,//TODO perf comparison 26 | NULL, 27 | NULL, 28 | NULL 29 | ); 30 | 31 | 32 | if (mvS->sws_ctx == NULL) 33 | { 34 | printf("Couldnt initialize sws\n"); 35 | return -1; 36 | } 37 | return 0; 38 | } 39 | 40 | 41 | int exitColorConvertSwscale(MovieState *mvS) 42 | { 43 | sws_freeContext(mvS->sws_ctx); 44 | return 0; 45 | } 46 | 47 | 48 | int colorConvertSwscale(MovieState *mvS) 49 | { 50 | // Convert the image from its native format to RGB 51 | sws_scale(mvS->sws_ctx, (uint8_t const *const *) mvS->pFrame->data, 52 | mvS->pFrame->linesize, 0, mvS->pCodecCtx->height, 53 | mvS->outFrame->data, mvS->outFrame->linesize); 54 | return 0; 55 | } 56 | 57 | #define CHECKRES() do{if(res != 0){printf("error %lx L%d %s\n",(u32)res,__LINE__,osStrError(res));return -1;}}while(0); 58 | 59 | int ffmpegPixelFormatToY2R(enum AVPixelFormat pix_fmt) 60 | { 61 | switch (pix_fmt) 62 | { 63 | case AV_PIX_FMT_YUV420P : 64 | return INPUT_YUV420_INDIV_8; 65 | case AV_PIX_FMT_YUV422P : 66 | return INPUT_YUV422_INDIV_8; 67 | case AV_PIX_FMT_YUV420P16LE : 68 | return INPUT_YUV420_INDIV_16; 69 | case AV_PIX_FMT_YUV422P16LE : 70 | return INPUT_YUV422_INDIV_16; 71 | case AV_PIX_FMT_YUYV422 : 72 | return INPUT_YUV422_BATCH; 73 | default: 74 | printf("unknown format %d, using INPUT_YUV420_INDIV_8\n", pix_fmt); 75 | return INPUT_YUV420_INDIV_8; 76 | } 77 | } 78 | 79 | int initColorConverterY2r(MovieState *mvS) 80 | { 81 | Result res = 0; 82 | res = y2rInit(); 83 | CHECKRES(); 84 | res = Y2RU_StopConversion(); 85 | CHECKRES(); 86 | bool is_busy = 0; 87 | int tries = 0; 88 | do 89 | { 90 | svcSleepThread(100000ull); 91 | res = Y2RU_StopConversion(); 92 | CHECKRES(); 93 | res = Y2RU_IsBusyConversion(&is_busy); 94 | CHECKRES(); 95 | tries += 1; 96 | // printf("is_busy %d\n",is_busy); 97 | } while (is_busy && tries < 100); 98 | 99 | mvS->params.input_format = ffmpegPixelFormatToY2R(mvS->pCodecCtx->pix_fmt); 100 | if (mvS->out_bpp == 3) mvS->params.output_format = OUTPUT_RGB_24; 101 | else if (mvS->out_bpp == 4) mvS->params.output_format = OUTPUT_RGB_32; 102 | mvS->params.rotation = ROTATION_NONE; 103 | mvS->params.block_alignment = BLOCK_8_BY_8; 104 | mvS->params.input_line_width = mvS->pCodecCtx->width; 105 | mvS->params.input_lines = mvS->pCodecCtx->height; 106 | if (mvS->params.input_lines % 8) 107 | { 108 | mvS->params.input_lines += 8 - mvS->params.input_lines % 8; 109 | printf("Height not multiple of 8, cropping to %dpx\n", mvS->params.input_lines); 110 | } 111 | mvS->params.standard_coefficient = COEFFICIENT_ITU_R_BT_601;//TODO : detect 112 | mvS->params.unused = 0; 113 | mvS->params.alpha = 0xFF; 114 | 115 | res = Y2RU_SetConversionParams(&mvS->params); 116 | CHECKRES(); 117 | 118 | res = Y2RU_SetTransferEndInterrupt(true); 119 | CHECKRES(); 120 | mvS->end_event = 0; 121 | res = Y2RU_GetTransferEndEvent(&mvS->end_event); 122 | CHECKRES(); 123 | 124 | 125 | return 0; 126 | } 127 | 128 | 129 | int colorConvertY2R(MovieState *mvS) 130 | { 131 | Result res; 132 | 133 | const u16 img_w = mvS->params.input_line_width; 134 | const u16 img_h = mvS->params.input_lines; 135 | const u32 img_size = img_w * img_h; 136 | 137 | size_t src_Y_size = 0; 138 | size_t src_UV_size = 0; 139 | switch (mvS->params.input_format) 140 | { 141 | case INPUT_YUV422_INDIV_8: 142 | src_Y_size = img_size; 143 | src_UV_size = img_size / 2; 144 | break; 145 | case INPUT_YUV420_INDIV_8: 146 | src_Y_size = img_size; 147 | src_UV_size = img_size / 4; 148 | break; 149 | case INPUT_YUV422_INDIV_16: 150 | src_Y_size = img_size * 2; 151 | src_UV_size = img_size / 2 * 2; 152 | break; 153 | case INPUT_YUV420_INDIV_16: 154 | src_Y_size = img_size * 2; 155 | src_UV_size = img_size / 4 * 2; 156 | break; 157 | case INPUT_YUV422_BATCH: 158 | src_Y_size = img_size * 2; 159 | src_UV_size = img_size * 2; 160 | break; 161 | } 162 | if (mvS->params.input_format == INPUT_YUV422_BATCH) 163 | { 164 | //TODO : test it 165 | assert(mvS->pFrame->linesize[0] >= src_Y_size); 166 | res = Y2RU_SetSendingYUYV(mvS->pFrame->data[0], src_Y_size, img_w, mvS->pFrame->linesize[0] - src_Y_size); 167 | } 168 | else 169 | { 170 | const u8 *src_Y = mvS->pFrame->data[0]; 171 | const u8 *src_U = mvS->pFrame->data[1]; 172 | const u8 *src_V = mvS->pFrame->data[2]; 173 | const u16 src_Y_padding = mvS->pFrame->linesize[0] - img_w; 174 | const u16 src_UV_padding = mvS->pFrame->linesize[1] - (img_w >> 1); 175 | 176 | res = Y2RU_SetSendingY(src_Y, src_Y_size, img_w, src_Y_padding); 177 | CHECKRES(); 178 | res = Y2RU_SetSendingU(src_U, src_UV_size, img_w >> 1, src_UV_padding); 179 | CHECKRES(); 180 | res = Y2RU_SetSendingV(src_V, src_UV_size, img_w >> 1, src_UV_padding); 181 | CHECKRES(); 182 | } 183 | 184 | const u16 out_bpp = mvS->out_bpp; 185 | size_t rgb_size = img_size * out_bpp; 186 | s16 gap = (mvS->outFrame->width - img_w) * 8 * out_bpp; 187 | if (mvS->outFrame->width * 8 * out_bpp >= 0x8000) 188 | { 189 | printf("This image is too wide for y2r.\n"); 190 | return 1; 191 | //TODO : check at setup 192 | } 193 | res = Y2RU_SetReceiving(mvS->outFrame->data[0], rgb_size, img_w * 8 * out_bpp, gap); 194 | CHECKRES(); 195 | res = Y2RU_StartConversion(); 196 | CHECKRES(); 197 | u64 beforeTick = svcGetSystemTick(); 198 | res = svcWaitSynchronization(mvS->end_event, 1000 * 1000 * 10); 199 | u64 afterTick = svcGetSystemTick(); 200 | 201 | #define TICKS_PER_USEC 268.123480 202 | #define TICKS_PER_MSEC 268123.480 203 | if (res) 204 | { 205 | printf("outdim %d unitsize %d gap %d\n", mvS->outFrame->width * 8 * out_bpp, img_w * 8 * out_bpp, gap); 206 | printf("svcWaitSynchronization %lx\n", res); 207 | } 208 | // else printf("waited %lf\n",u64_to_double(afterTick-beforeTick)/TICKS_PER_USEC); 209 | 210 | return 0; 211 | } 212 | 213 | int exitColorConvertY2R(MovieState *mvS) 214 | { 215 | Result res = 0; 216 | bool is_busy = 0; 217 | 218 | Y2RU_StopConversion(); 219 | Y2RU_IsBusyConversion(&is_busy); 220 | y2rExit(); 221 | return 0; 222 | } 223 | 224 | 225 | int initColorConverter(MovieState *mvS) 226 | { 227 | switch (mvS->convertColorMethod) 228 | { 229 | default: 230 | case CONVERT_COL_SWSCALE: 231 | return initColorConverterSwscale(mvS); 232 | case CONVERT_COL_Y2R: 233 | return initColorConverterY2r(mvS); 234 | } 235 | } 236 | 237 | 238 | int colorConvert(MovieState *mvS) 239 | { 240 | switch (mvS->convertColorMethod) 241 | { 242 | default: 243 | case CONVERT_COL_SWSCALE: 244 | return colorConvertSwscale(mvS); 245 | case CONVERT_COL_Y2R: 246 | return colorConvertY2R(mvS); 247 | } 248 | } 249 | 250 | int exitColorConvert(MovieState *mvS) 251 | { 252 | switch (mvS->convertColorMethod) 253 | { 254 | default: 255 | case CONVERT_COL_SWSCALE: 256 | return exitColorConvertSwscale(mvS); 257 | case CONVERT_COL_Y2R: 258 | return exitColorConvertY2R(mvS); 259 | } 260 | } -------------------------------------------------------------------------------- /source/gpu.c: -------------------------------------------------------------------------------- 1 | /** 2 | *@file gpu.c 3 | *@author Lectem 4 | *@date 11/07/2015 5 | */ 6 | 7 | #include <3ds.h> 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | //TODO clean this crap 14 | 15 | 16 | 17 | typedef struct 18 | { 19 | float x, y; 20 | } vector_2f; 21 | 22 | typedef struct 23 | { 24 | float x, y, z; 25 | } vector_3f; 26 | 27 | typedef struct 28 | { 29 | float r, g, b, a; 30 | } vector_4f; 31 | 32 | typedef struct 33 | { 34 | u8 r, g, b, a; 35 | } vector_4u8; 36 | 37 | typedef struct __attribute__((__packed__)) 38 | { 39 | vector_3f position; 40 | vector_4u8 color; 41 | vector_2f texpos; 42 | } vertex_pos_col; 43 | 44 | #define BG_COLOR_U8 {0xFF,0xFF,0xFF,0xFF} 45 | 46 | static const vertex_pos_col test_mesh[] = 47 | { 48 | {{-1.0f, -1.0f, -0.5f}, BG_COLOR_U8, {1.0f, 0.0f}}, 49 | {{1.0f, -1.0f, -0.5f}, BG_COLOR_U8, {1.0f, 1.0f}}, 50 | {{1.0f, 1.0f, -0.5f}, BG_COLOR_U8, {0.0f, 1.0f}}, 51 | {{-1.0f, 1.0f, -0.5f}, BG_COLOR_U8, {0.0f, 0.0f}}, 52 | }; 53 | 54 | static void *test_data = NULL; 55 | 56 | 57 | void setTexturePart(vertex_pos_col *data, float x, float y, float u, float v) 58 | { 59 | data[0].texpos.x = u; 60 | data[0].texpos.y = y; 61 | 62 | data[1].texpos.x = u; 63 | data[1].texpos.y = v; 64 | 65 | data[2].texpos.x = x; 66 | data[2].texpos.y = v; 67 | 68 | data[3].texpos.x = x; 69 | data[3].texpos.y = y; 70 | 71 | 72 | } 73 | 74 | 75 | #define ABGR8(r, g, b, a) ((((r)&0xFF)<<24) | (((g)&0xFF)<<16) | (((b)&0xFF)<<8) | (((a)&0xFF)<<0)) 76 | 77 | u32 clearColor = ABGR8(0x68, 0xB0, 0xD8, 0xFF); 78 | 79 | #define DISPLAY_TRANSFER_FLAGS \ 80 | (GX_TRANSFER_FLIP_VERT(0) | GX_TRANSFER_OUT_TILED(0) | GX_TRANSFER_RAW_COPY(0) | \ 81 | GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | GX_TRANSFER_OUT_FORMAT(gfxGetScreenFormat(GFX_TOP)) | \ 82 | GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO)) 83 | 84 | 85 | #define GPU_CMD_SIZE 0x40000 86 | 87 | //GPU framebuffer address 88 | u32 *gpuFBuffer = NULL; 89 | //GPU depth buffer address 90 | u32 *gpuDBuffer = NULL; 91 | //GPU command buffers 92 | u32 *gpuCmd = NULL; 93 | 94 | //shader structure 95 | DVLB_s *shader_dvlb; //the header 96 | shaderProgram_s shader; //the program 97 | 98 | 99 | Result projUniformRegister = -1; 100 | Result modelviewUniformRegister = -1; 101 | 102 | //The projection matrix 103 | static float ortho_matrix[4 * 4]; 104 | 105 | void GPU_SetDummyTexEnv(u8 num); 106 | 107 | void gpuEndFrame(); 108 | 109 | 110 | void GPU_SetDummyTexEnv(u8 num) 111 | { 112 | //Don't touch the colors of the previous stages 113 | GPU_SetTexEnv(num, 114 | GPU_TEVSOURCES(GPU_PREVIOUS, 0, 0), 115 | GPU_TEVSOURCES(GPU_PREVIOUS, 0, 0), 116 | GPU_TEVOPERANDS(0, 0, 0), 117 | GPU_TEVOPERANDS(0, 0, 0), 118 | GPU_REPLACE, 119 | GPU_REPLACE, 120 | 0xFFFFFFFF); 121 | } 122 | 123 | 124 | void gpuDisableEverything() 125 | { 126 | 127 | GPU_SetFaceCulling(GPU_CULL_NONE); 128 | //No stencil test 129 | GPU_SetStencilTest(false, GPU_ALWAYS, 0x00, 0xFF, 0x00); 130 | GPU_SetStencilOp(GPU_STENCIL_KEEP, GPU_STENCIL_KEEP, GPU_STENCIL_KEEP); 131 | //No blending color 132 | GPU_SetBlendingColor(0, 0, 0, 0); 133 | //Fake disable AB. We just ignore the Blending part 134 | GPU_SetAlphaBlending( 135 | GPU_BLEND_ADD, 136 | GPU_BLEND_ADD, 137 | GPU_ONE, GPU_ZERO, 138 | GPU_ONE, GPU_ZERO 139 | ); 140 | 141 | GPU_SetAlphaTest(false, GPU_ALWAYS, 0x00); 142 | 143 | GPU_SetDepthTestAndWriteMask(true, GPU_ALWAYS, GPU_WRITE_ALL); 144 | GPUCMD_AddMaskedWrite(GPUREG_EARLYDEPTH_TEST1, 0x1, 0); 145 | GPUCMD_AddWrite(GPUREG_EARLYDEPTH_TEST2, 0); 146 | 147 | GPU_SetDummyTexEnv(0); 148 | GPU_SetDummyTexEnv(1); 149 | GPU_SetDummyTexEnv(2); 150 | GPU_SetDummyTexEnv(3); 151 | GPU_SetDummyTexEnv(4); 152 | GPU_SetDummyTexEnv(5); 153 | } 154 | 155 | void gpuInit() 156 | { 157 | test_data = linearAlloc(sizeof(test_mesh)); //allocate our vbo on the linear heap 158 | memcpy(test_data, test_mesh, sizeof(test_mesh)); //Copy our data 159 | //Allocate the GPU render buffers 160 | gpuFBuffer = vramMemAlign(400 * 240 * 4 * 2 * 2, 0x100); 161 | gpuDBuffer = vramMemAlign(400 * 240 * 4 * 2 * 2, 0x100); 162 | 163 | 164 | //In this example we are only rendering in "2D mode", so we don't need one command buffer per eye 165 | gpuCmd = linearAlloc(GPU_CMD_SIZE * (sizeof *gpuCmd)); //Don't forget that commands size is 4 (hence the sizeof) 166 | 167 | GPU_Init(NULL);//initialize GPU 168 | 169 | gfxSet3D(false);//We will not be using the 3D mode in this example 170 | Result res = 0; 171 | 172 | 173 | //Reset the gpu 174 | //This actually needs a command buffer to work, and will then use it as default 175 | GPU_Reset(NULL, gpuCmd, GPU_CMD_SIZE); 176 | 177 | /** 178 | * Load our vertex shader and its uniforms 179 | * Check http://3dbrew.org/wiki/SHBIN for more informations about the shader binaries 180 | */ 181 | shader_dvlb = DVLB_ParseFile((u32 *) shader_shbin, shader_shbin_size);//load our vertex shader binary 182 | shaderProgramInit(&shader); 183 | res = shaderProgramSetVsh(&shader, &shader_dvlb->DVLE[0]); 184 | 185 | projUniformRegister = shaderInstanceGetUniformLocation(shader.vertexShader, "projection"); 186 | 187 | 188 | shaderProgramUse(&shader); // Select the shader to use 189 | 190 | 191 | 192 | initOrthographicMatrix(ortho_matrix, 0.0f, 240.0f, 0.0f, 400.0f, 0.0f, 1.0f); // A basic projection for 2D drawings 193 | SetUniformMatrix(projUniformRegister, ortho_matrix); // Upload the matrix to the GPU 194 | 195 | 196 | gpuDisableEverything(); 197 | gpuEndFrame(); 198 | } 199 | 200 | void gpuExit() 201 | { 202 | 203 | if (test_data) 204 | { 205 | linearFree(test_data); 206 | } 207 | //do things properly 208 | linearFree(gpuCmd); 209 | vramFree(gpuDBuffer); 210 | vramFree(gpuFBuffer); 211 | shaderProgramFree(&shader); 212 | DVLB_Free(shader_dvlb); 213 | GPU_Reset(NULL, gpuCmd, GPU_CMD_SIZE); // Not really needed, but safer for the next applications ? 214 | } 215 | 216 | void gpuEndFrame() 217 | { 218 | //Ask the GPU to draw everything (execute the commands) 219 | GPU_FinishDrawing(); 220 | GPUCMD_Finalize(); 221 | GPUCMD_FlushAndRun(); 222 | gspWaitForP3D();//Wait for the gpu 3d processing to be done 223 | //Copy the GPU output buffer to the screen framebuffer 224 | //See http://3dbrew.org/wiki/GPU#Transfer_Engine for more details about the transfer engine 225 | Result res = GX_DisplayTransfer(gpuFBuffer, GX_BUFFER_DIM(240, 400), 226 | (u32 *) gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL), 227 | GX_BUFFER_DIM(240, 400), 228 | DISPLAY_TRANSFER_FLAGS); 229 | if (!res)gspWaitForPPF(); 230 | 231 | gfxSwapBuffersGpu(); 232 | 233 | //Wait for the screen to be updated 234 | gspWaitForEvent(GSPGPU_EVENT_VBlank0, false); 235 | //TODO : use gspWaitForEvent(GSPEVENT_VBlank0,true); if tearing happens 236 | 237 | //Clear the screen 238 | GX_MemoryFill(gpuFBuffer, clearColor, &gpuFBuffer[400 * 240], GX_FILL_TRIGGER | GX_FILL_32BIT_DEPTH, 239 | gpuDBuffer, 0x00000000, &gpuDBuffer[400 * 240], GX_FILL_TRIGGER | GX_FILL_32BIT_DEPTH); 240 | gspWaitForPSC0(); 241 | 242 | //Get ready to start a new frame 243 | GPUCMD_SetBufferOffset(0); 244 | //Viewport (http://3dbrew.org/wiki/GPU_Commands#Command_0x0041) 245 | GPU_SetViewport((u32 *) osConvertVirtToPhys((u32) gpuDBuffer), 246 | (u32 *) osConvertVirtToPhys((u32) gpuFBuffer), 247 | 0, 0, 248 | //Our screen is 400*240, but the GPU actually renders to 400*480 and then downscales it SetDisplayTransfer bit 24 is set 249 | //This is the case here (See http://3dbrew.org/wiki/GPU#0x1EF00C10 for more details) 250 | 240, 400); 251 | 252 | } 253 | 254 | 255 | void gpuRenderFrame(MovieState *mvS) 256 | { 257 | GPU_SetTextureEnable(GPU_TEXUNIT0); 258 | 259 | GPU_SetTexture( 260 | GPU_TEXUNIT0, 261 | (u32 *) osConvertVirtToPhys((u32) mvS->outFrame->data[0]), 262 | // width and height swapped? 263 | mvS->outFrame->width, 264 | mvS->outFrame->height, 265 | //GPU_TEXTURE_MAG_FILTER(GPU_NEAREST) | GPU_TEXTURE_MIN_FILTER(GPU_NEAREST) | 266 | GPU_TEXTURE_WRAP_S(1) | GPU_TEXTURE_WRAP_T(1), 267 | GPU_RGBA8 268 | ); 269 | GPUCMD_AddWrite(GPUREG_TEXUNIT0_BORDER_COLOR, 0xFFFF0000); 270 | 271 | int texenvnum = 0; 272 | GPU_SetTexEnv( 273 | texenvnum, 274 | GPU_TEVSOURCES(GPU_TEXTURE0, GPU_TEXTURE0, 0), 275 | GPU_TEVSOURCES(GPU_TEXTURE0, GPU_TEXTURE0, 0), 276 | GPU_TEVOPERANDS(0, 0, 0), 277 | GPU_TEVOPERANDS(0, 0, 0), 278 | GPU_REPLACE, GPU_REPLACE, 279 | 0xAABBCCDD 280 | ); 281 | 282 | setTexturePart(test_data, 0.0, 1.0f - mvS->pCodecCtx->height / (float) mvS->outFrame->height, 283 | mvS->pCodecCtx->width / (float) mvS->outFrame->width, 1.0f); 284 | // setTexturePart(test_data,0.0,0.0,1.0,1.0); 285 | GPU_SetAttributeBuffers( 286 | 3, // number of attributes 287 | (u32 *) osConvertVirtToPhys((u32) test_data), 288 | GPU_ATTRIBFMT(0, 3, GPU_FLOAT) | GPU_ATTRIBFMT(1, 4, GPU_UNSIGNED_BYTE) | GPU_ATTRIBFMT(2, 2, GPU_FLOAT), 289 | 0xFFF8,//Attribute mask, in our case 0b1110 since we use only the first one 290 | 0x210,//Attribute permutations (here it is the identity) 291 | 1, //number of buffers 292 | (u32[]) {0x0}, // buffer offsets (placeholders) 293 | (u64[]) {0x210}, // attribute permutations for each buffer (identity again) 294 | (u8[]) {3} // number of attributes for each buffer 295 | ); 296 | 297 | //Display the buffers data 298 | GPU_DrawArray(GPU_TRIANGLE_FAN,0, sizeof(test_mesh) / sizeof(test_mesh[0])); 299 | 300 | } -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /cmake/Tools3DS.cmake: -------------------------------------------------------------------------------- 1 | ############################################################################ 2 | # Various macros for 3DS homebrews tools 3 | # 4 | # add_3dsx_target 5 | # ^^^^^^^^^^^^^^^ 6 | # 7 | # This macro has two signatures : 8 | # 9 | # ## add_3dsx_target(target [NO_SMDH]) 10 | # 11 | # Adds a target that generates a .3dsx file from `target`. If NO_SMDH is specified, no .smdh file will be generated. 12 | # 13 | # You can set the following variables to change the SMDH file : 14 | # 15 | # * APP_TITLE is the name of the app stored in the SMDH file (Optional) 16 | # * APP_DESCRIPTION is the description of the app stored in the SMDH file (Optional) 17 | # * APP_AUTHOR is the author of the app stored in the SMDH file (Optional) 18 | # * APP_ICON is the filename of the icon (.png), relative to the project folder. 19 | # If not set, it attempts to use one of the following (in this order): 20 | # - $(target).png 21 | # - icon.png 22 | # - $(libctru folder)/default_icon.png 23 | # 24 | # ## add_3dsx_target(target APP_TITLE APP_DESCRIPTION APP_AUTHOR [APP_ICON]) 25 | # 26 | # This version will produce the SMDH with tha values passed as arguments. Tha APP_ICON is optional and follows the same rule as the other version of `add_3dsx_target`. 27 | # 28 | # add_cia_target(target RSF IMAGE SOUND [APP_TITLE APP_DESCRIPTION APP_AUTHOR [APP_ICON]]) 29 | # ^^^^^^^^^^^^^^ 30 | # 31 | # Same as add_3dsx_target but for CIA files. 32 | # 33 | # RSF is the .rsf file to be given to makerom. 34 | # IMAGE is either a .png or a cgfximage file. 35 | # SOUND is either a .wav or a cwavaudio file. 36 | # 37 | # add_netload_target(name target_or_file) 38 | # ^^^^^^^^^^^^^^^^^^ 39 | # 40 | # Adds a target `name` that sends a .3dsx using the homebrew launcher netload system (3dslink). 41 | # target_or_file is either the name of a target or of file. 42 | # 43 | # add_binary_library(target input1 [input2 ...]) 44 | # ^^^^^^^^^^^^^^^^^^ 45 | # 46 | # /!\ Requires ASM to be enabled ( `enable_language(ASM)` or `project(yourprojectname C CXX ASM)`) 47 | # 48 | # Converts the files given as input to arrays of their binary data. This is useful to embed resources into your project. 49 | # For example, logo.bmp will generate the array `u8 logo_bmp[]` and its size `logo_bmp_size`. By linking this library, you 50 | # will also have access to a generated header file called `logo_bmp.h` which contains the declarations you need to use it. 51 | # 52 | # Note : All dots in the filename are converted to `_`, and if it starts with a number, `_` will be prepended. 53 | # For example 8x8.gas.tex would give the name _8x8_gas_tex. 54 | # 55 | # target_embed_file(target input1 [input2 ...]) 56 | # ^^^^^^^^^^^^^^^^^ 57 | # 58 | # Same as add_binary_library(tempbinlib input1 [input2 ...]) + target_link_libraries(target tempbinlib) 59 | # 60 | # add_shbin(output input [entrypoint] [shader_type]) 61 | # ^^^^^^^^^^^^^^^^^^^^^^^ 62 | # 63 | # Assembles the shader given as `input` into the file `output`. No file extension is added. 64 | # You can choose the shader assembler by setting SHADER_AS to `picasso` or `nihstro`. 65 | # 66 | # If `nihstro` is set as the assembler, entrypoint and shader_type will be used. 67 | # entrypoint is set to `main` by default 68 | # shader_type can be either VSHADER or GSHADER. By default it is VSHADER. 69 | # 70 | # generate_shbins(input1 [input2 ...]) 71 | # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 72 | # 73 | # Assemble all the shader files given as input into .shbin files. Those will be located in the folder `shaders` of the build directory. 74 | # The names of the output files will be .shbin. vshader.pica will output shader.shbin but shader.vertex.pica will output shader.shbin too. 75 | # 76 | # add_shbin_library(target input1 [input2 ...]) 77 | # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 78 | # 79 | # /!\ Requires ASM to be enabled ( `enable_language(ASM)` or `project(yourprojectname C CXX ASM)`) 80 | # 81 | # This is the same as calling generate_shbins and add_binary_library. This is the function to be used to reproduce devkitArm makefiles behaviour. 82 | # For example, add_shbin_library(shaders data/my1stshader.vsh.pica) will generate the target library `shaders` and you 83 | # will be able to use the shbin in your program by linking it, including `my1stshader_pica.h` and using `my1stshader_pica[]` and `my1stshader_pica_size`. 84 | # 85 | # target_embed_shader(target input1 [input2 ...]) 86 | # ^^^^^^^^^^^^^^^^^ 87 | # 88 | # Same as add_shbin_library(tempbinlib input1 [input2 ...]) + target_link_libraries(target tempbinlib) 89 | # 90 | ############################################################################ 91 | 92 | if(NOT 3DS) 93 | message(WARNING "Those tools can only be used if you are using the 3DS toolchain file. Please erase this build directory or create another one, and then use -DCMAKE_TOOLCHAIN_FILE=DevkitArm3DS.cmake when calling cmake for the 1st time. For more information, see the Readme.md for more information.") 94 | endif() 95 | 96 | get_filename_component(__tools3dsdir ${CMAKE_CURRENT_LIST_FILE} PATH) # Used to locate files to be used with configure_file 97 | 98 | message(STATUS "Looking for 3ds tools...") 99 | 100 | ############## 101 | ## 3DSXTOOL ## 102 | ############## 103 | if(NOT _3DSXTOOL) 104 | # message(STATUS "Looking for 3dsxtool...") 105 | find_program(_3DSXTOOL 3dsxtool ${DEVKITARM}/bin) 106 | if(_3DSXTOOL) 107 | message(STATUS "3dsxtool: ${_3DSXTOOL} - found") 108 | else() 109 | message(WARNING "3dsxtool - not found") 110 | endif() 111 | endif() 112 | 113 | 114 | ############## 115 | ## SMDHTOOL ## 116 | ############## 117 | if(NOT SMDHTOOL) 118 | # message(STATUS "Looking for smdhtool...") 119 | find_program(SMDHTOOL smdhtool ${DEVKITARM}/bin) 120 | if(SMDHTOOL) 121 | message(STATUS "smdhtool: ${SMDHTOOL} - found") 122 | else() 123 | message(WARNING "smdhtool - not found") 124 | endif() 125 | endif() 126 | 127 | ################ 128 | ## BANNERTOOL ## 129 | ################ 130 | if(NOT BANNERTOOL) 131 | # message(STATUS "Looking for bannertool...") 132 | find_program(BANNERTOOL bannertool ${DEVKITARM}/bin) 133 | if(BANNERTOOL) 134 | message(STATUS "bannertool: ${BANNERTOOL} - found") 135 | else() 136 | message(WARNING "bannertool - not found") 137 | endif() 138 | endif() 139 | 140 | set(FORCE_SMDHTOOL FALSE CACHE BOOL "Force the use of smdhtool instead of bannertool") 141 | 142 | ############# 143 | ## MAKEROM ## 144 | ############# 145 | if(NOT MAKEROM) 146 | # message(STATUS "Looking for makerom...") 147 | find_program(MAKEROM makerom ${DEVKITARM}/bin) 148 | if(MAKEROM) 149 | message(STATUS "makerom: ${MAKEROM} - found") 150 | else() 151 | message(WARNING "makerom - not found") 152 | endif() 153 | endif() 154 | 155 | 156 | 157 | ############# 158 | ## STRIP ## 159 | ############# 160 | if(NOT STRIP) 161 | # message(STATUS "Looking for strip...") 162 | find_program(STRIP arm-none-eabi-strip ${DEVKITARM}/bin) 163 | if(STRIP) 164 | message(STATUS "strip: ${STRIP} - found") 165 | else() 166 | message(WARNING "strip - not found") 167 | endif() 168 | endif() 169 | 170 | 171 | 172 | ############# 173 | ## BIN2S ## 174 | ############# 175 | if(NOT BIN2S) 176 | # message(STATUS "Looking for bin2s...") 177 | find_program(BIN2S bin2s ${DEVKITARM}/bin) 178 | if(BIN2S) 179 | message(STATUS "bin2s: ${BIN2S} - found") 180 | else() 181 | message(WARNING "bin2s - not found") 182 | endif() 183 | endif() 184 | 185 | ############### 186 | ## 3DSLINK ## 187 | ############### 188 | if(NOT _3DSLINK) 189 | # message(STATUS "Looking for 3dslink...") 190 | find_program(_3DSLINK 3dslink ${DEVKITARM}/bin) 191 | if(_3DSLINK) 192 | message(STATUS "3dslink: ${_3DSLINK} - found") 193 | else() 194 | message(WARNING "3dslink - not found") 195 | endif() 196 | endif() 197 | 198 | ############# 199 | ## PICASSO ## 200 | ############# 201 | if(NOT PICASSO_EXE) 202 | # message(STATUS "Looking for Picasso...") 203 | find_program(PICASSO_EXE picasso ${DEVKITARM}/bin) 204 | if(PICASSO_EXE) 205 | message(STATUS "Picasso: ${PICASSO_EXE} - found") 206 | set(SHADER_AS picasso CACHE STRING "The shader assembler to be used. Allowed values are 'none', 'picasso' or 'nihstro'") 207 | else() 208 | message(STATUS "Picasso - not found") 209 | endif() 210 | endif() 211 | 212 | 213 | ############# 214 | ## NIHSTRO ## 215 | ############# 216 | 217 | if(NOT NIHSTRO_AS) 218 | # message(STATUS "Looking for nihstro...") 219 | find_program(NIHSTRO_AS nihstro ${DEVKITARM}/bin) 220 | if(NIHSTRO_AS) 221 | message(STATUS "nihstro: ${NIHSTRO_AS} - found") 222 | set(SHADER_AS nihstro CACHE STRING "The shader assembler to be used. Allowed values are 'none', 'picasso' or 'nihstro'") 223 | else() 224 | message(STATUS "nihstro - not found") 225 | endif() 226 | endif() 227 | 228 | set(SHADER_AS none CACHE STRING "The shader assembler to be used. Allowed values are 'none', 'picasso' or 'nihstro'") 229 | 230 | ############################### 231 | ############################### 232 | ######## MACROS ######### 233 | ############################### 234 | ############################### 235 | 236 | 237 | ################### 238 | ### EXECUTABLES ### 239 | ################### 240 | 241 | 242 | function(__add_smdh target APP_TITLE APP_DESCRIPTION APP_AUTHOR APP_ICON) 243 | if(BANNERTOOL AND NOT FORCE_SMDHTOOL) 244 | set(__SMDH_COMMAND ${BANNERTOOL} makesmdh -s ${APP_TITLE} -l ${APP_DESCRIPTION} -p ${APP_AUTHOR} -i ${APP_ICON} -o ${CMAKE_CURRENT_BINARY_DIR}/${target}) 245 | else() 246 | set(__SMDH_COMMAND ${SMDHTOOL} --create ${APP_TITLE} ${APP_DESCRIPTION} ${APP_AUTHOR} ${APP_ICON} ${CMAKE_CURRENT_BINARY_DIR}/${target}) 247 | endif() 248 | add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${target} 249 | COMMAND ${__SMDH_COMMAND} 250 | WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} 251 | DEPENDS ${APP_ICON} 252 | VERBATIM 253 | ) 254 | endfunction() 255 | 256 | function(add_3dsx_target target) 257 | get_filename_component(target_we ${target} NAME_WE) 258 | if((NOT (${ARGC} GREATER 1 AND "${ARGV1}" STREQUAL "NO_SMDH") ) OR (${ARGC} GREATER 3) ) 259 | if(${ARGC} GREATER 3) 260 | set(APP_TITLE ${ARGV1}) 261 | set(APP_DESCRIPTION ${ARGV2}) 262 | set(APP_AUTHOR ${ARGV3}) 263 | endif() 264 | if(${ARGC} EQUAL 5) 265 | set(APP_ICON ${ARGV4}) 266 | endif() 267 | if(NOT APP_TITLE) 268 | set(APP_TITLE ${target}) 269 | endif() 270 | if(NOT APP_DESCRIPTION) 271 | set(APP_DESCRIPTION "Built with devkitARM & libctru") 272 | endif() 273 | if(NOT APP_AUTHOR) 274 | set(APP_AUTHOR "Unspecified Author") 275 | endif() 276 | if(NOT APP_ICON) 277 | if(EXISTS ${target}.png) 278 | set(APP_ICON ${target}.png) 279 | elseif(EXISTS icon.png) 280 | set(APP_ICON icon.png) 281 | elseif(CTRULIB) 282 | set(APP_ICON ${CTRULIB}/default_icon.png) 283 | else() 284 | message(FATAL_ERROR "No icon found ! Please use NO_SMDH or provide some icon.") 285 | endif() 286 | endif() 287 | if( NOT ${target_we}.smdh) 288 | __add_smdh(${target_we}.smdh ${APP_TITLE} ${APP_DESCRIPTION} ${APP_AUTHOR} ${APP_ICON}) 289 | endif() 290 | add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${target_we}.3dsx 291 | COMMAND ${_3DSXTOOL} $ ${CMAKE_CURRENT_BINARY_DIR}/${target_we}.3dsx --smdh=${CMAKE_CURRENT_BINARY_DIR}/${target_we}.smdh 292 | DEPENDS ${target} ${CMAKE_CURRENT_BINARY_DIR}/${target_we}.smdh 293 | VERBATIM 294 | ) 295 | else() 296 | message(STATUS "No smdh file will be generated") 297 | add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${target_we}.3dsx 298 | COMMAND ${_3DSXTOOL} $ ${CMAKE_CURRENT_BINARY_DIR}/${target_we}.3dsx 299 | DEPENDS ${target} 300 | VERBATIM 301 | ) 302 | endif() 303 | add_custom_target(${target_we}_3dsx ALL SOURCES ${CMAKE_CURRENT_BINARY_DIR}/${target_we}.3dsx) 304 | set_target_properties(${target} PROPERTIES LINK_FLAGS "-specs=3dsx.specs") 305 | endfunction() 306 | 307 | function(__add_ncch_banner target IMAGE SOUND) 308 | if(IMAGE MATCHES ".*\\.png$") 309 | set(IMG_PARAM -i ${IMAGE}) 310 | else() 311 | set(IMG_PARAM -ci ${IMAGE}) 312 | endif() 313 | if(SOUND MATCHES ".*\\.wav$") 314 | set(SND_PARAM -a ${SOUND}) 315 | else() 316 | set(SND_PARAM -ca ${SOUND}) 317 | endif() 318 | add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${target} 319 | COMMAND ${BANNERTOOL} makebanner -o ${CMAKE_CURRENT_BINARY_DIR}/${target} ${IMG_PARAM} ${SND_PARAM} 320 | WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} 321 | DEPENDS ${IMAGE} ${SOUND} 322 | VERBATIM 323 | ) 324 | endfunction() 325 | 326 | function(add_cia_target target RSF IMAGE SOUND ) 327 | get_filename_component(target_we ${target} NAME_WE) 328 | if(${ARGC} GREATER 6) 329 | set(APP_TITLE ${ARGV4}) 330 | set(APP_DESCRIPTION ${ARGV5}) 331 | set(APP_AUTHOR ${ARGV6}) 332 | endif() 333 | if(${ARGC} EQUAL 8) 334 | set(APP_ICON ${ARGV7}) 335 | endif() 336 | if(NOT APP_TITLE) 337 | set(APP_TITLE ${target}) 338 | endif() 339 | if(NOT APP_DESCRIPTION) 340 | set(APP_DESCRIPTION "Built with devkitARM & libctru") 341 | endif() 342 | if(NOT APP_AUTHOR) 343 | set(APP_AUTHOR "Unspecified Author") 344 | endif() 345 | if(NOT APP_ICON) 346 | if(EXISTS ${target}.png) 347 | set(APP_ICON ${target}.png) 348 | elseif(EXISTS icon.png) 349 | set(APP_ICON icon.png) 350 | elseif(CTRULIB) 351 | set(APP_ICON ${CTRULIB}/default_icon.png) 352 | else() 353 | message(FATAL_ERROR "No icon found ! Please use NO_SMDH or provide some icon.") 354 | endif() 355 | endif() 356 | if( NOT ${target_we}.smdh) 357 | __add_smdh(${target_we}.smdh ${APP_TITLE} ${APP_DESCRIPTION} ${APP_AUTHOR} ${APP_ICON}) 358 | endif() 359 | __add_ncch_banner(${target_we}.bnr ${IMAGE} ${SOUND}) 360 | add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${target_we}.cia 361 | COMMAND ${STRIP} -o $-stripped $ 362 | COMMAND ${MAKEROM} -f cia 363 | -target t 364 | -exefslogo 365 | -o ${CMAKE_CURRENT_BINARY_DIR}/${target_we}.cia 366 | -elf $-stripped 367 | -rsf ${RSF} 368 | -banner ${CMAKE_CURRENT_BINARY_DIR}/${target_we}.bnr 369 | -icon ${CMAKE_CURRENT_BINARY_DIR}/${target_we}.smdh 370 | DEPENDS ${target} ${RSF} ${CMAKE_CURRENT_BINARY_DIR}/${target_we}.bnr ${CMAKE_CURRENT_BINARY_DIR}/${target_we}.smdh 371 | WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} 372 | VERBATIM 373 | ) 374 | 375 | add_custom_target(${target_we}_cia ALL SOURCES ${CMAKE_CURRENT_BINARY_DIR}/${target_we}.cia) 376 | set_target_properties(${target} PROPERTIES LINK_FLAGS "-specs=3dsx.specs") 377 | endfunction() 378 | 379 | macro(add_netload_target name target) 380 | set(NETLOAD_IP "" CACHE STRING "The ip address of the 3ds when using netload.") 381 | if(NETLOAD_IP) 382 | set(__NETLOAD_IP_OPTION -a ${NETLOAD_IP}) 383 | endif() 384 | if(NOT TARGET ${target}) 385 | message("NOT ${target}") 386 | set(FILE ${target}) 387 | else() 388 | set(FILE ${CMAKE_CURRENT_BINARY_DIR}/${target}.3dsx) 389 | endif() 390 | add_custom_target(${name} 391 | COMMAND ${_3DSLINK} ${FILE} ${__NETLOAD_IP_OPTION} 392 | DEPENDS ${FILE} 393 | ) 394 | endmacro() 395 | 396 | ###################### 397 | ### File embedding ### 398 | ###################### 399 | 400 | macro(add_binary_library libtarget) 401 | if(NOT ${ARGC} GREATER 1) 402 | message(FATAL_ERROR "add_binary_library : Argument error (no input files)") 403 | endif() 404 | get_cmake_property(ENABLED_LANGUAGES ENABLED_LANGUAGES) 405 | if(NOT ENABLED_LANGUAGES MATCHES ".*ASM.*") 406 | message(FATAL_ERROR "You have to enable ASM in order to use add_shader_library. Use enable_language(ASM). Currently enabled languages are ${ENABLED_LANGUAGES}") 407 | endif() 408 | 409 | 410 | foreach(__file ${ARGN}) 411 | get_filename_component(__file_wd ${__file} NAME) 412 | string(REGEX REPLACE "^([0-9])" "_\\1" __BIN_FILE_NAME ${__file_wd}) # add '_' if the file name starts by a number 413 | string(REGEX REPLACE "[-./]" "_" __BIN_FILE_NAME ${__BIN_FILE_NAME}) 414 | 415 | #Generate the header file 416 | configure_file(${__tools3dsdir}/bin2s_header.h.in ${CMAKE_CURRENT_BINARY_DIR}/${libtarget}_include/${__BIN_FILE_NAME}.h) 417 | endforeach() 418 | 419 | file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/binaries_asm) 420 | # Generate the assembly file, and create the new target 421 | add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/binaries_asm/${libtarget}.s 422 | COMMAND ${BIN2S} ${ARGN} > ${CMAKE_CURRENT_BINARY_DIR}/binaries_asm/${libtarget}.s 423 | DEPENDS ${ARGN} 424 | WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} 425 | ) 426 | 427 | add_library(${libtarget} ${CMAKE_CURRENT_BINARY_DIR}/binaries_asm/${libtarget}.s) 428 | target_include_directories(${libtarget} INTERFACE ${CMAKE_CURRENT_BINARY_DIR}/${libtarget}_include) 429 | endmacro() 430 | 431 | macro(target_embed_file _target) 432 | if(NOT ${ARGC} GREATER 1) 433 | message(FATAL_ERROR "target_embed_file : Argument error (no input files)") 434 | endif() 435 | get_filename_component(__1st_file_wd ${ARGV1} NAME) 436 | add_binary_library(__${_target}_embed_${__1st_file_wd} ${ARGN}) 437 | target_link_libraries(${_target} __${_target}_embed_${__1st_file_wd}) 438 | endmacro() 439 | 440 | ################### 441 | ##### SHADERS ##### 442 | ################### 443 | 444 | macro(add_shbin OUTPUT INPUT ) 445 | 446 | if(SHADER_AS STREQUAL "picasso") 447 | 448 | if(${ARGC} GREATER 2) 449 | message(WARNING "Picasso doesn't support changing the entrypoint or shader type") 450 | endif() 451 | add_custom_command(OUTPUT ${OUTPUT} COMMAND ${PICASSO_EXE} -o ${OUTPUT} ${INPUT} WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}) 452 | 453 | elseif(SHADER_AS STREQUAL "nihstro") 454 | if(NOT NIHSTRO_AS) 455 | message(SEND_ERROR "SHADER_AS is set to nihstro, but nihstro wasn't found. Please set NIHSTRO_AS.") 456 | endif() 457 | if(${ARGC} GREATER 2) 458 | if(${ARGV2} EQUAL GSHADER) 459 | set(SHADER_TYPE_FLAG "-g") 460 | elseif(NOT ${ARGV2} EQUAL VSHADER) 461 | set(_ENTRYPOINT ${ARGV2}) 462 | endif() 463 | endif() 464 | if(${ARGC} GREATER 3) 465 | if(${ARGV2} EQUAL GSHADER) 466 | set(SHADER_TYPE_FLAG "-g") 467 | elseif(NOT ${ARGV3} EQUAL VSHADER) 468 | set(_ENTRYPOINT ${ARGV3}) 469 | endif() 470 | endif() 471 | if(NOT _ENTRYPOINT) 472 | set(_ENTRYPOINT "main") 473 | endif() 474 | add_custom_command(OUTPUT ${OUTPUT} COMMAND ${NIHSTRO_AS} ${INPUT} -o ${OUTPUT} -e ${_ENTRYPOINT} ${SHADER_TYPE_FLAG} WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}) 475 | 476 | else() 477 | message(FATAL_ERROR "Please set SHADER_AS to 'picasso' or 'nihstro' if you use the shbin feature.") 478 | endif() 479 | 480 | endmacro() 481 | 482 | function(generate_shbins) 483 | file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/shaders) 484 | foreach(__shader_file ${ARGN}) 485 | get_filename_component(__shader_file_we ${__shader_file} NAME_WE) 486 | #Generate the shbin file 487 | list(APPEND __SHADERS_BIN_FILES ${CMAKE_CURRENT_BINARY_DIR}/shaders/${__shader_file_we}.shbin) 488 | add_shbin(${CMAKE_CURRENT_BINARY_DIR}/shaders/${__shader_file_we}.shbin ${__shader_file}) 489 | endforeach() 490 | endfunction() 491 | 492 | function(add_shbin_library libtarget) 493 | file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/shaders) 494 | foreach(__shader_file ${ARGN}) 495 | get_filename_component(__shader_file_we ${__shader_file} NAME_WE) 496 | #Generate the shbin file 497 | list(APPEND __SHADERS_BIN_FILES ${CMAKE_CURRENT_BINARY_DIR}/shaders/${__shader_file_we}.shbin) 498 | add_shbin(${CMAKE_CURRENT_BINARY_DIR}/shaders/${__shader_file_we}.shbin ${__shader_file}) 499 | endforeach() 500 | add_binary_library(${libtarget} ${__SHADERS_BIN_FILES}) 501 | endfunction() 502 | 503 | 504 | macro(target_embed_shader _target) 505 | if(NOT ${ARGC} GREATER 1) 506 | message(FATAL_ERROR "target_embed_shader : Argument error (no input files)") 507 | endif() 508 | get_filename_component(__1st_file_wd ${ARGV1} NAME) 509 | add_shbin_library(__${_target}_embed_${__1st_file_wd} ${ARGN}) 510 | target_link_libraries(${_target} __${_target}_embed_${__1st_file_wd}) 511 | endmacro() 512 | --------------------------------------------------------------------------------