Homebrew [Release] m3diaLib - A C++ library for easier homebrew development for the Nintendo 3DS

Is this needed/would you use it?

  • Yes, definetly

    Votes: 20 60.6%
  • No, definetly not

    Votes: 3 9.1%
  • Maybe, in the future

    Votes: 10 30.3%

  • Total voters
    33

StuntHacks

Well-Known Member
OP
Newcomer
Joined
Jan 19, 2017
Messages
46
Trophies
0
Age
22
Location
Vienna
XP
205
Country
Austria
Over the last year, or so, I've been working on a library for easier 3DS-homebrew development. It's fully written in C++11 and supports sound, graphics and more. Keep in mind, that this library is still in beta. So, if you find any bugs or have any issues, please report them via GitHub.

Useful links:
Features
The m3diaLib (spelled media-lib) is split into multiple modules, which can then be split into smaller parts:

Core
The core module contains all functionality for interacting with the system. Its features range from running and handling the app itself to displaying errors and running system applets.

Its main features are:
  • A class for running your homebrew app
  • Easy interaction with the system itself
  • Starting and running applets
  • Time measurement
  • Support for the RomFS
  • Multithreading and concurrency
Input
The input module does what its name says: It handles each and every input for interacting with the user.

Its main features are:
  • Handling button input
  • Handling touch input
Audio
The audio module can be used for both music and sound effects.
Its main features are:
  • Loading or streaming audio files directly from the file system
  • Support for .wav and .mp3 (more to come!)
  • Two different classes, sound and music, which have features that can be helpful specific in their use case
Graphics
The graphics module is by far the biggest module. It handles anything graphic-wise, from rendering simple shapes to rendering and animating high-quality textures.

Its main features are:
  • Support for the top and bottom screen
  • Support for stereoscopic 3D
  • Easy-to-use interface for fast rendering on both screens
  • Support for transformation of textures and sprites
  • Pre-coded shapes as well as a shape class for easily rendering your own shapes
  • Easy-to-use color system
  • Collision detection
Utils
The utils module contains all kind of useful utilities. Currently, it has the following functionality:
  • Basic encryption


All features are well documented here. Examples can be viewed here.

How to use it
The barebones of a homebrew app using the m3diaLib would look like this:
C++:
#include <m3dia.hpp>

int main() {
    m3d::Applet app;

    while (app.isRunning()) {
        if (m3d::buttons::buttonPressed(m3d::buttons::Button::Start)) {
            app.exit(); // exit if start is pressed
        }
    }
}

Easy, isn't it?


Planned features
Audio:
  • Microphone support
  • More file formats
Core:
  • Support for all availiable os and system functionality
Graphics:
  • Animation
  • RenderTargets
  • More file formats for textures
  • 3D support
Networking:
This module isn't availiable at the moment. However, it's planned features are:
  • A simple HTTP and WebSocket client and server
  • Socket support
  • A 3DS-download-game alternative (more on that at a later point)
Utils:
  • ZIP compression and decompression
  • JSON and XML parsing
  • Secure random numbers
...and anything that strikes my mind in the future.

Installation
To install the library, download the latest release-build and execute the command
Code:
make install
.

To build it from the source, download the latest release and then execute the following commands:
Code:
make
make install
Dependencies
To compile a m3diaLib-app, you need the following dependencies installed (install via devkitPro-pacman):
  • libctru
  • citro3d
  • citro2d
  • 3ds-tinyxml2
  • 3ds-zlib
  • 3ds-mpg123
  • 3ds-libpng
  • 3ds-freetype
  • tex3ds (if you want to use spritesheets)
Credits
 
Last edited by StuntHacks,

StuntHacks

Well-Known Member
OP
Newcomer
Joined
Jan 19, 2017
Messages
46
Trophies
0
Age
22
Location
Vienna
XP
205
Country
Austria
This may bring more developers to the 3DS scene. This looks a lot simpler than using libctru directly tbh. I'ma give it a go!
That was indeed my intention. The latest release now added 3D support as well as a few other new features and I'm already working in the next release! I'd love to see what you create with it!
 

bennyman123abc

Well-Known Member
Member
Joined
Mar 21, 2013
Messages
918
Trophies
0
Age
20
Location
Alton, IL
XP
1,073
Country
United States
That was indeed my intention. The latest release now added 3D support as well as a few other new features and I'm already working in the next release! I'd love to see what you create with it!
The issue I'm experiencing is that this lib doesn't work with 11.8. It crashes when loading any homebrew written with it; including all of the examples. I can provide a Luma3DS stack trace if you'd like.
 

StuntHacks

Well-Known Member
OP
Newcomer
Joined
Jan 19, 2017
Messages
46
Trophies
0
Age
22
Location
Vienna
XP
205
Country
Austria
The issue I'm experiencing is that this lib doesn't work with 11.8. It crashes when loading any homebrew written with it; including all of the examples. I can provide a Luma3DS stack trace if you'd like.
Please, report it via GitHub. Please also include your Luma version and any other information that could be relevant, such as whether you are using a N3DS or not.
 
Last edited by StuntHacks,

KyoIsHacking

Well-Known Member
Member
Joined
Jun 17, 2018
Messages
113
Trophies
0
Age
20
XP
412
Country
Austria
I can't get my app with m3diaLib to compile, it always says:
Code:
C:/devkitPro/portlibs/3ds/include/m3d/audio/music.hpp:10:10: fatal error: atomic: No such file or directory
 #include <atomic>
even though that file (atomic) is in the IncludePath of Visual Studio Community 2017, which i'm using.

I hope this is the right place to post about this but I can't find any errors on my side, so..
Does anyone know what could be wrong?
Thanks in advance.

(edit because i wanted to add some things i forgot to say)
 
Last edited by KyoIsHacking,

StuntHacks

Well-Known Member
OP
Newcomer
Joined
Jan 19, 2017
Messages
46
Trophies
0
Age
22
Location
Vienna
XP
205
Country
Austria
I can't get my app with m3diaLib to compile, it always says:
Code:
C:/devkitPro/portlibs/3ds/include/m3d/audio/music.hpp:10:10: fatal error: atomic: No such file or directory
 #include <atomic>
even though that file (atomic) is in the IncludePath of Visual Studio Community 2017, which i'm using.

I hope this is the right place to post about this but I can't find any errors on my side, so..
Does anyone know what could be wrong?
Thanks in advance.

(edit because i wanted to add some things i forgot to say)

Are you using the Makefile from the m3dctr-examples? If not, can you show me your current Makefile?

Also, that error should only happen when you try to build the m3diaLib itself, not a project that uses it.
 

KyoIsHacking

Well-Known Member
Member
Joined
Jun 17, 2018
Messages
113
Trophies
0
Age
20
XP
412
Country
Austria
Are you using the Makefile from the m3dctr-examples? If not, can you show me your current Makefile?

Also, that error should only happen when you try to build the m3diaLib itself, not a project that uses it.
I'm sorry that I didn't answer earlier, I used this one (yes i was playing around with the homebrew launcher):
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------

ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif

TOPDIR ?= $(CURDIR)
include $(DEVKITARM)/3ds_rules


export VER_MAJOR := 2
export VER_MINOR := 0
export VER_PATCH := 0

export VERSTRING := v$(VER_MAJOR).$(VER_MINOR).$(VER_PATCH)
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
# GRAPHICS is a list of directories containing graphics files
# GFXBUILD is the directory where converted graphics files will be placed
# If set to $(BUILD), it will statically link in the converted
# files as if they were data files.
#
# NO_SMDH: if set to anything, no SMDH file is generated.
# ROMFS is the directory which contains the RomFS, relative to the Makefile (Optional)
# APP_TITLE is the name of the app stored in the SMDH file (Optional)
# APP_DESCRIPTION is the description of the app stored in the SMDH file (Optional)
# APP_AUTHOR is the author of the app stored in the SMDH file (Optional)
# ICON is the filename of the icon (.png), relative to the project folder.
# If not set, it attempts to use one of the following (in this order):
# - <Project name>.png
# - icon.png
# - <libctru folder>/default_icon.png
#---------------------------------------------------------------------------------
TARGET := boot
BUILD := build
SOURCES := source source/ui source/parsing source/loaders $(sort $(dir $(wildcard source/*/)))
DATA := data
INCLUDES := include $(sort $(dir $(wildcard includes/*/)))
GRAPHICS := gfx
ROMFS := romfs
GFXBUILD := $(ROMFS)/gfx

APP_TITLE := Homebrew Menu $(VERSTRING)
APP_DESCRIPTION := Nintendo 3DS Homebrew Launcher
APP_AUTHOR := hbmenu team

#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft

CFLAGS := -g -Wall -O2 -mword-relocations \
-fomit-frame-pointer -ffunction-sections \
$(ARCH)

CFLAGS += $(INCLUDE) -DARM11 -D_3DS -DVERSION=\"$(VERSTRING)\"

CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11

ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)

LIBS := -lm3dia -lcitro3d -lctru -lm -lz -ltinyxml2 -lcitro2d -lmpg123

#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(PORTLIBS) $(CTRULIB)


#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------

export OUTPUT := $(CURDIR)/$(TARGET)
export TOPDIR := $(CURDIR)

export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(GRAPHICS),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))

export DEPSDIR := $(CURDIR)/$(BUILD)

CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
PICAFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.v.pica)))
SHLISTFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.shlist)))
GFXFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.t3s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))

#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------

#---------------------------------------------------------------------------------
ifeq ($(GFXBUILD),$(BUILD))
#---------------------------------------------------------------------------------
export T3XFILES := $(GFXFILES:.t3s=.t3x)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export ROMFS_T3XFILES := $(patsubst %.t3s, $(GFXBUILD)/%.t3x, $(GFXFILES))
export T3XHFILES := $(patsubst %.t3s, $(BUILD)/%.h, $(GFXFILES))
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------

export OFILES_SOURCES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)

export OFILES_BIN := $(addsuffix .o,$(BINFILES)) \
$(PICAFILES:.v.pica=.shbin.o) $(SHLISTFILES:.shlist=.shbin.o) \
$(addsuffix .o,$(T3XFILES))

export OFILES := $(OFILES_BIN) $(OFILES_SOURCES)

export HFILES := $(PICAFILES:.v.pica=_shbin.h) $(SHLISTFILES:.shlist=_shbin.h) \
$(addsuffix .h,$(subst .,_,$(BINFILES))) \
$(GFXFILES:.t3s=.h)

export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)

export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)

export _3DSXDEPS := $(if $(NO_SMDH),,$(OUTPUT).smdh)

ifeq ($(strip $(ICON)),)
icons := $(wildcard *.png)
ifneq (,$(findstring $(TARGET).png,$(icons)))
export APP_ICON := $(TOPDIR)/$(TARGET).png
else
ifneq (,$(findstring icon.png,$(icons)))
export APP_ICON := $(TOPDIR)/icon.png
endif
endif
else
export APP_ICON := $(TOPDIR)/$(ICON)
endif

ifeq ($(strip $(NO_SMDH)),)
export _3DSXFLAGS += --smdh=$(CURDIR)/$(TARGET).smdh
endif

ifneq ($(ROMFS),)
export _3DSXFLAGS += --romfs=$(CURDIR)/$(ROMFS)
endif

.PHONY: all clean

#---------------------------------------------------------------------------------
all: $(BUILD) $(GFXBUILD) $(DEPSDIR) $(ROMFS_T3XFILES) $(T3XHFILES)
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile

$(BUILD):
@mkdir -p [email protected]

ifneq ($(GFXBUILD),$(BUILD))
$(GFXBUILD):
@mkdir -p [email protected]
endif

ifneq ($(DEPSDIR),$(BUILD))
$(DEPSDIR):
@mkdir -p [email protected]
endif

#---------------------------------------------------------------------------------
clean:
@Echo clean ...
@rm -fr $(BUILD) $(TARGET).3dsx $(OUTPUT).smdh $(TARGET).elf $(GFXBUILD)

#---------------------------------------------------------------------------------
$(GFXBUILD)/%.t3x $(BUILD)/%.h : %.t3s
#---------------------------------------------------------------------------------
@Echo $(notdir $<)
@tex3ds -i $< -H $(BUILD)/$*.h -d $(DEPSDIR)/$*.d -o $(GFXBUILD)/$*.t3x

#---------------------------------------------------------------------------------
else

#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT).3dsx : $(OUTPUT).elf $(_3DSXDEPS)

$(OFILES_SOURCES) : $(HFILES)

$(OUTPUT).elf : $(OFILES)

#---------------------------------------------------------------------------------
# you need a rule like this for each extension you use as binary data
#---------------------------------------------------------------------------------
%.bin.o %_bin.h : %.bin
#---------------------------------------------------------------------------------
@Echo $(notdir $<)
@$(bin2o)

#---------------------------------------------------------------------------------
.PRECIOUS : %.t3x
#---------------------------------------------------------------------------------
%.t3x.o %_t3x.h : %.t3x
#---------------------------------------------------------------------------------
@Echo $(notdir $<)
@$(bin2o)

#---------------------------------------------------------------------------------
# rules for assembling GPU shaders
#---------------------------------------------------------------------------------
define shader-as
$(eval CURBIN := $*.shbin)
$(eval DEPSFILE := $(DEPSDIR)/$*.shbin.d)
echo "$(CURBIN).o: $< $1" > $(DEPSFILE)
echo "extern const u8" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(CURBIN) | tr . _)`.h
echo "extern const u8" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(CURBIN) | tr . _)`.h
echo "extern const u32" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(CURBIN) | tr . _)`.h
picasso -o $(CURBIN) $1
bin2s $(CURBIN) | $(AS) -o $*.shbin.o
endef

%.shbin.o %_shbin.h : %.v.pica %.g.pica
@Echo $(notdir $^)
@$(call shader-as,$^)

%.shbin.o %_shbin.h : %.v.pica
@Echo $(notdir $<)
@$(call shader-as,$<)

%.shbin.o %_shbin.h : %.shlist
@Echo $(notdir $<)
@$(call shader-as,$(foreach file,$(shell cat $<),$(dir $<)$(file)))

#---------------------------------------------------------------------------------
%.t3x %.h : %.t3s
#---------------------------------------------------------------------------------
@Echo $(notdir $<)
@tex3ds -i $< -H $*.h -d $*.d -o $*.t3x

-include $(DEPSDIR)/*.d

#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------
I could try using an example makefile but idk if it breaks anything else.

Thanks.
 
Last edited by KyoIsHacking,

0c0de

New Member
Newbie
Joined
Jan 27, 2018
Messages
3
Trophies
0
Age
23
XP
25
Country
Spain
Hi I don't know if you will see this but I'm trying to use m3d::Sound class for some effects just 2 but audio isn't playing any sound but with m3d::Music I can play the sounds, doesn't matter the format of audio mp3 or wav just don't play it this is how I have declared:

Code:
    //This code is inside main function
    //Init all music and effects
    m3d::Music bgm("romfs:/bgm.mp3");
    m3d::Sound pickFX("romfs:/pickup.mp3");
    m3d::Sound dieFX("romfs:/died.mp3");

   //Then when I want to play it I'm trying to use
   //play() method but no luke
   if(snakeParts[0].getXPosition() >= foodPosX - 6 &&
      snakeParts[0].getXPosition() <= foodPosX + 6  &&
      snakeParts[0].getYPosition() >= foodPosY - 6 &&
      snakeParts[0].getYPosition() <= foodPosY + 6)
    {
                    pickFX.setVolume(0.9f);
                    pickFX.play("romfs:/pickup.wav");
                    canGenerateFood = true;
                    score++;
                }else {
                    snakeParts.pop_back();
                }

When using music plays but after some plays maybe 8 or 10 didn't play anymore, so any idea why this happens? anyway thanks for creating this
 

StuntHacks

Well-Known Member
OP
Newcomer
Joined
Jan 19, 2017
Messages
46
Trophies
0
Age
22
Location
Vienna
XP
205
Country
Austria
Hi I don't know if you will see this but I'm trying to use m3d::Sound class for some effects just 2 but audio isn't playing any sound but with m3d::Music I can play the sounds, doesn't matter the format of audio mp3 or wav just don't play it this is how I have declared:

[...]

When using music plays but after some plays maybe 8 or 10 didn't play anymore, so any idea why this happens? anyway thanks for creating this

Hi, are you running this program on real hardware (as in, a real 3DS) or in an emulator? Could you try to compile your program and post the compile .3dsx as well as your full project directory (including the complete source as well as the audio files)?
 

0c0de

New Member
Newbie
Joined
Jan 27, 2018
Messages
3
Trophies
0
Age
23
XP
25
Country
Spain
I use a real 3DS to be more precise, an O3DS with b9s here It's all the project including source code and 3dsx, BTW this is my first C++ project

Link for download the project: bit.ly/ 2TfZpe3

Sorry for this late response but I was busy with college
 

ChrisCross

Member
Newcomer
Joined
Jul 1, 2019
Messages
5
Trophies
0
Age
19
XP
99
Country
Germany
If I try to complile it, I get the following error:
source/graphics/screen.cpp:439:3: error: 'C3D_TexEnvInit' was not declared in this scope; did you mean 'C3D_TexInit'?

I have no Idea, where the problem is.
 
Last edited by ChrisCross,
General chit-chat
Help Users
    NeoGaming @ NeoGaming: only gamer understand this https://www.youtube.com/shorts/ig5LUVK9kcM