1
0
Fork 0
mirror of https://github.com/ctruLua/ctruLua.git synced 2025-10-27 08:29:31 +00:00

Added missing dependicies

This commit is contained in:
Reuh 2015-08-17 21:10:54 +02:00
parent 03baa21c10
commit ebcd9f00ed
47 changed files with 18405 additions and 0 deletions

6
libs/3ds_portlibs/.gitignore vendored Normal file
View file

@ -0,0 +1,6 @@
freetype-*
libexif-*
libjpeg-*
libpng-*
sqlite-*
zlib-*

150
libs/3ds_portlibs/Makefile Normal file
View file

@ -0,0 +1,150 @@
FREETYPE := freetype
FREETYPE_VERSION := $(FREETYPE)-2.6
FREETYPE_SRC := $(FREETYPE_VERSION).tar.bz2
FREETYPE_DOWNLOAD := "http://download.savannah.gnu.org/releases/freetype/freetype-2.6.tar.bz2"
LIBEXIF := libexif
LIBEXIF_VERSION := $(LIBEXIF)-0.6.21
LIBEXIF_SRC := $(LIBEXIF_VERSION).tar.bz2
LIBEXIF_DOWNLOAD := "http://sourceforge.net/projects/libexif/files/libexif/0.6.21/libexif-0.6.21.tar.bz2"
LIBJPEGTURBO := libjpeg-turbo
LIBJPEGTURBO_VERSION := $(LIBJPEGTURBO)-1.4.1
LIBJPEGTURBO_SRC := $(LIBJPEGTURBO_VERSION).tar.gz
LIBJPEGTURBO_DOWNLOAD := "http://sourceforge.net/projects/libjpeg-turbo/files/1.4.1/libjpeg-turbo-1.4.1.tar.gz"
LIBPNG := libpng
LIBPNG_VERSION := $(LIBPNG)-1.6.17
LIBPNG_SRC := $(LIBPNG_VERSION).tar.xz
LIBPNG_DOWNLOAD := "http://prdownloads.sourceforge.net/libpng/libpng-1.6.17.tar.xz"
SQLITE := sqlite
SQLITE_VERSION := $(SQLITE)-autoconf-3081002
SQLITE_SRC := $(SQLITE_VERSION).tar.gz
SQLITE_DOWNLOAD := "http://www.sqlite.org/2015/sqlite-autoconf-3081002.tar.gz"
ZLIB := zlib
ZLIB_VERSION := $(ZLIB)-1.2.8
ZLIB_SRC := $(ZLIB_VERSION).tar.gz
ZLIB_DOWNLOAD := "http://prdownloads.sourceforge.net/libpng/zlib-1.2.8.tar.gz"
export PORTLIBS := $(CURDIR)/build
export PATH := $(DEVKITARM)/bin:$(PATH)
export PKG_CONFIG_PATH := $(PORTLIBS)/lib/pkgconfig
export CFLAGS := -march=armv6k -mtune=mpcore -mfloat-abi=hard -O3 \
-mword-relocations -fomit-frame-pointer -ffast-math
export CPPFLAGS := -I$(PORTLIBS)/include
export LDFLAGS := -L$(PORTLIBS)/lib
.PHONY: all old_all install install-zlib clean \
$(FREETYPE) \
$(LIBEXIF) \
$(LIBJPEGTURBO) \
$(LIBPNG) \
$(SQLITE) \
$(ZLIB)
all: zlib install-zlib freetype libexif libjpeg-turbo libpng sqlite install
@echo "Finished!"
create_build_dir:
@[ -d $(CURDIR)/build ] || mkdir -p $(CURDIR)/build
@[ -d $(CURDIR)/build/include ] || mkdir -p $(CURDIR)/build/include
@[ -d $(CURDIR)/build/lib ] || mkdir -p $(CURDIR)/build/lib
old_all:
@echo "Please choose one of the following targets:"
@echo " $(FREETYPE) (requires zlib to be installed)"
@echo " $(LIBEXIF)"
@echo " $(LIBJPEGTURBO)"
@echo " $(LIBPNG) (requires zlib to be installed)"
@echo " $(SQLITE)"
@echo " $(ZLIB)"
$(FREETYPE): $(FREETYPE_SRC)
@[ -d $(FREETYPE_VERSION) ] || tar -xf $<
@cd $(FREETYPE_VERSION) && \
./configure --prefix=$(PORTLIBS) --host=arm-none-eabi --disable-shared --enable-static --without-harfbuzz
@$(MAKE) -C $(FREETYPE_VERSION)
@make create_build_dir
@cp -srf $(CURDIR)/freetype-2.6/include/. $(CURDIR)/build/include
@cp -sf $(CURDIR)/freetype-2.6/objs/.libs/libfreetype.a $(CURDIR)/build/lib/libfreetype.a
$(LIBEXIF): $(LIBEXIF_SRC)
@[ -d $(LIBEXIF_VERSION) ] || tar -xf $<
@cd $(LIBEXIF_VERSION) && \
./configure --prefix=$(PORTLIBS) --host=arm-none-eabi --disable-shared --enable-static
@$(MAKE) -C $(LIBEXIF_VERSION)
$(LIBJPEGTURBO): $(LIBJPEGTURBO_SRC)
@[ -d $(LIBJPEGTURBO_VERSION) ] || tar -xf $<
@cd $(LIBJPEGTURBO_VERSION) && \
./configure --prefix=$(PORTLIBS) --host=arm-none-eabi --disable-shared --enable-static
@$(MAKE) CFLAGS+="\"-Drandom()=rand()\"" -C $(LIBJPEGTURBO_VERSION)
@make create_build_dir
@cp -sf $(CURDIR)/libjpeg-turbo-*/*.h $(CURDIR)/build/include
@cp -sf $(CURDIR)/libjpeg-turbo-*/.libs/libjpeg.a $(CURDIR)/build/lib/libjpeg.a
$(LIBPNG): $(LIBPNG_SRC)
@[ -d $(LIBPNG_VERSION) ] || tar -xf $<
@cd $(LIBPNG_VERSION) && \
./configure --prefix=$(PORTLIBS) --host=arm-none-eabi --disable-shared --enable-static
@$(MAKE) -C $(LIBPNG_VERSION)
@make create_build_dir
@cp -sf $(CURDIR)/libpng-*/*.h $(CURDIR)/build/include
@cp -sf $(CURDIR)/libpng-*/.libs/*.a $(CURDIR)/build/lib/libpng.a
# sqlite won't work with -ffast-math
$(SQLITE): $(SQLITE_SRC)
@[ -d $(SQLITE_VERSION) ] || tar -xf $<
@cd $(SQLITE_VERSION) && \
CFLAGS="$(filter-out -ffast-math,$(CFLAGS)) -DSQLITE_OS_OTHER=1" ./configure --disable-shared --disable-threadsafe --disable-dynamic-extensions --host=arm-none-eabi --prefix=$(PORTLIBS)
# avoid building sqlite3 shell
@$(MAKE) -C $(SQLITE_VERSION) libsqlite3.la
$(ZLIB): $(ZLIB_SRC)
@[ -d $(ZLIB_VERSION) ] || tar -xf $<
@cd $(ZLIB_VERSION) && \
CHOST=arm-none-eabi ./configure --static --prefix=$(PORTLIBS)
@$(MAKE) -C $(ZLIB_VERSION)
@make create_build_dir
@cp -sf $(CURDIR)/zlib-*/*.h $(CURDIR)/build/include
@cp -sf $(CURDIR)/zlib-*/libz.a $(CURDIR)/build/lib/libz.a
# Downloads
$(ZLIB_SRC):
wget -O $@ $(ZLIB_DOWNLOAD)
$(FREETYPE_SRC):
wget -O $@ $(FREETYPE_DOWNLOAD)
$(LIBEXIF_SRC):
wget -O $@ $(LIBEXIF_DOWNLOAD)
$(LIBJPEGTURBO_SRC):
wget -O $@ $(LIBJPEGTURBO_DOWNLOAD)
$(LIBPNG_SRC):
wget -O $@ $(LIBPNG_DOWNLOAD)
$(SQLITE_SRC):
wget -O $@ $(SQLITE_DOWNLOAD)
install-zlib:
@$(MAKE) -C $(ZLIB_VERSION) install
install:
@[ ! -d $(FREETYPE_VERSION) ] || $(MAKE) -C $(FREETYPE_VERSION) install
@[ ! -d $(LIBEXIF_VERSION) ] || $(MAKE) -C $(LIBEXIF_VERSION) install
@[ ! -d $(LIBJPEGTURBO_VERSION) ] || $(MAKE) -C $(LIBJPEGTURBO_VERSION) install
@[ ! -d $(LIBPNG_VERSION) ] || $(MAKE) -C $(LIBPNG_VERSION) install
@[ ! -d $(SQLITE_VERSION) ] || $(MAKE) -C $(SQLITE_VERSION) install-libLTLIBRARIES install-data
clean:
@$(RM) -r $(FREETYPE_VERSION)
@$(RM) -r $(LIBEXIF_VERSION)
@$(RM) -r $(LIBJPEGTURBO_VERSION)
@$(RM) -r $(LIBPNG_VERSION)
@$(RM) -r $(SQLITE_VERSION)
@$(RM) -r $(ZLIB_VERSION)
@rm -rf $(CURDIR)/build
@rm -f $(CURDIR)/*.tar.*

View file

@ -0,0 +1,42 @@
3DS Portlibs
============
Here is a Makefile for building various portlibs for 3DS.
Type:
$ make
or:
$ make all
to download and install all the libraries at once.
You can build and install the libraries separately:
$ make zlib
$ make install-zlib
$ make <targets>
$ make install
This will install the portlibs to `$DEVKITPRO/portlibs/armv6k`. If this is a
privileged location, you will need to `sudo make install-zlib` and `sudo make
install` in order for the portlibs to be installed.
Currently supports the following portlibs:
* freetype (requires zlib)
* libexif
* libjpeg-turbo
* libpng (requires zlib)
* sqlite
* zlib
Download links:
* [freetype-2.5.5.tar.bz2] (http://download.savannah.gnu.org/releases/freetype/freetype-2.5.5.tar.bz2)
* [libexif-0.6.21.tar.bz2] (http://sourceforge.net/projects/libexif/files/libexif/0.6.21/libexif-0.6.21.tar.bz2/download)
* [libjpeg-turbo-1.4.0.tar.gz] (http://sourceforge.net/projects/libjpeg-turbo/files/1.4.0/libjpeg-turbo-1.4.0.tar.gz/download)
* [libpng-1.6.17.tar.xz] (http://prdownloads.sourceforge.net/libpng/libpng-1.6.17.tar.xz?download)
* [sqlite-autoconf-3081002.tar.gz] (http://www.sqlite.org/2015/sqlite-autoconf-3081002.tar.gz)
* [zlib-1.2.8.tar.gz] (http://prdownloads.sourceforge.net/libpng/zlib-1.2.8.tar.gz?download)

17
libs/3ds_portlibs/TODO.md Normal file
View file

@ -0,0 +1,17 @@
TODO
====
List of things to get done.
General
-------
* Change `-mfloat-abi=softfp` to `-mfloat-abi=hard` when new devkitARM is
released.
SQLite
------
* Implement `sqlite3_os_init` and `sqlite3_os_end`, or replace
`-DSQLITE_OS_OTHER=1` with `-DSQLITE_OS_UNIX=1`?
* Remove `--disable-threadsafe` and implement locking mechanism.

27
libs/aemstro/README.md Normal file
View file

@ -0,0 +1,27 @@
aemstro
=======
''THE ORIGINAL'' pica200 shader (dis)assembly toolkit !
set of tools used to disassemble and assemble shader code for DMP's MAESTRO shader extension used in the 3DS's PICA200 GPU
see http://3dbrew.org/wiki/Shader_Instruction_Set for more information
it is meant for rapid iteration and experimentation as I reverse engineer the instruction set. as such, the code is dirty and ugly and poorly organized. functionality is also lacking and overall it is not recommended that you use this for your own homebrew projects unless they involve reverse engineering. for more user friendly implementations, see neobrain's nihstro and fincs's picasso.
requires python 3. sorry !
please note that the current iteration of aemstro is very experimental as we are still in the process of reverse engineering the instruction set. the current version is a prototype meant to be iterated upon quickly; not a well thought out piece of clean software. so basically don't fret if you think the code looks like shit and could be written in a much more efficient manner; you're not alone.
aemstro.py :
- disassembles shbin/bcsdr files
- usage : aemstro.py <input.shbin/input.bcsdr>
- outputs to stdout
aemstro_as.py :
- assembles vertex shaders
- usage : aemstro_as.py <input.vsh> <output.shbin>
- see test.vsh for sample code
- can *not* assemble output from aemstro.py
- is currently much less up to date than aemstro.py (mostly the instruction format thing is all wrong)

749
libs/aemstro/aemstro.py Executable file
View file

@ -0,0 +1,749 @@
import struct
import os
import sys
input={}
# '''0x0 : "vertex.position",
# 0x1 : "vertex.texcoord",
# 0x4 : "vertex.color?"}'''
output={}
# {0x0 : "glPosition",
# 0x2 : "glTexcoord",
# 0x4 : "glTexcoord",
# 0x6 : "glColor?",
# 0x8 : "glTexcoord?"}
lineIndentLevel={}
def indentLine(k):
if not(k in lineIndentLevel):
lineIndentLevel[k]=0
lineIndentLevel[k]+=1
def unindentLine(k):
if not(k in lineIndentLevel):
lineIndentLevel[k]=0
lineIndentLevel[k]-=1
def resetIndentLevel():
for k in lineIndentLevel:
lineIndentLevel[k]=0
def getWord(b, k, n=4):
return sum(list(map(lambda c: b[k+c]<<(c*8),range(n))))
def convFloat24(f):
#seee eeee mmmm mmmm mmmm mmmm
if f==0x0:
return 0.0
s=f>>23
e=(f>>16)&0x7F
m=f&0xffff
x=pow(2.0,e-63)*(1 + m*pow(2.0,-16))
if f&0x800000!=0:
return -x
return x
# # doesn't quite work, but could be a more accurate approach ?
# def convFloat24(val):
# if val==0x0:
# return 0.0
# tmp=((val>>16)&0xFF)+0x40
# out=(tmp<<23)|((val&0x800000)<<31)|((val&0xFFFF)<<7)
# try:
# return (struct.unpack("f",struct.pack("I",out)))[0]
# except:
# return (val)
def parseSymbol(b,o):
len=0
while getWord(b,o+len,1)!=0x00:
len+=1
return(b[o:o+len].decode("ascii"))
def parseExtTable(data):
l=len(data)
out=[]
for i in range(0,l,8):
out+=[(getWord(data, i), getWord(data, i+0x4))]
return out
def getRegisterNameSRC(v):
if v<0x80:
return getRegisterNameSRC1(v)
elif v<0x88:
return "i"+str(v-0x80)
else:
return "b"+str(v-0x88)
def getRegisterNameSRC1(v):
if v<0x10:
return "v"+str(v&0xF)
elif v<0x20:
return "r"+str(v-0x10)
elif v<0x80:
return "c"+str(v-0x20)
else:
return ("r%02X"%(v))
def getRegisterNameSRC2(v):
return getRegisterNameSRC1(v)
def getRegisterNameDST(v):
if v<0x10:
return ("o%X"%(v))
elif v<0x20:
return "r"+str(v-0x10)
else:
return ("r%02X"%(v))
def getRegisterName(v):
return ("r%02X"%(v))
# if v<16:
# return "v"+str(v&0xF)
# elif v<120:
# return "c"+str(v-16)
# else:
# return "b"+str(v-0x88)
def getInputSymbol(v, vt, ut, idx):
src=getRegisterNameSRC(v)
return getInputSymbolFromString(src, vt, ut, idx)
def getInputSymbolFromString(src, vt, ut, idx):
idxstr=""
if idx==1:
idxstr="[idx1]"
elif idx==2:
idxstr="[idx2]"
elif idx==3:
idxstr="[lcnt]"
if src in vt:
return vt[src]+idxstr
if src in ut:
return ut[src]+idxstr
else:
f=src.find(".")
if f>=0:
src=getInputSymbolFromString(src[:f], vt, ut, idx)+src[f:]
idxstr=""
return src+idxstr
def getOutputSymbol(v, ot):
dst=getRegisterNameDST(v)
return ot[dst] if dst in ot else dst
def getLabelSymbol(v, t):
return t[v][1] if v in t else hex(v)
def initIndent():
global numIdent
numIdent=0
def indentOut():
global numIdent
numIdent=numIdent+1
def unindentOut():
global numIdent
numIdent=numIdent-1
def iprint(s, e=False):
global numIdent
if e:
print(" "*numIdent+s,end='')
else:
print(" "*numIdent+s)
comp=["x", "y", "z", "w"]
def parseComponentMask(v):
out=""
for i in range(4):
if v&(1<<(3-i))!=0x0:
out+=comp[i]
else:
out+="_"
return out
def parseExt(v):
return {"src1" : (v>>5)&0xFF,
"src2" : (v>>14)&0xFF,
"src3" : (v>>23)&0xFF,
"nsrc1" : (v>>4)&0x1, #negation bit
"nsrc2" : (v>>13)&0x1, #negation bit
"nsrc3" : (v>>22)&0x1, #negation bit
"dst" : (v)&0x1F,
"dstcomp" : parseComponentMask(v&0xF),
"rest" : (v>>22)}
def parseComponentSwizzle(v):
out=""
for i in range(4):
out+=comp[(v>>((3-i)*2))&0x3]
return out
def parseInstFormat10(k, v, lt={}):
return {"opcode" : v>>26,
"src2" : (v>>7)&0x1F,
"src1" : (v>>12)&0x7F,
"idx_1" : (v>>19)&0x3,
"idx_2" : 0x0,
"cmpY" : (v>>21)&0x7,
"cmpX" : (v>>24)&0x7,
"extid" : (v)&0x7F}
def parseInstFormat1(k, v, lt={}):
return {"opcode" : v>>26,
"src2" : (v>>7)&0x1F,
"src1" : (v>>12)&0x7F,
"idx_1" : (v>>19)&0x3,
"idx_2" : 0x0,
"dst" : (v>>21)&0x1F,
"extid" : (v)&0x7F}
def parseInstFormat8(k, v, lt={}):
return {"opcode" : v>>26,
"src2" : (v>>7)&0x7F,
"src1" : (v>>14)&0x1F,
"idx_1" : 0x0,
"idx_2" : (v>>19)&0x3,
"dst" : (v>>21)&0x1F,
"extid" : (v)&0x7F}
def parseInstFormat9(k, v, lt={}):
return {"opcode" : v>>26,
"dst" : (v>>24)&0x1F,
"src1" : (v>>17)&0x7F,
"src2" : (v>>10)&0x7F,
"src3" : (v>>5)&0x1F,
"idx_1" : 0x0,
"idx_2" : 0x0,
"extid" : (v)&0x1F}
def parseInstFormat12(k, v, lt={}):
return {"opcode" : v>>26,
"dst" : (v>>24)&0x1F,
"src1" : (v>>17)&0x7F,
"src2" : (v>>12)&0x1F,
"src3" : (v>>5)&0x7F,
"idx_1" : 0x0,
"idx_2" : 0x0,
"extid" : (v)&0x1F}
def parseInstFormat2(k, v, lt={}):
ret={"opcode" : v>>26,
"addr" : (v>>8)&0x3FFC,
"flags" : (v>>22)&0xF,
"ret" : (v)&0x3FF}
if ret["opcode"]==0x28: #IF?
for i in range(k+4,ret["addr"],4):
indentLine(i)
for i in range(ret["addr"],ret["addr"]+ret["ret"]*4,4):
indentLine(i)
if ret["ret"]>0:
lt[ret["addr"]]=(-1,"ELSE_%X"%(k))
return ret
#?
def parseInstFormat3(k, v, lt={}):
return {"opcode" : v>>26,
"src2" : (v>>0)&0x1F,
"src1" : (v>>7)&0x7F,
"dst" : (v>>14)&0x1F}
#?
def parseInstFormat6(k, v, lt={}):
return {"opcode" : v>>26,
"vtxid" : (v>>24)&0x3,
"primid" : (v>>22)&0x3}
# MOV?
def parseInstFormat4(k, v, lt={}):
return {"opcode" : v>>26,
"src1" : (v>>7)&0x7F,
"dst" : (v>>14)&0x1F,
"extid" : (v)&0x3F}
# CONDJUMP
def parseInstFormat5(k, v, lt={}):
ret={"opcode" : v>>26,
"addr" : (v>>8)&0x3FFC,
"bool" : (v>>22)&0xF,
"ret" : (v)&0x3FF}
if ret["opcode"]==0x27: #IFU
for i in range(k+4,ret["addr"],4):
indentLine(i)
for i in range(ret["addr"],ret["addr"]+ret["ret"]*4,4):
indentLine(i)
if ret["ret"]>0:
lt[ret["addr"]]=(-1,"ELSE_%X"%(k))
elif ret["opcode"]==0x29: #LOOP
for i in range(k+4,ret["addr"]+4,4):
indentLine(i)
return ret
def outputStringList(k, strl, fmtl):
l=len(strl)
if k in lineIndentLevel and lineIndentLevel[k]>0:
out=" "*lineIndentLevel[k]
else:
out=""
if l==len(fmtl):
for i in range(l):
str=strl[i]
fmt=fmtl[i]
if fmt:
v=len(str)
if v<fmt:
str+=" "*(fmt-v)
out+=str
iprint(out)
def printInstFormat1(k, n, inst, e, lt, vt, ut, ot):
ext=e[inst["extid"]][0]
extd=parseExt(ext)
nsrc1="-" if extd["nsrc1"]==1 else ""
nsrc2="-" if extd["nsrc2"]==1 else ""
outputStringList(k, [n,
getOutputSymbol(inst["dst"], ot)+"."+extd["dstcomp"],
" <- ",
nsrc1+getInputSymbol(inst["src1"], vt, ut, inst["idx_1"])+"."+(parseComponentSwizzle(extd["src1"])),
" , ",
nsrc2+getInputSymbol(inst["src2"], vt, ut, inst["idx_2"])+"."+(parseComponentSwizzle(extd["src2"])),
" ("+hex(inst["extid"])+" "+hex(extd["rest"])+")"],
[8, 32, None, 32, None, 32, None])
cmpOp={0x0 : "EQ", 0x1 : "NE", 0x2 : "LT", 0x3 : "LE", 0x4 : "GT", 0x5 : "GE", 0x6 : "??", 0x7 : "??"}
def printInstFormat10(k, n, inst, e, lt, vt, ut, ot):
ext=e[inst["extid"]][0]
extd=parseExt(ext)
nsrc1="-" if extd["nsrc1"]==1 else ""
nsrc2="-" if extd["nsrc2"]==1 else ""
outputStringList(k, [n,
nsrc1+getInputSymbol(inst["src1"], vt, ut, inst["idx_1"])+"."+(parseComponentSwizzle(extd["src1"])),
"("+cmpOp[inst["cmpX"]]+", "+cmpOp[inst["cmpY"]]+")",
nsrc2+getInputSymbol(inst["src2"], vt, ut, inst["idx_2"])+"."+(parseComponentSwizzle(extd["src2"])),
" ("+hex(inst["extid"])+")"],
[8, 32, 12, 32, None])
def printInstFormat9(k, n, inst, e, lt, vt, ut, ot):
ext=e[inst["extid"]][0]
extd=parseExt(ext)
nsrc1="-" if extd["nsrc1"]==1 else ""
nsrc2="-" if extd["nsrc2"]==1 else ""
nsrc3="-" if extd["nsrc3"]==1 else ""
outputStringList(k, [n,
getOutputSymbol(inst["dst"], ot)+"."+extd["dstcomp"],
" <- ",
nsrc1+getInputSymbol(inst["src1"], vt, ut, inst["idx_1"])+"."+(parseComponentSwizzle(extd["src1"])),
" , ",
nsrc2+getInputSymbol(inst["src2"], vt, ut, inst["idx_2"])+"."+(parseComponentSwizzle(extd["src2"])),
" , ",
nsrc3+getInputSymbol(inst["src3"], vt, ut, 0)+"."+(parseComponentSwizzle(extd["src3"])),
" ("+hex(extd["rest"])+")"],
[8, 32, None, 16, None, 16, None, 16, None])
def printInstFormat4(k, n, inst, e, lt, vt, ut, ot):
ext=e[inst["extid"]][0]
extd=parseExt(ext)
nsrc1="-" if extd["nsrc1"]==1 else ""
nsrc2="-" if extd["nsrc2"]==1 else ""
outputStringList(k, [n,
getOutputSymbol(inst["dst"], ot)+"."+extd["dstcomp"],
" <- ",
nsrc1+getInputSymbol(inst["src1"], vt, ut, inst["idx_1"])+"."+(parseComponentSwizzle(extd["src1"])),
" ", "",
" ("+hex(inst["extid"])+")"],
[8, 32, None, 32, None, 32, None])
def printInstFormat7(k, n, inst, e, lt, vt, ut, ot):
ext=e[inst["extid"]][0]
extd=parseExt(ext)
nsrc1="-" if extd["nsrc1"]==1 else ""
nsrc2="-" if extd["nsrc2"]==1 else ""
outputStringList(k, [n,
"idx.xy__",
" <- ",
nsrc1+getInputSymbol(inst["src1"], vt, ut, inst["idx_1"])+"."+(parseComponentSwizzle(extd["src1"])),
" ", "",
" ("+hex(inst["extid"])+")"],
[8, 32, None, 32, None, 32, None])
def printInstFormat6(k, n, inst, e, lt, vt, ut, ot):
outputStringList(k, [n,
"vtx%02X," % inst["vtxid"],
"PRIM_EMIT" if inst["primid"]&2==2 else "",
"UNK_FLAG" if inst["primid"]&1==1 else ""],
[8, 8, 12, 16])
def printInstFormat2(k, n, inst, e, lt, vt, ut, ot):
outputStringList(k, [n,
getLabelSymbol(inst["addr"], lt),
" ("+str(inst["ret"])+ " words, flags: "+bin(inst['flags'])+")"],
[8, 32, 32])
# CONDJUMP (uniform)
def printInstFormat5(k, n, inst, e, lt, vt, ut, ot):
if inst["opcode"]==0x29: #LOOP
reg=getRegisterNameSRC((inst['bool']&0xF)+0x80)
start=getInputSymbolFromString(reg+".y", vt, ut, 0)
end=start+"+"+getInputSymbolFromString(reg+".x", vt, ut, 0)
stride=getInputSymbolFromString(reg+".z", vt, ut, 0)
outputStringList(k, [n,
"(lcnt = "+start+"; lcnt <= "+end+"; lcnt += "+stride+")",
" (adr "+getLabelSymbol(inst["addr"], lt)+", "+str(inst["ret"])+ " words, "+str(inst['bool']&0xF)+")"],
[8, 16, 16])
elif inst["opcode"]==0x27: #IFU
outputStringList(k, [n,
"("+getInputSymbol((inst['bool']&0xF)+0x88, vt, ut, 0)+")",
" ("+getLabelSymbol(inst["addr"], lt)+", "+str(inst["ret"])+ " words, "+str(inst['bool']&0xF)+")"],
[8, 16, 16])
elif inst["opcode"]==0x2d: #JMPU
outputStringList(k, [n,
getLabelSymbol(inst["addr"], lt),
" , ",
("!" if inst["ret"]==1 else "")+getInputSymbol((inst['bool']&0xF)+0x88, vt, ut, 0),
" ", "",
" ("+str(inst["ret"])+ " words, "+str(inst['bool']&0xF)+")"],
[8, 16, None, 16, None, 16, None])
else:
outputStringList(k, [n,
getLabelSymbol(inst["addr"], lt),
" , ",
getInputSymbol((inst['bool']&0xF)+(0x80 if inst["opcode"]==0x29 else 0x88), vt, ut, 0),
" ", "",
" ("+str(inst["ret"])+ " words, "+str(inst['bool']&0xF)+")"],
[8, 16, None, 16, None, 16, None])
# CONDJUMP (dynamic)
def printInstFormat11(k, n, inst, e, lt, vt, ut, ot):
cond=""
if inst["flags"]&0x3==0x0: #OR
cond=("!" if inst["flags"]&0x8 == 0 else "")+"cmp.x"+" || "+("!" if inst["flags"]&0x4 == 0 else "")+"cmp.y"
elif inst["flags"]&0x3==0x1: #AND
cond=("!" if inst["flags"]&0x8 == 0 else "")+"cmp.x"+" && "+("!" if inst["flags"]&0x4 == 0 else "")+"cmp.y"
elif inst["flags"]&0x3==0x2: #X
cond=("!" if inst["flags"]&0x8 == 0 else "")+"cmp.x"
elif inst["flags"]&0x3==0x3: #Y
cond=("!" if inst["flags"]&0x4 == 0 else "")+"cmp.y"
if inst["opcode"]==0x23: #BREAK
outputStringList(k, [n,
"("+cond+")",
" ", "",
" ("+str(inst["ret"])+ " words, "+str(inst['flags']&0xF)+")"],
[8, 16, None, 16, None])
elif inst["opcode"]==0x28: #IF
outputStringList(k, [n,
"("+cond+")",
" , ",
getLabelSymbol(inst["addr"], lt),
" ", "",
" ("+str(inst["ret"])+ " words, "+str(inst['flags']&0xF)+")"],
[8, 16, None, 16, None, 16, None])
else:
outputStringList(k, [n,
getLabelSymbol(inst["addr"], lt),
" , ",
"("+cond+")",
" ", "",
" ("+str(inst["ret"])+ " words, "+str(inst['flags']&0xF)+")"],
[8, 16, None, 16, None, 16, None])
instList={}
fmtList=[(parseInstFormat1, printInstFormat1), (parseInstFormat2, printInstFormat2), (parseInstFormat2, printInstFormat2), (parseInstFormat1, printInstFormat4), (parseInstFormat5, printInstFormat5), (parseInstFormat6, printInstFormat6), (parseInstFormat1, printInstFormat7), (parseInstFormat8, printInstFormat1), (parseInstFormat9, printInstFormat9), (parseInstFormat10, printInstFormat10), (parseInstFormat2, printInstFormat11), (parseInstFormat12, printInstFormat9)]
instList[0x00]={"name" : "ADD", "format" : 0} #really SUB ?
instList[0x01]={"name" : "DP3", "format" : 0}
instList[0x02]={"name" : "DP4", "format" : 0}
instList[0x03]={"name" : "DPH", "format" : 0} #tested, definitely
instList[0x05]={"name" : "EX2", "format" : 3} #tested, definitely
instList[0x06]={"name" : "LG2", "format" : 3} #tested, definitely
instList[0x08]={"name" : "MUL", "format" : 0}
instList[0x09]={"name" : "SGE", "format" : 0}
instList[0x0A]={"name" : "SLT", "format" : 0}
instList[0x0B]={"name" : "FLR", "format" : 3} #tested, definitely FLR and not FRC
instList[0x0C]={"name" : "MAX", "format" : 0} #definitely
instList[0x0D]={"name" : "MIN", "format" : 0} #definitely
instList[0x0E]={"name" : "RCP", "format" : 3} #1/op1
instList[0x0F]={"name" : "RSQ", "format" : 3} #1/sqrt(op1)
instList[0x12]={"name" : "SETIDX", "format" : 6}
instList[0x13]={"name" : "MOV", "format" : 3}
instList[0x18]={"name" : "DPHI", "format" : 7}
instList[0x1A]={"name" : "SGEI", "format" : 7}
instList[0x1B]={"name" : "SLTI", "format" : 7}
instList[0x23]={"name" : "BREAKC", "format" : 10} #conditional break
instList[0x24]={"name" : "CALL", "format" : 1} #unconditional call
instList[0x25]={"name" : "CALLC", "format" : 10} #conditional call
instList[0x26]={"name" : "CALLU", "format" : 4} #conditional call (uniform bool)
instList[0x27]={"name" : "IFU", "format" : 4} #if/else statement (uniform bool)
instList[0x28]={"name" : "IFC", "format" : 10}
instList[0x29]={"name" : "LOOP", "format" : 4}
instList[0x2b]={"name" : "SETEMIT", "format" : 5}
instList[0x2c]={"name" : "JMPC", "format" : 10} #conditional jump
instList[0x2d]={"name" : "JMPU", "format" : 4} #conditional jump (uniform bool)
for i in range(0x2):
instList[0x2e+i]={"name" : "CMP", "format" : 9}
for i in range(0x8):
instList[0x30+i]={"name" : "MADI", "format" : 11}
for i in range(0x8):
instList[0x38+i]={"name" : "MAD", "format" : 8}
def parseCode(data, e, lt, vt, ut, ot):
l=len(data)
for k in range(0,l,4):
v=getWord(data,k)
opcode=v>>26
if k in lt:
iprint("%08x [--------] "%(k), True)
unindentLine(k)
outputStringList(k, [lt[k][1]+":"], [8])
indentLine(k)
iprint("%08x [%08x] "%(k,v), True)
if opcode in instList:
fmt=instList[opcode]["format"]
inst=fmtList[fmt][0](k, v, lt)
fmtList[fmt][1](k, instList[opcode]["name"], inst, e, lt, vt, ut, ot)
elif opcode==0x21:
# outputStringList(k,["END"],[8])
outputStringList(k,["NOP"],[8])
elif opcode==0x22:
outputStringList(k,["END"],[8])
elif opcode==0x2A:
inst=parseInstFormat1(k, v)
outputStringList(k,["EMITVERTEX"],[10])
else:
inst=parseInstFormat1(k, v)
if inst["extid"] < len(e):
ext=e[inst["extid"]][0]
extd=parseExt(ext)
printInstFormat1(k, "???%02X"%(inst["opcode"]), inst, e, lt, vt, ut, ot)
else:
inst=parseInstFormat3(k, v)
outputStringList(k,["???%02X"%(inst["opcode"]),
getOutputSymbol(inst["dst"], ot),
" <- ",
getInputSymbol(inst["src1"], vt, ut, 0),
" , ",
getInputSymbol(inst["src2"], vt, ut, 0),
"(invalid extension id)"],
[8, 16, None, 16, None, 16, None])
k+=0x4
def parseDVLP(data, lt, vt, ut, ot, k):
l=len(data)
extOffset=getWord(data, 0x10)
fnOffset=getWord(data, 0x18)
# for i in range(fnOffset, l):
# if k==0:
# break
# elif data[i]==0:
# k-=1
# print(parseSymbol(data,i))
extSize=getWord(data, 0x14)*8
ext=parseExtTable(data[extOffset:(extOffset+extSize)])
codeOffset=getWord(data, 0x8)
codeSize=getWord(data, 0xC)*4
parseCode(data[codeOffset:(codeOffset+codeSize)], ext, lt, vt, ut, ot)
def parseLabelTable(data, sym):
l=len(data)
out={}
for i in range(0,l,0x10):
id=getWord(data,i,1)
loc=getWord(data,i+0x4)*4
off=getWord(data,i+0xC)
out[loc]=(id,parseSymbol(sym,off))
return out
def transformRegisterValue(v):
if v<16:
return (v&0xF)
return v+16
def parseVarTable(data, sym):
l=len(data)
iprint("Uniforms :")
indentOut()
src={}
for i in range(0,l,0x8):
off=getWord(data,i)
v1=getWord(data,i+4,2)
v2=getWord(data,i+6,2)
base=transformRegisterValue(v1)
end=transformRegisterValue(v2)
# iprint(getRegisterNameSRC(base)+" - "+getRegisterNameSRC(end)+" : "+parseSymbol(sym,off))
iprint(getRegisterNameSRC(base)+" - "+getRegisterNameSRC(end)+" : "+parseSymbol(sym,off)+" ("+hex(getWord(data,i))+", "+hex(getWord(data,i+4))+")")
if base==end:
name=parseSymbol(sym,off)
src[getRegisterNameSRC(base)]=name
else:
for k in range(base, end+1):
name=parseSymbol(sym,off)+"["+str(k-base)+"]"
src[getRegisterNameSRC(k)]=name
unindentOut()
print("")
return src
def parseConstTable(data, sym):
l=len(data)
iprint("Constants :")
indentOut()
out={}
for i in range(0,l,0x14):
type=getWord(data,i,2)
r=getWord(data,i+2,2)
name=None
if type==0x0:
#constant bool
vec=False if getWord(data,i+4)==0x0 else True
r+=0x88
name=str(vec)
elif type==0x1:
#constant integer vec4
vec=[hex(getWord(data,i+k,1)) for k in range(4,8,1)]
r+=0x80
out[getRegisterNameSRC(r)+".x"]=vec[0]
out[getRegisterNameSRC(r)+".y"]=vec[1]
out[getRegisterNameSRC(r)+".z"]=vec[2]
out[getRegisterNameSRC(r)+".w"]=vec[3]
else:
#constant float24 vec4 (should be type==0x2 but would rather output potential unknowns too)
vec=[convFloat24(getWord(data,i+k)) for k in range(4,0x14,4)]
r+=0x20
name="["+", ".join(["%4.2f"%(v) for v in vec])+"]"
# iprint(getRegisterNameSRC(r)+" = "+str(vec)+" ("+str([hex(getWord(data,i+k)) for k in range(0,0x14,4)])+")")
iprint(getRegisterNameSRC(r)+" = "+str(vec))
if name!=None:
out[getRegisterNameSRC(r)]=name
unindentOut()
print("")
return out
outputTypes={0x0 : "result.position",
0x1 : "result.normalquat", #maybe
0x2 : "result.color",
0x3 : "result.texcoord0",
0x4 : "result.texcoord0w",
0x5 : "result.texcoord1",
0x6 : "result.texcoord2",
# 0x7 : "?", #sets outreg info to 0x1f1f1f1f...
0x8 : "result.view", #"result.view" seems to be pre-projmatrix vertex coordinates
}
def parseOutputTable(data, sym):
l=len(data)
iprint("Output :")
indentOut()
out={}
for i in range(0,l,0x8):
off=getWord(data,i+4)
v1=getWord(data,i,2)
v2=getWord(data,i+2,2)
dst=getRegisterNameDST(v2)
if v1 in outputTypes:
out[dst]=outputTypes[v1]
iprint("o"+str(v2)+" = "+(outputTypes[v1] if v1 in outputTypes else hex(v1))+" ("+hex(off)+", "+hex(v1)+", "+hex(v2)+")")
unindentOut()
print("")
return out
def parseDVLE(data,dvlp, k):
l=len(data)
iprint("DVLE "+str(k))
shaderType=getWord(data, 0x6, 1)
mainStart=getWord(data, 0x8)*4
mainEnd=getWord(data, 0xC)*4
resetIndentLevel()
iprint("unkval "+hex(getWord(data, 0x4, 2)))
iprint("vertex shader" if shaderType==0x0 else "geometry shader")
iprint("main : "+hex(mainStart)+"-"+hex(mainEnd))
print("")
# # temporarily filter out geometry shaders
# if shaderType!=0x0:
# return
# # temporarily filter out vertex shaders
# if shaderType==0x0:
# return
codeStartOffset=getWord(data, 0x8)
codeEndOffset=getWord(data, 0xC)
unifOffset=getWord(data, 0x18)
unifSize=getWord(data, 0x1C)*0x14
labelOffset=getWord(data, 0x20)
labelSize=getWord(data, 0x24)*0x10
outputOffset=getWord(data, 0x28)
outputSize=getWord(data, 0x2C)*0x8
varOffset=getWord(data, 0x30)
varSize=getWord(data, 0x34)*0x8
symbolOffset=getWord(data, 0x38)
symbolSize=getWord(data, 0x3C)
sym=data[symbolOffset:(symbolOffset+symbolSize)]
labelTable=parseLabelTable(data[labelOffset:(labelOffset+labelSize)],sym)
varTable=parseVarTable(data[varOffset:(varOffset+varSize)],sym)
unifTable=parseConstTable(data[unifOffset:(unifOffset+unifSize)],sym)
outputTable=parseOutputTable(data[outputOffset:(outputOffset+outputSize)],sym)
parseDVLP(dvlp, labelTable, varTable, unifTable, outputTable, k)
print("")
return (labelTable,varTable,unifTable,range(codeStartOffset,codeEndOffset))
def parseDVLB(data):
l=len(data)
n=getWord(data, 0x4)
dvleTable={}
labelTable={}
varTable={}
unifTable={}
dvlp=data[(0x8+0x4*n):l]
for i in range(n):
offset=getWord(data, 0x8+0x4*i)
r=parseDVLE(data[offset:l],dvlp,i)
# for k in r[3]:
# dvleTable[k*4]=i
# labelTable.update(r[0])
# varTable[i]=r[1]
# unifTable[i]=r[2]
# parseDVLP(dvlp,labelTable,varTable,unifTable,dvleTable)
if len(sys.argv)<2:
print("AEMSTRO :")
print(" aemstro.py <input.shbin/input.bcsdr>")
else:
initIndent()
src1fn=sys.argv[1]
data=bytearray(open(src1fn, "rb").read())
l=len(data)
for i in range(0,l-4,4):
if getWord(data, i)==0x424C5644:
parseDVLB(data[i:l])

682
libs/aemstro/aemstro_as.py Normal file
View file

@ -0,0 +1,682 @@
import sys
import os
import re
import copy
import struct
#TODO : add parsing checks, handle errors more gracefully
def toFloat24(f):
f=bytearray(struct.pack('f', f))
s=f[3]>>7
tmp=(((f[3]<<1)|(f[2]>>7))&0xFF)-0x40
tmp2=(((f[0])|(f[1]<<8)|(f[2]<<16))>>7)&0xFFFF
if tmp>=0:
tmp2|=tmp<<16
tmp2|=s<<23
else:
tmp2=s<<23
return tmp2
vshMain=None
vshEndmain=None
gshMain=None
gshEndmain=None
class DVLE(object):
def __init__(self, type):
self._main = 0
self._endmain = 0
self._type = type
self._const = []
self._label = []
self._labelmap = {}
self._outmap = []
self._inmap = []
self._symbol = bytearray()
self._symbolnum = 0
def setMain(self, main):
self._main = main
def setEndmain(self, endmain):
self._endmain = endmain
#binary word tuple
def addConstant(self, const):
self._const.append(const)
#(reg, v)
def addConstantB(self, const):
self._const.append(((const[0]<<16)|(0x0), const[1], 0, 0, 0))
#(reg, x, y, z, w)
def addConstantI(self, const):
self._const.append(((const[0]<<16)|(0x1), ((const[1]&0xff)|((const[2]&0xff)<<8)|((const[3]&0xff)<<16)|(const[4]<<24)), (0), (0), (0)))
#(reg, x, y, z, w)
def addConstantF(self, const):
self._const.append(((const[0]<<16)|(0x2), toFloat24(const[1]), toFloat24(const[2]), toFloat24(const[3]), toFloat24(const[4])))
#string
def addSymbol(self, s):
ret=len(self._symbol)
self._symbol+=bytearray(s, "ascii")+bytearray(b"\x00")
self._symbolnum+=1
return ret
#(code offset, symbol offset)
def addLabel(self, label):
self._label.append((label[0],self.addSymbol(label[1])))
self._labelmap[label[1]]=label[0]
def getLabelAddress(self, label):
if label in self._labelmap:
return self._labelmap[label]
else:
return 0x0
#binary word tuple
def addOutput(self, out):
self._outmap.append(out)
#(startreg, endreg, symbol offset)
def addInput(self, ind):
self._inmap.append((ind[0],ind[1],self.addSymbol(ind[2])))
def toBinary(self):
ret=[]
offsetConst=0x40
offsetLabel=offsetConst+len(self._const)*0x14
offsetOutmap=offsetLabel+len(self._label)*0x10
offsetInmap=offsetOutmap+len(self._outmap)*0x8
offsetSymbol=offsetInmap+len(self._inmap)*0x8
ret.append(0x454C5644) #DVLE magic
ret.append((self._type&1)<<16)
ret.append(self._main)
ret.append(self._endmain)
ret.append(0x00000000) # ?
ret.append(0x00000000) # ?
ret.append(offsetConst)
ret.append(len(self._const))
ret.append(offsetLabel)
ret.append(len(self._label))
ret.append(offsetOutmap)
ret.append(len(self._outmap))
ret.append(offsetInmap)
ret.append(len(self._inmap))
ret.append(offsetSymbol)
ret.append(len(self._symbol))
for k in self._const:
ret.append(k[0])
ret.append(k[1])
ret.append(k[2])
ret.append(k[3])
ret.append(k[4])
i=0
for k in self._label:
ret.append(i)
ret.append(k[0])
ret.append(0x00000000) # ?
ret.append(k[1])
i+=1
for k in self._outmap:
ret.append(k[0])
ret.append(k[1])
for k in self._inmap:
ret.append(k[2])
ret.append(((k[1]&0xFFFF)<<16)|(k[0]&0xFFFF))
retb=bytearray()
for k in ret:
retb+=struct.pack("I",k)
retb+=self._symbol
return retb
class DVLP(object):
def __init__(self):
self._code = []
self._opdesc = []
def clearCode(self):
self._code[:] = []
def addInstruction(self, inst):
self._code.append(inst)
return len(self._code)
def addOpdesc(self, opdesc):
self._opdesc.append(opdesc)
return len(self._opdesc)
def getCodelength(self):
return len(self._code)
def toBinary(self):
ret=[]
offsetCode=0x28
offsetOpdesc=offsetCode+len(self._code)*0x4
symbolOffset=offsetOpdesc+len(self._opdesc)*0x8
ret.append(0x504C5644) #DVLP magic
ret.append(0x00000000) # ?
ret.append(offsetCode)
ret.append(len(self._code))
ret.append(offsetOpdesc)
ret.append(len(self._opdesc))
ret.append(symbolOffset)
ret.append(0x00000000) # ?
ret.append(0x00000000) # ?
ret.append(0x00000000) # ?
retb=bytearray()
for k in ret:
retb+=struct.pack("I",k)
for k in self._code:
retb+=struct.pack("I",k)
for k in self._opdesc:
retb+=struct.pack("I",k[0])
retb+=struct.pack("I",k[1])
return retb
class DVLB(object):
def __init__(self):
self._dvlp = DVLP()
self._dvle = []
def getDVLP(self):
return self._dvlp
def addDVLE(self, dvle):
self._dvle.append(dvle)
def toBinary(self):
ret=[]
ret.append(0x424C5644) #DVLB magic
ret.append(len(self._dvle))
off=len(self._dvle)*0x4+0x8
retb=bytearray()
retb+=self._dvlp.toBinary()
for k in self._dvle:
retb+=bytearray([0x00]*(0 if len(retb)%4==0 else 4-(len(retb)%4)))
ret.append(off+len(retb))
retb+=k.toBinary()
retb2=bytearray()
for k in ret:
retb2+=struct.pack("I",k)
return retb2+retb
def getRegisterFromNameDst(s):
if s[0]=="o": # output
return int(s[1:])
elif s[0]=="v": # attribute
print("error : "+s+" cannot be accessed from dst")
elif s[0]=="r": # temporary register
return int(s[1:])+0x10
elif s[0]=="c": # uniform
print("error : "+s+" cannot be accessed from dst")
elif s[0]=="d": # direct hex; unambiguous
return int("0x"+s[1:],0)
else:
print("error : "+s+" is not a valid register name")
def getRegisterFromNameSrc1(s):
index=0
if "[" in s:
i=s.index("[")
index=s[i+1:-1]
s=s[:i]
if index=="a0.x":
index=1
elif index=="a0.y":
index=2
elif index=="aL":
index=3
if s[0]=="o": # output
print("error : "+s+" cannot be accessed from src1")
elif s[0]=="v": # attribute
return (int(s[1:]), index)
elif s[0]=="r": # temporary register
return (int(s[1:])+0x10, index)
elif s[0]=="c": # uniform
return (int(s[1:])+0x20, index)
elif s[0]=="d": # direct hex; unambiguous
return (int("0x"+s[1:],0), index)
else:
print("error : "+s+" is not a valid register name")
def getRegisterFromNameSrc2(s):
if s[0]=="o": # output
print("error : "+s+" cannot be accessed from src2")
elif s[0]=="v": # attribute
return int(s[1:])
elif s[0]=="r": # temporary register
return int(s[1:])+0x10
elif s[0]=="c": # uniform
print("error : "+s+" cannot be accessed from src2")
elif s[0]=="d": # direct hex; unambiguous
return int("0x"+s[1:],0)
else:
print("error : "+s+" is not a valid register name")
def assembleFormat11(d):
return (d["opcode"]<<26)|((d["dst"]&0x1F)<<24)|((d["src1"]&0x7F)<<17)|((d["src2"]&0x7F)<<10)|((d["src3"]&0x1F)<<5)|(d["extid"]&0x1F)
def parseFormat11(dvle, s):
operandFmt="[^\s,]*"
descFmt="(?:(?:0x)[0-9a-f]+)|[0-9a-f]+"
p=re.compile("^\s*("+operandFmt+"),\s*("+operandFmt+"),\s*("+operandFmt+"),\s*("+operandFmt+")\s*\(("+descFmt+")\)")
r=p.match(s)
if r:
src1 = getRegisterFromNameSrc1(r.group(2))
src2 = getRegisterFromNameSrc1(r.group(3))
return {"dst" : getRegisterFromNameDst(r.group(1)),
"src1" : src1[0],
"src2" : src2[0],
"src3" : getRegisterFromNameSrc2(r.group(4)),
"extid" : int(r.group(5),0)}
else:
raise Exception("encountered error while parsing instruction")
def assembleFormat12(d):
return (d["opcode"]<<26)|((d["dst"]&0x1F)<<24)|((d["src1"]&0x7F)<<17)|((d["src2"]&0x1F)<<12)|((d["src3"]&0x7F)<<5)|(d["extid"]&0x1F)
def parseFormat12(dvle, s):
operandFmt="[^\s,]*"
descFmt="(?:(?:0x)[0-9a-f]+)|[0-9a-f]+"
p=re.compile("^\s*("+operandFmt+"),\s*("+operandFmt+"),\s*("+operandFmt+"),\s*("+operandFmt+")\s*\(("+descFmt+")\)")
r=p.match(s)
if r:
src1 = getRegisterFromNameSrc1(r.group(2))
src3 = getRegisterFromNameSrc1(r.group(4))
return {"dst" : getRegisterFromNameDst(r.group(1)),
"src1" : src1[0],
"src2" : getRegisterFromNameSrc2(r.group(3)),
"src3" : src3[0],
"extid" : int(r.group(5),0)}
else:
raise Exception("encountered error while parsing instruction")
def assembleFormat1(d):
return (d["opcode"]<<26)|((d["dst"]&0x1F)<<21)|((d["idx"]&0x3)<<19)|((d["src1"]&0x7F)<<12)|((d["src2"]&0x1F)<<7)|(d["extid"]&0x7F)
def parseFormat1(dvle, s):
operandFmt="[^\s,]*"
descFmt="(?:(?:0x)[0-9a-f]+)|[0-9a-f]+"
p=re.compile("^\s*("+operandFmt+"),\s*("+operandFmt+"),\s*("+operandFmt+")\s*\(("+descFmt+")\)")
r=p.match(s)
if r:
src1 = getRegisterFromNameSrc1(r.group(2))
return {"dst" : getRegisterFromNameDst(r.group(1)),
"src1" : src1[0],
"idx" : src1[1],
"src2" : getRegisterFromNameSrc2(r.group(3)),
"extid" : int(r.group(4),0)}
else:
raise Exception("encountered error while parsing instruction")
def assembleFormat2(d):
print(d)
return (d["opcode"]<<26)|((d["flags"]&0xF)<<22)|((d["addr"]&0xFFF)<<10)|(d["ret"]&0x3FF)
def parseFormat2(dvle, s):
operandFmt1="[^\s,]*"
# operandFmt3="0b[01]+"
operandFmt3="([!]?)cmp.([xy])"
operandFmt3=operandFmt3+"\s*(?:(&&|\|\|)\s*"+operandFmt3+")?"
p=re.compile("^\s*("+operandFmt1+"),\s*("+operandFmt1+"),\s*"+operandFmt3+"\s*$")
# p=re.compile("^\s*("+operandFmt1+"),\s*("+operandFmt1+"),\s*("+operandFmt3+")\s*")
r=p.match(s)
if r:
neg = [0 if r.group(3)=="!" else 1, 0 if r.group(6)=="!" else 1]
comp = [2 if r.group(4)=="y" else 3, None if r.group(7)==None else (2 if r.group(7)=="y" else 3)]
op = r.group(5)
if comp[0]!=comp[1]:
flags=0
flags|=neg[0]<<comp[0]
flags|=neg[1]<<comp[1] if comp[1]!=None else 0
flags|=1 if op=="&&" else (0 if op=="||" else (3 if comp[0]==2 else 2))
# print(s)
# flags=int(r.group(3),0)
print(bin(flags))
return {"addr" : dvle.getLabelAddress(r.group(2)),
"ret" : dvle.getLabelAddress(r.group(1))-dvle.getLabelAddress(r.group(2)),
"flags" : flags}
else:
raise Exception("invalid or redundant condition "+s)
else:
raise Exception("encountered error while parsing instruction "+s)
def assembleFormat3(d):
return (d["opcode"]<<26)
def parseFormat3(dvle, s):
# doesn't check that there are no operands.
# (but really if you want to be an idiot and add useless operands to your code, go ahead)
return {}
def assembleFormat4(d):
return (d["opcode"]<<26)|((d["dst"]&0x1F)<<21)|((d["idx"]&0x3)<<19)|((d["src1"]&0x7F)<<12)|(d["extid"]&0x7F)
def parseFormat4(dvle, s):
operandFmt="[^\s,]*"
descFmt="(?:(?:0x)[0-9a-f]+)|[0-9a-f]+"
p=re.compile("^\s*("+operandFmt+"),\s*("+operandFmt+")\s*\(("+descFmt+")\)")
r=p.match(s)
if r:
src1 = getRegisterFromNameSrc1(r.group(2))
return {"dst" : getRegisterFromNameDst(r.group(1)),
"src1" : src1[0],
"idx" : src1[1],
"extid" : int(r.group(3),0)}
else:
raise Exception("encountered error while parsing instruction "+s)
def assembleFormat5(d):
return (d["opcode"]<<26)|((d["cmpx"]&0x7)<<24)|((d["cmpy"]&0x7)<<21)|((d["src1"]&0x7F)<<12)|((d["src2"]&0x1F)<<7)|(d["extid"]&0x7F)
cmpOp = {"eq" : 0x0, "ne" : 0x1, "lt" : 0x2, "le" : 0x3, "gt" : 0x4, "ge" : 0x5}
def parseFormat5(dvle, s):
operandFmt="[^\s,]*"
descFmt="(?:(?:0x)[0-9a-f]+)|[0-9a-f]+"
opFmt="[a-z]+"
p=re.compile("^\s*("+operandFmt+"),\s*("+opFmt+"),\s*("+opFmt+"),\s*("+operandFmt+")\s*\(("+descFmt+")\)")
r=p.match(s)
if r:
src1 = getRegisterFromNameSrc1(r.group(1))
return {"src1" : src1[0],
"idx" : src1[1],
"cmpx" : cmpOp[r.group(2)],
"cmpy" : cmpOp[r.group(3)],
"src2" : getRegisterFromNameSrc2(r.group(4)),
"extid" : int(r.group(5),0)}
else:
raise Exception("encountered error while parsing instruction (5)")
def assembleFormat6(d):
return (d["opcode"]<<26)|((d["dst"]&0x1F)<<21)|((d["src2"]&0x7F)<<7)|((d["src1"]&0x1F)<<14)|(d["extid"]&0x7F)
def parseFormat7(dvle, s):
operandFmt1="[^\s,]*"
operandFmt3="i[0-9]+"
p=re.compile("^\s*("+operandFmt1+"),\s*("+operandFmt3+")")
r=p.match(s)
if r:
return {"addr" : dvle.getLabelAddress(r.group(1))-1,
"ret" : 0,
"int" : int(r.group(2).strip()[1:],0)}
else:
raise Exception("encountered error while parsing instruction")
def assembleFormat7(d):
return (d["opcode"]<<26)|((d["int"]&0xF)<<22)|((d["addr"]&0xFFF)<<10)|(d["ret"]&0x3FF)
def parseFormat8(dvle, s):
operandFmt1="[^\s,]*"
operandFmt3="b[0-9]+"
p=re.compile("^\s*("+operandFmt1+"),\s*("+operandFmt1+"),\s*("+operandFmt3+")")
r=p.match(s)
if r:
return {"addr" : dvle.getLabelAddress(r.group(2)),
"ret" : dvle.getLabelAddress(r.group(1))-dvle.getLabelAddress(r.group(2)),
"bool" : int(r.group(3).strip()[1:],0)}
else:
raise Exception("encountered error while parsing instruction")
def assembleFormat8(d):
return (d["opcode"]<<26)|((d["bool"]&0xF)<<22)|((d["addr"]&0xFFF)<<10)|(d["ret"]&0x3FF)
def parseFormat9(dvle, s):
operandFmt1="true|false"
operandFmt3="vtx[0-9]+"
p=re.compile("^\s*("+operandFmt3+"),\s*("+operandFmt1+"),\s*("+operandFmt1+")")
r=p.match(s)
if r:
return {"unk" : r.group(3)=="true",
"prim" : r.group(2)=="true",
"vtx" : int(r.group(1).strip()[3:],0)}
else:
raise Exception("encountered error while parsing instruction")
def assembleFormat9(d):
return (d["opcode"]<<26)|((d["vtx"]&0x3)<<24)|((d["unk"]&0x1)<<22)|((d["prim"]&0x1)<<23)
def parseFormat10(dvle, s):
operandFmt1="[^\s,]*"
p=re.compile("^\s*("+operandFmt1+"),\s*("+operandFmt1+")")
r=p.match(s)
if r:
return {"addr" : dvle.getLabelAddress(r.group(1)),
"ret" : dvle.getLabelAddress(r.group(2))-dvle.getLabelAddress(r.group(1)),
"flags" : 0x0}
else:
raise Exception("encountered error while parsing instruction")
instList={}
fmtList=[(parseFormat1, assembleFormat1), (parseFormat2, assembleFormat2), (parseFormat3, assembleFormat3), (parseFormat4, assembleFormat4), (parseFormat5, assembleFormat5), (parseFormat1, assembleFormat6), (parseFormat7, assembleFormat7), (parseFormat8, assembleFormat8), (parseFormat9, assembleFormat9), (parseFormat10, assembleFormat2), (parseFormat11, assembleFormat11), (parseFormat12, assembleFormat12)]
instList["add"]={"opcode" : 0x00, "format" : 0}
instList["dp3"]={"opcode" : 0x01, "format" : 0}
instList["dp4"]={"opcode" : 0x02, "format" : 0}
instList["dph"]={"opcode" : 0x03, "format" : 0}
instList["op4"]={"opcode" : 0x04, "format" : 0}
instList["ex2"]={"opcode" : 0x05, "format" : 3}
instList["lg2"]={"opcode" : 0x06, "format" : 3}
instList["op7"]={"opcode" : 0x07, "format" : 3}
instList["mul"]={"opcode" : 0x08, "format" : 0}
instList["sge"]={"opcode" : 0x09, "format" : 0}
instList["slt"]={"opcode" : 0x0a, "format" : 0}
instList["flr"]={"opcode" : 0x0B, "format" : 3}
instList["max"]={"opcode" : 0x0C, "format" : 0}
instList["min"]={"opcode" : 0x0D, "format" : 0}
instList["rcp"]={"opcode" : 0x0E, "format" : 3}
instList["rsq"]={"opcode" : 0x0F, "format" : 3}
instList["mova"]={"opcode" : 0x12, "format" : 3}
instList["mov"]={"opcode" : 0x13, "format" : 3}
instList["dphi"]={"opcode" : 0x18, "format" : 5}
instList["op19"]={"opcode" : 0x19, "format" : 5}
instList["sgei"]={"opcode" : 0x1a, "format" : 5}
instList["slti"]={"opcode" : 0x1b, "format" : 5}
instList["nop"]={"opcode" : 0x21, "format" : 2}
instList["end"]={"opcode" : 0x22, "format" : 2}
instList["call"] ={"opcode" : 0x24, "format" : 9}
instList["ifu"] ={"opcode" : 0x27, "format" : 7}
instList["ifc"] ={"opcode" : 0x28, "format" : 1}
instList["loop"] ={"opcode" : 0x29, "format" : 6}
instList["emit"]={"opcode" : 0x2a, "format" : 2}
instList["setemit"]={"opcode" : 0x2b, "format" : 8}
instList["cmp"]={"opcode" : 0x2e, "format" : 4}
instList["madi"]={"opcode" : 0x30, "format" : 11}
instList["mad"]={"opcode" : 0x38, "format" : 10}
def parseConst(dvlp, dvle, s):
s=s.split(",")
s[0]=s[0].strip()
if s[0][0]=="b":
# bool constant
dvle.addConstantB((int(s[0][1:],0), int(s[1])))
elif s[0][0]=="i":
# int vec4 constant
dvle.addConstantI((int(s[0][1:],0), int(s[1],0), int(s[2],0), int(s[3],0), int(s[4],0)))
elif s[0][0]=="c":
# float vec4 constant
dvle.addConstantF((int(s[0][1:],0), float(s[1]), float(s[2]), float(s[3]), float(s[4])))
outputTypes={"result.position" : 0x0,
"result.normalquat" : 0x1,
"result.color" : 0x2,
"result.texcoord0" : 0x3,
"result.texcoord0w" : 0x4,
"result.texcoord1" : 0x5,
"result.texcoord2" : 0x6,
"result.view" : 0x8}
def parseOut(dvlp, dvle, s):
s=s.split(",")
s[0]=s[0].replace(" ", "")
s[1]=s[1].replace(" ", "")
s[2]=s[2].replace(" ", "")
reg=int(s[0][1:])
if s[1] in outputTypes:
type=outputTypes[s[1]]
mask=int(s[2], 0)
dvle.addOutput((type|(reg<<16), mask))
swizVal={"w":0x3,"z":0x2,"y":0x1,"x":0x0}
def parseOpdesc(dvlp, dvle, s):
s=s.split(",")
for k in range(len(s)):
s[k]=s[k].replace(" ", "")
#dst mask
mask=0
for k in range(4):
if s[0][k]!="_":
mask|=1<<(3-k)
swiz=[0,0,0]
neg=[0,0,0]
for i in range(len(s)-1):
l=s[1+i]
if l[0]=='-':
neg[i]=1
l=l[1:]
for k in range(4):
swiz[i]=((swiz[i]<<2)|swizVal[l[k]])
dvlp.addOpdesc(((1<<31)|(swiz[2]<<23)|(neg[2]<<22)|(swiz[1]<<14)|(neg[1]<<13)|(swiz[0]<<5)|(neg[0]<<4)|(mask),0x0000000F))
def parseUniform(dvlp, dvle, s):
s=s.split(",")
for k in range(len(s)):
s[k]=s[k].replace(" ", "")
type=s[0][0]
if type!=s[1][0]:
print("inconsistent uniform register assignment !")
return
if type=="c":
offset=0x10
elif type=="i":
offset=0x70
elif type=="b":
offset=0x78
dvle.addInput((int(s[0][1:],0)+offset,int(s[1][1:],0)+offset,s[2]))
def parseVsh(dvlp, dvle, s):
global vshMain, vshEndmain
s=s.split(",")
for k in range(len(s)):
s[k]=s[k].replace(" ", "")
vshMain, vshEndmain = s[0], s[1]
def parseGsh(dvlp, dvle, s):
global gshMain, gshEndmain
s=s.split(",")
for k in range(len(s)):
s[k]=s[k].replace(" ", "")
gshMain, gshEndmain = s[0], s[1]
dirList={}
dirList["const"]=(parseConst)
dirList["out"]=(parseOut)
dirList["opdesc"]=(parseOpdesc)
dirList["uniform"]=(parseUniform)
dirList["vsh"]=(parseVsh)
dirList["gsh"]=(parseGsh)
def parseInstruction(dvle, s):
s=s.lower()
p=re.compile("^\s*([^\s]*)(.*)")
r=p.match(s)
if r:
name=r.group(1)
if name in instList:
fmt=instList[name]["format"]
out=fmtList[fmt][0](dvle, r.group(2))
out["opcode"]=instList[name]["opcode"]
v=fmtList[fmt][1](out)
return v
else:
print(name+" : no such instruction")
return None
def parseLabel(s):
s=s.lower()
p=re.compile("^\s*([a-z_0-9]*):")
r=p.match(s)
if r:
return r.group(1)
return None
def parseLine(dvlp, dvle, l, mode):
l=l.split(";")[0] #remove comments
k=0
while (k<len(l) and (l[k]==" " or l[k]==" ")):
k+=1
l=l[k:]
if len(l)>1:
if l[0]==".": #directive
if not(mode):
p=re.compile("^\s*\.([^\s]*)(.*)")
r=p.match(l)
if r:
name=r.group(1)
if name in dirList:
dirList[name](dvlp, dvle, r.group(2))
else:
print(name+" : no such directive")
else:
v=parseLabel(l)
if v: #label
if not(mode):
dvle.addLabel((dvlp.getCodelength(), v))
else: #instruction
v=parseInstruction(dvle, l)
if v:
dvlp.addInstruction(v)
if len(sys.argv)<3:
print("AEMSTRO AS :")
print(" aemstro_as.py <input.vsh> <output.shbin>")
else:
dvlb=DVLB()
vsh_dvle=DVLE(0x0)
with open(sys.argv[1], "r") as f:
for line in f:
parseLine(dvlb.getDVLP(), vsh_dvle, line, False)
dvlb.getDVLP().clearCode()
with open(sys.argv[1], "r") as f:
for line in f:
parseLine(dvlb.getDVLP(), vsh_dvle, line, True)
vsh_dvle.setMain(vsh_dvle.getLabelAddress(vshMain))
vsh_dvle.setEndmain(vsh_dvle.getLabelAddress(vshEndmain))
dvlb.addDVLE(vsh_dvle)
if gshMain!=None and gshEndmain!=None:
gsh_dvle=copy.deepcopy(vsh_dvle)
gsh_dvle._type=0x1
gsh_dvle.setMain(gsh_dvle.getLabelAddress(gshMain))
gsh_dvle.setEndmain(gsh_dvle.getLabelAddress(gshEndmain))
dvlb.addDVLE(gsh_dvle)
open(sys.argv[2],"wb").write(dvlb.toBinary())

43
libs/aemstro/test.vsh Normal file
View file

@ -0,0 +1,43 @@
; setup constants
.const 5, 0.0, 1.0, 2.0, 3.0
; setup outmap
.out o0, result.position
.out o1, result.color
.out o2, result.texcoord0
.out o3, result.texcoord1
.out o4, result.texcoord2
; setup uniform map (not required)
.uniform 0x10, 0x13, mdlvMtx
.uniform 0x14, 0x17, projMtx
;code
main:
; result.pos = mdlvMtx * in.pos
dp4 d40, d40, d00 (0x0)
dp4 d40, d41, d00 (0x1)
dp4 d40, d42, d00 (0x2)
mov d40, d25 (0x4)
; result.pos = projMtx * in.pos
dp4 d00, d44, d40 (0x0)
dp4 d00, d45, d40 (0x1)
dp4 d00, d46, d40 (0x2)
dp4 d00, d47, d40 (0x3)
; result.color = in.pos
mov d04, d25 (0x5)
; result.texcoord = const
mov d08, d25 (0x5)
mov d0C, d25 (0x5)
mov d10, d25 (0x5)
flush
end
endmain:
;operand descriptors
.opdesc x___, xyzw, xyzw ; 0x0
.opdesc _y__, xyzw, xyzw ; 0x1
.opdesc __z_, xyzw, xyzw ; 0x2
.opdesc ___w, xyzw, xyzw ; 0x3
.opdesc ___w, yyyy, xyzw ; 0x4
.opdesc xyzw, xyzw, xyzw ; 0x5

21
libs/sf2dlib/LICENSE Normal file
View file

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 Sergi Granell (xerpi), xerpi.g.12@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

7
libs/sf2dlib/README.md Normal file
View file

@ -0,0 +1,7 @@
## SF2DLIB
Simple and Fast 2D library for the Nintendo 3DS (using ctrulib)
### Documentation
http://xerpi.github.io/sf2dlib/html/sf2d_8h.html

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,142 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/3ds_rules
#---------------------------------------------------------------------------------
# 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
#---------------------------------------------------------------------------------
TARGET := sf2d
BUILD := build
SOURCES := source
DATA := data
INCLUDES := include
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard
CFLAGS := -g -Wall -O2\
$(ARCH)
CFLAGS += $(INCLUDE) -DARM11 -D_3DS
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
ASFLAGS := -g $(ARCH)
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(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)/lib/lib$(TARGET).a
export VPATH := $(foreach dir,$(SOURCES),$(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)))
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
#---------------------------------------------------------------------------------
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
.PHONY: $(BUILD) clean all
#---------------------------------------------------------------------------------
all: $(BUILD)
lib:
@[ -d $@ ] || mkdir -p $@
$(BUILD): lib
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) lib latex html
#---------------------------------------------------------------------------------
install: $(BUILD)
@cp $(OUTPUT) $(CTRULIB)/lib
@cp include/sf2d.h $(CTRULIB)/include
@echo "Installed!"
#---------------------------------------------------------------------------------
docs:
@doxygen Doxyfile
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT) : $(OFILES)
#---------------------------------------------------------------------------------
%.bin.o : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
# WARNING: This is not the right way to do this! TODO: Do it right!
#---------------------------------------------------------------------------------
%_vsh.h %.vsh.o : %.vsh
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@python ../../../aemstro/aemstro_as.py $< ../$(notdir $<).shbin
@bin2s ../$(notdir $<).shbin | $(PREFIX)as -o $@
@echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(notdir $<).shbin | tr . _)`.h
@echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(notdir $<).shbin | tr . _)`.h
@echo "extern const u32" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(notdir $<).shbin | tr . _)`.h
@rm ../$(notdir $<).shbin
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

View file

@ -0,0 +1,39 @@
; setup constants
.const c20, 0.0, 0.0, 0.0, 1.0
; setup outmap
.out o0, result.position, 0xF
.out o1, result.texcoord0, 0x3
.out o2, result.color, 0xF
; setup uniform map (not required)
.uniform c0, c3, projection
.vsh vmain, end_vmain
;code
vmain:
; result.pos = projMtx * in.pos
dp4 o0, c0, v0 (0x0)
dp4 o0, c1, v0 (0x1)
dp4 o0, c2, v0 (0x2)
dp4 o0, c3, v0 (0x3)
; result.texcoord = in.texcoord
mov o1, v1 (0x5)
; result.color = in.color
mov o2, v1 (0x5)
nop
end
end_vmain:
;operand descriptors
.opdesc x___, xyzw, xyzw ; 0x0
.opdesc _y__, xyzw, xyzw ; 0x1
.opdesc __z_, xyzw, xyzw ; 0x2
.opdesc ___w, xyzw, xyzw ; 0x3
.opdesc xyz_, xyzw, xyzw ; 0x4
.opdesc xyzw, xyzw, xyzw ; 0x5
.opdesc x_zw, xyzw, xyzw ; 0x6
.opdesc xyzw, yyyw, xyzw ; 0x7
.opdesc xyz_, wwww, wwww ; 0x8
.opdesc xyz_, yyyy, xyzw ; 0x9

View file

@ -0,0 +1,496 @@
/**
* @file sf2d.h
* @author Sergi Granell (xerpi)
* @date 22 March 2015
* @brief sf2dlib header
*/
#ifndef SF2D_H
#define SF2D_H
#include <3ds.h>
#ifdef __cplusplus
extern "C" {
#endif
// Defines
/**
* @brief Creates a new RGBA8 color
* @param r the red component of the color to create
* @param g the green component of the color to create
* @param b the blue component of the color to create
* @param a the alpha component of the color to create
*/
#define RGBA8(r, g, b, a) ((((r)&0xFF)<<24) | (((g)&0xFF)<<16) | (((b)&0xFF)<<8) | (((a)&0xFF)<<0))
/**
* @brief Default size of the GPU commands FIFO buffer
*/
#define SF2D_GPUCMD_DEFAULT_SIZE 0x80000
/**
* @brief Default size of the temporary memory pool
*/
#define SF2D_TEMPPOOL_DEFAULT_SIZE 0x80000
/**
* @brief Default depth (Z coordinate) to draw the textures to
*/
#define SF2D_DEFAULT_DEPTH 0.5f
// Enums
/**
* @brief Represents a texture format
*/
typedef enum {
TEXFMT_RGBA8 = 0,
TEXFMT_RGB8 = 1,
TEXFMT_RGB5A1 = 2,
TEXFMT_RGB565 = 3,
TEXFMT_RGBA4 = 4,
TEXFMT_IA8 = 5,
TEXFMT_I8 = 7,
TEXFMT_A8 = 8,
TEXFMT_IA4 = 9,
TEXFMT_I4 = 10,
TEXFMT_A4 = 11,
TEXFMT_ETC1 = 12,
TEXFMT_ETC1A4 = 13
} sf2d_texfmt;
/**
* @brief Data allocated on the RAM or VRAM
*/
typedef enum {
SF2D_PLACE_RAM, /**< RAM allocated */
SF2D_PLACE_VRAM, /**< VRAM allocated */
SF2D_PLACE_TEMP /**< Temporary memory pool allocated */
} sf2d_place;
// Structs
/**
* @brief Represents a two dimensional float vector
*/
typedef struct {
float u; /**< First component of the vector */
float v; /**< Second component of the vector */
} sf2d_vector_2f;
/**
* @brief Represents a three dimensional float vector
*/
typedef struct {
float x; /**< First component of the vector */
float y; /**< Second component of the vector */
float z; /**< Third component of the vector */
} sf2d_vector_3f;
/**
* @brief Represents a four dimensional float vector
*/
typedef struct {
float r; /**< Red component of the vector/color */
float g; /**< Green component of the vector/color */
float b; /**< Blue component of the vector/color */
float a; /**< Alpha component of the vector/color */
} sf2d_vector_4f;
/**
* @brief Represents a vertex containing position and color attributes
*/
typedef struct {
sf2d_vector_3f position; /**< Position of the vertex */
sf2d_vector_4f color; /**< Color of the vertex */
} sf2d_vertex_pos_col;
/**
* @brief Represents a vertex containing position and texture coordinates
*/
typedef struct {
sf2d_vector_3f position; /**< Position of the vertex */
sf2d_vector_2f texcoord; /**< Texture coordinates of the vertex */
} sf2d_vertex_pos_tex;
/**
* @brief Represents a texture
*/
typedef struct {
sf2d_place place; /**< Where the texture data resides, RAM or VRAM */
int tiled; /**< Whether the tetxure is tiled or not */
sf2d_texfmt pixel_format; /**< Pixel format */
int width; /**< Texture width */
int height; /**< Texture height */
int pow2_w; /**< Nearest power of 2 >= width */
int pow2_h; /**< Nearest power of 2 >= height */
int data_size; /**< Size of the raw texture data */
void *data; /**< Pointer to the data */
} sf2d_texture;
// Basic functions
/**
* @brief Initializates the library
* @return Whether the initialization has been successful or not
*/
int sf2d_init();
/**
* @brief Initializates the library (with advanced settings)
* @param gpucmd_size the size of the GPU FIFO
* @param temppool_size the size of the temporary pool
* @return Whether the initialization has been successful or not
*/
int sf2d_init_advanced(int gpucmd_size, int temppool_size);
/**
* @brief Finishes the library
* @return Whether the finalization has been successful or not
*/
int sf2d_fini();
/**
* @brief Enables or disables the 3D
* @param enable whether to enable or disable the 3D
*/
void sf2d_set_3D(int enable);
/**
* @brief Starts a frame
* @param screen target screen
* @param side target eye (only for top screen)
*/
void sf2d_start_frame(gfxScreen_t screen, gfx3dSide_t side);
/**
* @brief Ends a frame, should be called on pair with sf2d_start_frame
*/
void sf2d_end_frame();
/**
* @brief Swaps the framebuffers, should be called once after all the frames have been finished
*/
void sf2d_swapbuffers();
/**
* @brief Enables or disables the VBlank waiting
* @param enable whether to enable or disable the VBlank waiting
*/
void sf2d_set_vblank_wait(int enable);
/**
* @brief Returns the FPS (frames per second)
* @return the current FPS
*/
float sf2d_get_fps();
/**
* @brief Allocates memory from a temporary pool. The pool will be emptied after a sf2d_swapbuffers call
* @param size the number of bytes to allocate
*/
void *sf2d_pool_malloc(u32 size);
/**
* @brief Allocates aligned memory from a temporary pool. Works as sf2d_pool_malloc
* @param size the number of bytes to allocate
* @param alignment the alignment to where allocate the memory
*/
void *sf2d_pool_memalign(u32 size, u32 alignment);
/**
* @brief Returns the temporary pool's free space
* @return the temporary pool's free space
*/
unsigned int sf2d_pool_space_free();
/**
* @brief Empties the temporary pool
*/
void sf2d_pool_reset();
/**
* @brief Sets the screen clear color
* @param color the color
*/
void sf2d_set_clear_color(u32 color);
// Draw functions
/**
* @brief Draws a line
* @param x0 x coordinate of the first dot
* @param y0 y coordinate of the first dot
* @param x1 x coordinate of the second dot
* @param y1 y coordinate of the sceond dot
* @param color the color to draw the line
*/
void sf2d_draw_line(int x0, int y0, int x1, int y1, u32 color);
/**
* @brief Draws a rectangle
* @param x x coordinate of the top left corner of the rectangle
* @param y y coordinate of the top left corner of the rectangle
* @param w rectangle width
* @param h rectangle height
* @param color the color to draw the rectangle
*/
void sf2d_draw_rectangle(int x, int y, int w, int h, u32 color);
/**
* @brief Draws a rotated rectangle
* @param x x coordinate of the top left corner of the rectangle
* @param y y coordinate of the top left corner of the rectangle
* @param w rectangle width
* @param h rectangle height
* @param color the color to draw the rectangle
* @param rad rotation (in radians) to draw the rectangle
*/
void sf2d_draw_rectangle_rotate(int x, int y, int w, int h, u32 color, float rad);
/**
* @brief Draws a filled circle
* @param x x coordinate of the center of the circle
* @param y y coordinate of the center of the circle
* @param radius the radius of the circle
* @param color the color to draw the circle
*/
void sf2d_draw_fill_circle(int x, int y, int radius, u32 color);
// Texture
/**
* @brief Creates an empty texture.
* The returned texture has the data allocated,
* this means that the raw pixel data can be filled
* just after the return.
* @param width the width of the texture
* @param height the height of the texture
* @param pixel_format the pixel_format of the texture
* @param place where to allocate the texture
* @return a pointer to the newly created texture
*/
sf2d_texture *sf2d_create_texture(int width, int height, sf2d_texfmt pixel_format, sf2d_place place);
/**
* @brief Frees a texture
* @param texture pointer to the texture to freeze
*/
void sf2d_free_texture(sf2d_texture *texture);
/**
* @brief Fills an already allocated texture from a RGBA8 source
* @param dst pointer to the destination texture to fill
* @param rgba8 pointer to the RGBA8 data to fill from
* @param source_w width (in pixels) of the RGAB8 source
* @param source_h height (in pixels) of the RGAB8 source
*/
void sf2d_fill_texture_from_RGBA8(sf2d_texture *dst, const void *rgba8, int source_w, int source_h);
/**
* @brief Creates a texture and fills it from a RGBA8 memory source.
* The returned texture is already tiled.
* @param src_buffer pointer to the RGBA8 data to fill from
* @param src_w width (in pixels) of the RGAB8 source
* @param src_h height (in pixels) of the RGAB8 source
* @param pixel_format the pixel_format of the texture to create
* @param place where to allocate the texture
* @return a pointer to the newly created, filled, and tiled texture
*/
sf2d_texture *sf2d_create_texture_mem_RGBA8(const void *src_buffer, int src_w, int src_h, sf2d_texfmt pixel_format, sf2d_place place);
/**
* @brief Binds a texture to a GPU texture unit
* @param texture the texture to bind
* @param unit GPU texture unit to bind to
*/
void sf2d_bind_texture(const sf2d_texture *texture, GPU_TEXUNIT unit);
/**
* @brief Binds a texture to a GPU texture unit with a constant color
* @param texture the texture to bind
* @param unit GPU texture unit to bind to
* @param color the color the bind with the texture
*/
void sf2d_bind_texture_color(const sf2d_texture *texture, GPU_TEXUNIT unit, u32 color);
/**
* @brief Binds a texture to a GPU texture unit with custom parameters
* @param texture the texture to bind
* @param unit GPU texture unit to bind to
* @param params the parameters the bind with the texture
*/
void sf2d_bind_texture_parameters(const sf2d_texture *texture, GPU_TEXUNIT unit, unsigned int params);
/**
* @brief Draws a texture
* @param texture the texture to draw
* @param x the x coordinate to draw the texture to
* @param y the y coordinate to draw the texture to
*/
void sf2d_draw_texture(const sf2d_texture *texture, int x, int y);
/**
* @brief Draws a texture with rotation
* @param texture the texture to draw
* @param x the x coordinate to draw the texture to
* @param y the y coordinate to draw the texture to
* @param rad rotation (in radians) to draw the texture
*/
void sf2d_draw_texture_rotate(const sf2d_texture *texture, int x, int y, float rad);
/**
* @brief Draws a part of a texture
* @param texture the texture to draw
* @param x the x coordinate to draw the texture to
* @param y the y coordinate to draw the texture to
* @param tex_x the starting point (x coordinate) where to start drawing
* @param tex_y the starting point (y coordinate) where to start drawing
* @param tex_w the width to draw from the starting point
* @param tex_h the height to draw from the starting point
*/
void sf2d_draw_texture_part(const sf2d_texture *texture, int x, int y, int tex_x, int tex_y, int tex_w, int tex_h);
/**
* @brief Draws a texture with scaling
* @param texture the texture to draw
* @param x the x coordinate to draw the texture to
* @param y the y coordinate to draw the texture to
* @param x_scale the x scale
* @param y_scale the y scale
*/
void sf2d_draw_texture_scale(const sf2d_texture *texture, int x, int y, float x_scale, float y_scale);
/**
* @brief Draws a part of a texture, with rotation and scaling
* @param texture the texture to draw
* @param x the x coordinate to draw the texture to
* @param y the y coordinate to draw the texture to
* @param rad rotation (in radians) to draw the texture
* @param tex_x the starting point (x coordinate) where to start drawing
* @param tex_y the starting point (y coordinate) where to start drawing
* @param tex_w the width to draw from the starting point
* @param tex_h the height to draw from the starting point
* @param x_scale the x scale
* @param y_scale the y scale
*/
void sf2d_draw_texture_rotate_cut_scale(const sf2d_texture *texture, int x, int y, float rad, int tex_x, int tex_y, int tex_w, int tex_h, float x_scale, float y_scale);
/**
* @brief Draws a texture blended with a color
* @param texture the texture to draw
* @param x the x coordinate to draw the texture to
* @param y the y coordinate to draw the texture to
* @param color the color to blend with the texture
*/
void sf2d_draw_texture_blend(const sf2d_texture *texture, int x, int y, u32 color);
/**
* @brief Draws a part of a texture blended with a color
* @param texture the texture to draw
* @param x the x coordinate to draw the texture to
* @param y the y coordinate to draw the texture to
* @param tex_x the starting point (x coordinate) where to start drawing
* @param tex_y the starting point (y coordinate) where to start drawing
* @param tex_w the width to draw from the starting point
* @param tex_h the height to draw from the starting point
* @param color the color to blend with the texture
*/
void sf2d_draw_texture_part_blend(const sf2d_texture *texture, int x, int y, int tex_x, int tex_y, int tex_w, int tex_h, u32 color);
/**
* @brief Draws a texture blended in a certain depth
* @param texture the texture to draw
* @param x the x coordinate to draw the texture to
* @param y the y coordinate to draw the texture to
* @param z the depth to draw the texture to
* @note The z parameter is a value in the [-32768, +32767] range,
* where -32768 is the deepest and +32767 the toppest.
* By default, the textures are drawn at z = 0.
* Keep in mind that this function won't do
* Order-independent transparency (OIT), so you should use fully
* opaque textures to get good results.
*/
void sf2d_draw_texture_depth(const sf2d_texture *texture, int x, int y, signed short z);
/**
* @brief Draws a texture using custom texture coordinates and parameters
* @param texture the texture to draw
* @param left the left coordinate of the texture to start drawing
* @param top the top coordinate of the texture to start drawing
* @param width the width to draw from the starting left coordinate
* @param height the height to draw from the starting top coordinate
* @param u0 the U texture coordinate of the left vertices
* @param v0 the V texture coordinate of the top vertices
* @param u1 the U texture coordinate of the right vertices
* @param v1 the V texture coordinate of the bottom vertices
* @param params the parameters to draw the texture with
*/
void sf2d_draw_quad_uv(const sf2d_texture *texture, float left, float top, float right, float bottom,
float u0, float v0, float u1, float v1, unsigned int params);
/**
* @brief Changes a pixel of the texture
* @param texture the texture to change the pixel
* @param x the x coordinate to change the pixel
* @param y the y coordinate to change the pixel
* @param new_color the new color to set to the pixel at (x, y)
*/
void sf2d_set_pixel(sf2d_texture *texture, int x, int y, u32 new_color);
/**
* @brief Gets a pixel of the texture
* @param texture the texture to get the pixel
* @param x the x coordinate to get the pixel
* @param y the y coordinate to get the pixel
* @return the pixel at (x, y)
*/
u32 sf2d_get_pixel(sf2d_texture *texture, int x, int y);
/**
* @brief Tiles a texture
* @param texture the texture to tile
*/
void sf2d_texture_tile32(sf2d_texture *texture);
/**
* @brief Sets the scissor test
* @param mode the test mode (disable, invert or normal)
* @param x the starting x coordinate of the scissor
* @param y the starting y coordinate of the scissor
* @param w the width of the scissor rectangle
* @param h the height of the scissor rectangle
* @note This function should be called after sf2d_start_frame.
* The scissor will remain active until the sf2d_end_frame call.
*/
void sf2d_set_scissor_test(GPU_SCISSORMODE mode, u32 x, u32 y, u32 w, u32 h);
/**
* @brief Returns the current screen (latest call to sf2d_start_frame)
* @note The returned value can be GFX_TOP or GFX_BOTTOM.
*/
gfxScreen_t sf2d_get_current_screen();
/**
* @brief Returns the current screen side (latest call to sf2d_start_frame)
* @note The returned value can be GFX_LEFT or GFX_RIGHT.
*/
gfx3dSide_t sf2d_get_current_side();
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,29 @@
#ifndef SF2D_PRIVATE_H
#define SF2D_PRIVATE_H
#include <3ds.h>
#include "sf2d.h"
void GPU_SetDummyTexEnv(u8 num);
// Vector operations
void vector_mult_matrix4x4(const float *msrc, const sf2d_vector_3f *vsrc, sf2d_vector_3f *vdst);
// Matrix operations
void matrix_copy(float *dst, const float *src);
void matrix_identity4x4(float *m);
void matrix_mult4x4(const float *src1, const float *src2, float *dst);
void matrix_set_z_rotation(float *m, float rad);
void matrix_rotate_z(float *m, float rad);
void matrix_set_scaling(float *m, float x_scale, float y_scale, float z_scale);
void matrix_swap_xy(float *m);
void matrix_init_orthographic(float *m, float left, float right, float bottom, float top, float near, float far);
void matrix_gpu_set_uniform(const float *m, u32 startreg);
unsigned int next_pow2(unsigned int v);
#endif

View file

@ -0,0 +1,303 @@
#include "sf2d.h"
#include "sf2d_private.h"
#include "shader_vsh_shbin.h"
static int sf2d_initialized = 0;
static u32 clear_color = RGBA8(0x00, 0x00, 0x00, 0xFF);
static u32 *gpu_cmd = NULL;
//GPU init variables
static int gpu_cmd_size = 0;
// Temporary memory pool
static void *pool_addr = NULL;
static u32 pool_index = 0;
static u32 pool_size = 0;
//GPU framebuffer address
static u32 *gpu_fb_addr = NULL;
//GPU depth buffer address
static u32 *gpu_depth_fb_addr = NULL;
//VBlank wait
static int vblank_wait = 1;
//FPS calculation
static float current_fps = 0.0f;
static unsigned int frames = 0;
static u64 last_time = 0;
//Current screen/side
static gfxScreen_t cur_screen = GFX_TOP;
static gfx3dSide_t cur_side = GFX_LEFT;
//Shader stuff
static DVLB_s *dvlb = NULL;
static shaderProgram_s shader;
static u32 projection_desc = -1;
//Matrix
static float ortho_matrix_top[4*4];
static float ortho_matrix_bot[4*4];
//Apt hook cookie
static aptHookCookie apt_hook_cookie;
//Functions
static void apt_hook_func(int hook, void* param);
static void reset_gpu_apt_resume();
int sf2d_init()
{
return sf2d_init_advanced(
SF2D_GPUCMD_DEFAULT_SIZE,
SF2D_TEMPPOOL_DEFAULT_SIZE);
}
int sf2d_init_advanced(int gpucmd_size, int temppool_size)
{
if (sf2d_initialized) return 0;
gpu_fb_addr = vramMemAlign(400*240*8, 0x100);
gpu_depth_fb_addr = vramMemAlign(400*240*8, 0x100);
gpu_cmd = linearAlloc(gpucmd_size * 4);
pool_addr = linearAlloc(temppool_size);
pool_size = temppool_size;
gpu_cmd_size = gpucmd_size;
gfxInitDefault();
GPU_Init(NULL);
gfxSet3D(false);
GPU_Reset(NULL, gpu_cmd, gpucmd_size);
//Setup the shader
dvlb = DVLB_ParseFile((u32 *)shader_vsh_shbin, shader_vsh_shbin_size);
shaderProgramInit(&shader);
shaderProgramSetVsh(&shader, &dvlb->DVLE[0]);
//Get shader uniform descriptors
projection_desc = shaderInstanceGetUniformLocation(shader.vertexShader, "projection");
shaderProgramUse(&shader);
matrix_init_orthographic(ortho_matrix_top, 0.0f, 400.0f, 0.0f, 240.0f, 0.0f, 1.0f);
matrix_init_orthographic(ortho_matrix_bot, 0.0f, 320.0f, 0.0f, 240.0f, 0.0f, 1.0f);
matrix_gpu_set_uniform(ortho_matrix_top, projection_desc);
//Register the apt callback hook
aptHook(&apt_hook_cookie, apt_hook_func, NULL);
vblank_wait = 1;
current_fps = 0.0f;
frames = 0;
last_time = osGetTime();
cur_screen = GFX_TOP;
cur_side = GFX_LEFT;
GPUCMD_Finalize();
GPUCMD_FlushAndRun(NULL);
gspWaitForP3D();
sf2d_pool_reset();
sf2d_initialized = 1;
return 1;
}
int sf2d_fini()
{
if (!sf2d_initialized) return 0;
aptUnhook(&apt_hook_cookie);
gfxExit();
shaderProgramFree(&shader);
DVLB_Free(dvlb);
linearFree(pool_addr);
linearFree(gpu_cmd);
vramFree(gpu_fb_addr);
vramFree(gpu_depth_fb_addr);
sf2d_initialized = 0;
return 1;
}
void sf2d_set_3D(int enable)
{
gfxSet3D(enable);
}
void sf2d_start_frame(gfxScreen_t screen, gfx3dSide_t side)
{
sf2d_pool_reset();
GPUCMD_SetBufferOffset(0);
// Only upload the uniform if the screen changes
if (screen != cur_screen) {
if (screen == GFX_TOP) {
matrix_gpu_set_uniform(ortho_matrix_top, projection_desc);
} else {
matrix_gpu_set_uniform(ortho_matrix_bot, projection_desc);
}
cur_screen = screen;
}
int screen_w;
if (screen == GFX_TOP) {
screen_w = 400;
cur_side = side;
} else {
screen_w = 320;
}
GPU_SetViewport((u32 *)osConvertVirtToPhys((u32)gpu_depth_fb_addr),
(u32 *)osConvertVirtToPhys((u32)gpu_fb_addr),
0, 0, 240, screen_w);
GPU_DepthMap(-1.0f, 0.0f);
GPU_SetFaceCulling(GPU_CULL_NONE);
GPU_SetStencilTest(false, GPU_ALWAYS, 0x00, 0xFF, 0x00);
GPU_SetStencilOp(GPU_KEEP, GPU_KEEP, GPU_KEEP);
GPU_SetBlendingColor(0,0,0,0);
GPU_SetDepthTestAndWriteMask(true, GPU_GEQUAL, GPU_WRITE_ALL);
GPUCMD_AddMaskedWrite(GPUREG_0062, 0x1, 0);
GPUCMD_AddWrite(GPUREG_0118, 0);
GPU_SetAlphaBlending(
GPU_BLEND_ADD,
GPU_BLEND_ADD,
GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA,
GPU_ONE, GPU_ZERO
);
GPU_SetAlphaTest(false, GPU_ALWAYS, 0x00);
GPU_SetDummyTexEnv(1);
GPU_SetDummyTexEnv(2);
GPU_SetDummyTexEnv(3);
GPU_SetDummyTexEnv(4);
GPU_SetDummyTexEnv(5);
}
void sf2d_end_frame()
{
GPU_FinishDrawing();
GPUCMD_Finalize();
GPUCMD_FlushAndRun(NULL);
gspWaitForP3D();
//Copy the GPU rendered FB to the screen FB
if (cur_screen == GFX_TOP) {
GX_SetDisplayTransfer(NULL, gpu_fb_addr, GX_BUFFER_DIM(240, 400),
(u32 *)gfxGetFramebuffer(GFX_TOP, cur_side, NULL, NULL),
GX_BUFFER_DIM(240, 400), 0x1000);
} else {
GX_SetDisplayTransfer(NULL, gpu_fb_addr, GX_BUFFER_DIM(240, 320),
(u32 *)gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL),
GX_BUFFER_DIM(240, 320), 0x1000);
}
gspWaitForPPF();
//Clear the screen
GX_SetMemoryFill(NULL, gpu_fb_addr, clear_color, &gpu_fb_addr[0x2EE00],
0x201, gpu_depth_fb_addr, 0x00000000, &gpu_depth_fb_addr[0x2EE00], 0x201);
gspWaitForPSC0();
}
void sf2d_swapbuffers()
{
gfxSwapBuffersGpu();
if (vblank_wait) {
gspWaitForEvent(GSPEVENT_VBlank0, false);
}
//Calculate FPS
frames++;
u64 delta_time = osGetTime() - last_time;
if (delta_time >= 1000) {
current_fps = frames/(delta_time/1000.0f);
frames = 0;
last_time = osGetTime();
}
}
void sf2d_set_vblank_wait(int enable)
{
vblank_wait = enable;
}
float sf2d_get_fps()
{
return current_fps;
}
void *sf2d_pool_malloc(u32 size)
{
if ((pool_index + size) < pool_size) {
void *addr = (void *)((u32)pool_addr + pool_index);
pool_index += size;
return addr;
}
return NULL;
}
void *sf2d_pool_memalign(u32 size, u32 alignment)
{
u32 new_index = (pool_index + alignment - 1) & ~(alignment - 1);
if ((new_index + size) < pool_size) {
void *addr = (void *)((u32)pool_addr + new_index);
pool_index = new_index + size;
return addr;
}
return NULL;
}
unsigned int sf2d_pool_space_free()
{
return pool_size - pool_index;
}
void sf2d_pool_reset()
{
pool_index = 0;
}
void sf2d_set_clear_color(u32 color)
{
clear_color = color;
}
void sf2d_set_scissor_test(GPU_SCISSORMODE mode, u32 x, u32 y, u32 w, u32 h)
{
if (cur_screen == GFX_TOP) {
GPU_SetScissorTest(mode, 240 - (y + h), 400 - (x + w), 240 - y, 400 - x);
} else {
GPU_SetScissorTest(mode, 240 - (y + h), 320 - (x + w), 240 - y, 320 - x);
}
}
gfxScreen_t sf2d_get_current_screen()
{
return cur_screen;
}
gfx3dSide_t sf2d_get_current_side()
{
return cur_side;
}
static void apt_hook_func(int hook, void* param)
{
if (hook == APTHOOK_ONRESTORE) {
reset_gpu_apt_resume();
}
}
static void reset_gpu_apt_resume()
{
GPU_Reset(NULL, gpu_cmd, gpu_cmd_size); // Only required for custom GPU cmd sizes
shaderProgramUse(&shader);
if (cur_screen == GFX_TOP) {
matrix_gpu_set_uniform(ortho_matrix_top, projection_desc);
} else {
matrix_gpu_set_uniform(ortho_matrix_bot, projection_desc);
}
GPUCMD_Finalize();
GPUCMD_FlushAndRun(NULL);
gspWaitForP3D();
}

View file

@ -0,0 +1,212 @@
#include "sf2d.h"
#include "sf2d_private.h"
#include <math.h>
void sf2d_draw_line(int x0, int y0, int x1, int y1, u32 color)
{
sf2d_vertex_pos_col *vertices = sf2d_pool_malloc(4 * sizeof(sf2d_vertex_pos_col));
if (!vertices) return;
vertices[0].position = (sf2d_vector_3f){(float)x0+1.0f, (float)y0+1.0f, SF2D_DEFAULT_DEPTH};
vertices[1].position = (sf2d_vector_3f){(float)x0-1.0f, (float)y0-1.0f, SF2D_DEFAULT_DEPTH};
vertices[2].position = (sf2d_vector_3f){(float)x1+1.0f, (float)y1+1.0f, SF2D_DEFAULT_DEPTH};
vertices[3].position = (sf2d_vector_3f){(float)x1-1.0f, (float)y1-1.0f, SF2D_DEFAULT_DEPTH};
u8 r = (color>>24) & 0xFF;
u8 g = (color>>16) & 0xFF;
u8 b = (color>>8) & 0xFF;
u8 a = color & 0xFF;
vertices[0].color = (sf2d_vector_4f){r/255.0f, g/255.0f, b/255.0f, a/255.0f};
vertices[1].color = vertices[0].color;
vertices[2].color = vertices[0].color;
vertices[3].color = vertices[0].color;
GPU_SetTexEnv(
0,
GPU_TEVSOURCES(GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR),
GPU_TEVSOURCES(GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR),
GPU_TEVOPERANDS(0, 0, 0),
GPU_TEVOPERANDS(0, 0, 0),
GPU_REPLACE, GPU_REPLACE,
0xFFFFFFFF
);
GPU_SetAttributeBuffers(
2, // number of attributes
(u32*)osConvertVirtToPhys((u32)vertices),
GPU_ATTRIBFMT(0, 3, GPU_FLOAT) | GPU_ATTRIBFMT(1, 4, GPU_FLOAT),
0xFFFC, //0b1100
0x10,
1, //number of buffers
(u32[]){0x0}, // buffer offsets (placeholders)
(u64[]){0x10}, // attribute permutations for each buffer
(u8[]){2} // number of attributes for each buffer
);
GPU_DrawArray(GPU_TRIANGLE_STRIP, 4);
}
void sf2d_draw_rectangle(int x, int y, int w, int h, u32 color)
{
sf2d_vertex_pos_col *vertices = sf2d_pool_malloc(4 * sizeof(sf2d_vertex_pos_col));
if (!vertices) return;
vertices[0].position = (sf2d_vector_3f){(float)x, (float)y, SF2D_DEFAULT_DEPTH};
vertices[1].position = (sf2d_vector_3f){(float)x+w, (float)y, SF2D_DEFAULT_DEPTH};
vertices[2].position = (sf2d_vector_3f){(float)x, (float)y+h, SF2D_DEFAULT_DEPTH};
vertices[3].position = (sf2d_vector_3f){(float)x+w, (float)y+h, SF2D_DEFAULT_DEPTH};
u8 r = (color>>24) & 0xFF;
u8 g = (color>>16) & 0xFF;
u8 b = (color>>8) & 0xFF;
u8 a = color & 0xFF;
vertices[0].color = (sf2d_vector_4f){r/255.0f, g/255.0f, b/255.0f, a/255.0f};
vertices[1].color = vertices[0].color;
vertices[2].color = vertices[0].color;
vertices[3].color = vertices[0].color;
GPU_SetTexEnv(
0,
GPU_TEVSOURCES(GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR),
GPU_TEVSOURCES(GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR),
GPU_TEVOPERANDS(0, 0, 0),
GPU_TEVOPERANDS(0, 0, 0),
GPU_REPLACE, GPU_REPLACE,
0xFFFFFFFF
);
GPU_SetAttributeBuffers(
2, // number of attributes
(u32*)osConvertVirtToPhys((u32)vertices),
GPU_ATTRIBFMT(0, 3, GPU_FLOAT) | GPU_ATTRIBFMT(1, 4, GPU_FLOAT),
0xFFFC, //0b1100
0x10,
1, //number of buffers
(u32[]){0x0}, // buffer offsets (placeholders)
(u64[]){0x10}, // attribute permutations for each buffer
(u8[]){2} // number of attributes for each buffer
);
GPU_DrawArray(GPU_TRIANGLE_STRIP, 4);
}
void sf2d_draw_rectangle_rotate(int x, int y, int w, int h, u32 color, float rad)
{
sf2d_vertex_pos_col *vertices = sf2d_pool_malloc(4 * sizeof(sf2d_vertex_pos_col));
if (!vertices) return;
int w2 = w/2.0f;
int h2 = h/2.0f;
vertices[0].position = (sf2d_vector_3f){(float)-w2, (float)-h2, SF2D_DEFAULT_DEPTH};
vertices[1].position = (sf2d_vector_3f){(float) w2, (float)-h2, SF2D_DEFAULT_DEPTH};
vertices[2].position = (sf2d_vector_3f){(float)-w2, (float) h2, SF2D_DEFAULT_DEPTH};
vertices[3].position = (sf2d_vector_3f){(float) w2, (float) h2, SF2D_DEFAULT_DEPTH};
u8 r = (color>>24) & 0xFF;
u8 g = (color>>16) & 0xFF;
u8 b = (color>>8) & 0xFF;
u8 a = color & 0xFF;
vertices[0].color = (sf2d_vector_4f){r/255.0f, g/255.0f, b/255.0f, a/255.0f};
vertices[1].color = vertices[0].color;
vertices[2].color = vertices[0].color;
vertices[3].color = vertices[0].color;
float m[4*4];
matrix_set_z_rotation(m, rad);
sf2d_vector_3f rot[4];
int i;
for (i = 0; i < 4; i++) {
vector_mult_matrix4x4(m, &vertices[i].position, &rot[i]);
vertices[i].position = (sf2d_vector_3f){rot[i].x + x + w2, rot[i].y + y + h2, rot[i].z};
}
GPU_SetTexEnv(
0,
GPU_TEVSOURCES(GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR),
GPU_TEVSOURCES(GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR),
GPU_TEVOPERANDS(0, 0, 0),
GPU_TEVOPERANDS(0, 0, 0),
GPU_REPLACE, GPU_REPLACE,
0xFFFFFFFF
);
GPU_SetAttributeBuffers(
2, // number of attributes
(u32*)osConvertVirtToPhys((u32)vertices),
GPU_ATTRIBFMT(0, 3, GPU_FLOAT) | GPU_ATTRIBFMT(1, 4, GPU_FLOAT),
0xFFFC, //0b1100
0x10,
1, //number of buffers
(u32[]){0x0}, // buffer offsets (placeholders)
(u64[]){0x10}, // attribute permutations for each buffer
(u8[]){2} // number of attributes for each buffer
);
GPU_DrawArray(GPU_TRIANGLE_STRIP, 4);
}
void sf2d_draw_fill_circle(int x, int y, int radius, u32 color)
{
static const int num_segments = 100;
sf2d_vertex_pos_col *vertices = sf2d_pool_malloc((num_segments + 2) * sizeof(sf2d_vertex_pos_col));
if (!vertices) return;
vertices[0].position = (sf2d_vector_3f){(float)x, (float)y, SF2D_DEFAULT_DEPTH};
u8 r = (color>>24) & 0xFF;
u8 g = (color>>16) & 0xFF;
u8 b = (color>>8) & 0xFF;
u8 a = color & 0xFF;
vertices[0].color = (sf2d_vector_4f){r/255.0f, g/255.0f, b/255.0f, a/255.0f};
float theta = 2 * M_PI / (float)num_segments;
float c = cosf(theta);
float s = sinf(theta);
float t;
float xx = radius;
float yy = 0;
int i;
for (i = 1; i <= num_segments; i++) {
vertices[i].position = (sf2d_vector_3f){(float)(x + xx), (float)(y + yy), SF2D_DEFAULT_DEPTH};
vertices[i].color = vertices[0].color;
t = xx;
xx = c * xx - s * yy;
yy = s * t + c * yy;
}
vertices[num_segments + 1].position = vertices[1].position;
vertices[num_segments + 1].color = vertices[1].color;
GPU_SetTexEnv(
0,
GPU_TEVSOURCES(GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR),
GPU_TEVSOURCES(GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR),
GPU_TEVOPERANDS(0, 0, 0),
GPU_TEVOPERANDS(0, 0, 0),
GPU_REPLACE, GPU_REPLACE,
0xFFFFFFFF
);
GPU_SetAttributeBuffers(
2, // number of attributes
(u32*)osConvertVirtToPhys((u32)vertices),
GPU_ATTRIBFMT(0, 3, GPU_FLOAT) | GPU_ATTRIBFMT(1, 4, GPU_FLOAT),
0xFFFC, //0b1100
0x10,
1, //number of buffers
(u32[]){0x0}, // buffer offsets (placeholders)
(u64[]){0x10}, // attribute permutations for each buffer
(u8[]){2} // number of attributes for each buffer
);
GPU_DrawArray(GPU_TRIANGLE_FAN, num_segments + 2);
}

View file

@ -0,0 +1,155 @@
#include <string.h>
#include <math.h>
#include "sf2d_private.h"
//stolen from staplebutt
void GPU_SetDummyTexEnv(u8 num)
{
GPU_SetTexEnv(num,
GPU_TEVSOURCES(GPU_PREVIOUS, 0, 0),
GPU_TEVSOURCES(GPU_PREVIOUS, 0, 0),
GPU_TEVOPERANDS(0,0,0),
GPU_TEVOPERANDS(0,0,0),
GPU_REPLACE,
GPU_REPLACE,
0xFFFFFFFF);
}
void vector_mult_matrix4x4(const float *msrc, const sf2d_vector_3f *vsrc, sf2d_vector_3f *vdst)
{
vdst->x = msrc[0*4 + 0]*vsrc->x + msrc[0*4 + 1]*vsrc->y + msrc[0*4 + 2]*vsrc->z + msrc[0*4 + 3];
vdst->y = msrc[1*4 + 0]*vsrc->x + msrc[1*4 + 1]*vsrc->y + msrc[1*4 + 2]*vsrc->z + msrc[1*4 + 3];
vdst->z = msrc[2*4 + 0]*vsrc->x + msrc[2*4 + 1]*vsrc->y + msrc[2*4 + 2]*vsrc->z + msrc[2*4 + 3];
}
void matrix_gpu_set_uniform(const float *m, u32 startreg)
{
float mu[4*4];
int i, j;
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
mu[i*4 + j] = m[i*4 + (3-j)];
}
}
GPU_SetFloatUniform(GPU_VERTEX_SHADER, startreg, (u32 *)mu, 4);
}
void matrix_copy(float *dst, const float *src)
{
memcpy(dst, src, sizeof(float)*4*4);
}
void matrix_identity4x4(float *m)
{
m[0] = m[5] = m[10] = m[15] = 1.0f;
m[1] = m[2] = m[3] = 0.0f;
m[4] = m[6] = m[7] = 0.0f;
m[8] = m[9] = m[11] = 0.0f;
m[12] = m[13] = m[14] = 0.0f;
}
void matrix_mult4x4(const float *src1, const float *src2, float *dst)
{
int i, j, k;
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
dst[i*4 + j] = 0.0f;
for (k = 0; k < 4; k++) {
dst[i*4 + j] += src1[i*4 + k]*src2[k*4 + j];
}
}
}
}
void matrix_set_z_rotation(float *m, float rad)
{
float c = cosf(rad);
float s = sinf(rad);
matrix_identity4x4(m);
m[0] = c;
m[1] = -s;
m[4] = s;
m[5] = c;
}
void matrix_rotate_z(float *m, float rad)
{
float mr[4*4], mt[4*4];
matrix_set_z_rotation(mr, rad);
matrix_mult4x4(mr, m, mt);
matrix_copy(m, mt);
}
void matrix_set_scaling(float *m, float x_scale, float y_scale, float z_scale)
{
matrix_identity4x4(m);
m[0] = x_scale;
m[5] = y_scale;
m[10] = z_scale;
}
void matrix_swap_xy(float *m)
{
float ms[4*4], mt[4*4];
matrix_identity4x4(ms);
ms[0] = 0.0f;
ms[1] = 1.0f;
ms[4] = 1.0f;
ms[5] = 0.0f;
matrix_mult4x4(ms, m, mt);
matrix_copy(m, mt);
}
void matrix_init_orthographic(float *m, float left, float right, float bottom, float top, float near, float far)
{
float mo[4*4], mp[4*4];
mo[0x0] = 2.0f/(right-left);
mo[0x1] = 0.0f;
mo[0x2] = 0.0f;
mo[0x3] = -(right+left)/(right-left);
mo[0x4] = 0.0f;
mo[0x5] = 2.0f/(top-bottom);
mo[0x6] = 0.0f;
mo[0x7] = -(top+bottom)/(top-bottom);
mo[0x8] = 0.0f;
mo[0x9] = 0.0f;
mo[0xA] = -2.0f/(far-near);
mo[0xB] = (far+near)/(far-near);
mo[0xC] = 0.0f;
mo[0xD] = 0.0f;
mo[0xE] = 0.0f;
mo[0xF] = 1.0f;
matrix_identity4x4(mp);
mp[0xA] = 0.5;
mp[0xB] = -0.5;
//Convert Z [-1, 1] to [-1, 0] (PICA shiz)
matrix_mult4x4(mp, mo, m);
// Rotate 180 degrees
matrix_rotate_z(m, M_PI);
// Swap X and Y axis
matrix_swap_xy(m);
}
//Grabbed from: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
unsigned int next_pow2(unsigned int v)
{
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
return v+1;
}

View file

@ -0,0 +1,620 @@
#include <stdlib.h>
#include <string.h>
#include "sf2d.h"
#include "sf2d_private.h"
#define TEX_MIN_SIZE 8
static unsigned int nibbles_per_pixel(sf2d_texfmt format)
{
switch (format) {
case TEXFMT_RGBA8:
return 8;
case TEXFMT_RGB8:
return 6;
case TEXFMT_RGB5A1:
case TEXFMT_RGB565:
case TEXFMT_RGBA4:
case TEXFMT_IA8:
return 4;
case TEXFMT_A4:
return 1;
case TEXFMT_I8:
case TEXFMT_A8:
case TEXFMT_IA4:
default:
return 2;
}
}
static int calc_buffer_size(sf2d_texfmt pixel_format, int width, int height)
{
return width * height * (nibbles_per_pixel(pixel_format)>>1);
}
sf2d_texture *sf2d_create_texture(int width, int height, sf2d_texfmt pixel_format, sf2d_place place)
{
int pow2_w = next_pow2(width);
int pow2_h = next_pow2(height);
if (pow2_w < TEX_MIN_SIZE) pow2_w = TEX_MIN_SIZE;
if (pow2_h < TEX_MIN_SIZE) pow2_h = TEX_MIN_SIZE;
int data_size = calc_buffer_size(pixel_format, pow2_w, pow2_h);
void *data;
if (place == SF2D_PLACE_RAM) {
// If there's not enough linear heap space, return
if (linearSpaceFree() < data_size) {
return NULL;
}
data = linearMemAlign(data_size, 0x80);
} else if (place == SF2D_PLACE_VRAM) {
// If there's not enough VRAM heap space, return
if (vramSpaceFree() < data_size) {
return NULL;
}
data = vramMemAlign(data_size, 0x80);
} else if (place == SF2D_PLACE_TEMP) {
if (sf2d_pool_space_free() < data_size) {
return NULL;
}
data = sf2d_pool_memalign(data_size, 0x80);
} else {
//wot?
return NULL;
}
sf2d_texture *texture = malloc(sizeof(*texture));
texture->tiled = 0;
texture->place = place;
texture->pixel_format = pixel_format;
texture->width = width;
texture->height = height;
texture->pow2_w = pow2_w;
texture->pow2_h = pow2_h;
texture->data_size = data_size;
texture->data = data;
memset(texture->data, 0, texture->data_size);
return texture;
}
void sf2d_free_texture(sf2d_texture *texture)
{
if (texture) {
if (texture->place == SF2D_PLACE_RAM) {
linearFree(texture->data);
} else if (texture->place == SF2D_PLACE_VRAM) {
vramFree(texture->data);
}
free(texture);
}
}
void sf2d_fill_texture_from_RGBA8(sf2d_texture *dst, const void *rgba8, int source_w, int source_h)
{
// TODO: add support for non-RGBA8 textures
u8 *tmp = linearAlloc(dst->pow2_w * dst->pow2_h * 4);
int i, j;
for (i = 0; i < source_h; i++) {
for (j = 0; j < source_w; j++) {
((u32 *)tmp)[i*dst->pow2_w + j] = ((u32 *)rgba8)[i*source_w + j];
}
}
memcpy(dst->data, tmp, dst->pow2_w*dst->pow2_h*4);
linearFree(tmp);
sf2d_texture_tile32(dst);
}
sf2d_texture *sf2d_create_texture_mem_RGBA8(const void *src_buffer, int src_w, int src_h, sf2d_texfmt pixel_format, sf2d_place place)
{
sf2d_texture *tex = sf2d_create_texture(src_w, src_h, pixel_format, place);
if (tex == NULL) return NULL;
sf2d_fill_texture_from_RGBA8(tex, src_buffer, src_w, src_h);
return tex;
}
void sf2d_bind_texture(const sf2d_texture *texture, GPU_TEXUNIT unit)
{
GPU_SetTextureEnable(unit);
GPU_SetTexEnv(
0,
GPU_TEVSOURCES(GPU_TEXTURE0, GPU_TEXTURE0, GPU_TEXTURE0),
GPU_TEVSOURCES(GPU_TEXTURE0, GPU_TEXTURE0, GPU_TEXTURE0),
GPU_TEVOPERANDS(0, 0, 0),
GPU_TEVOPERANDS(0, 0, 0),
GPU_REPLACE, GPU_REPLACE,
0xFFFFFFFF
);
GPU_SetTexture(
unit,
(u32 *)osConvertVirtToPhys((u32)texture->data),
texture->pow2_w,
texture->pow2_h,
GPU_TEXTURE_MAG_FILTER(GPU_NEAREST) | GPU_TEXTURE_MIN_FILTER(GPU_NEAREST),
texture->pixel_format
);
}
void sf2d_bind_texture_color(const sf2d_texture *texture, GPU_TEXUNIT unit, u32 color)
{
GPU_SetTextureEnable(unit);
GPU_SetTexEnv(
0,
GPU_TEVSOURCES(GPU_TEXTURE0, GPU_CONSTANT, GPU_CONSTANT),
GPU_TEVSOURCES(GPU_TEXTURE0, GPU_CONSTANT, GPU_CONSTANT),
GPU_TEVOPERANDS(0, 0, 0),
GPU_TEVOPERANDS(0, 0, 0),
GPU_MODULATE, GPU_MODULATE,
__builtin_bswap32(color) //RGBA8 -> ABGR8
);
GPU_SetTexture(
unit,
(u32 *)osConvertVirtToPhys((u32)texture->data),
texture->pow2_w,
texture->pow2_h,
GPU_TEXTURE_MAG_FILTER(GPU_NEAREST) | GPU_TEXTURE_MIN_FILTER(GPU_NEAREST),
texture->pixel_format
);
}
void sf2d_bind_texture_parameters(const sf2d_texture *texture, GPU_TEXUNIT unit, unsigned int params)
{
GPU_SetTextureEnable(unit);
GPU_SetTexEnv(
0,
GPU_TEVSOURCES(GPU_TEXTURE0, GPU_TEXTURE0, GPU_TEXTURE0),
GPU_TEVSOURCES(GPU_TEXTURE0, GPU_TEXTURE0, GPU_TEXTURE0),
GPU_TEVOPERANDS(0, 0, 0),
GPU_TEVOPERANDS(0, 0, 0),
GPU_REPLACE, GPU_REPLACE,
0xFFFFFFFF
);
GPU_SetTexture(
unit,
(u32 *)osConvertVirtToPhys((u32)texture->data),
texture->pow2_w,
texture->pow2_h,
params,
texture->pixel_format
);
}
void sf2d_draw_texture(const sf2d_texture *texture, int x, int y)
{
sf2d_vertex_pos_tex *vertices = sf2d_pool_malloc(4 * sizeof(sf2d_vertex_pos_tex));
if (!vertices) return;
int w = texture->width;
int h = texture->height;
vertices[0].position = (sf2d_vector_3f){(float)x, (float)y, SF2D_DEFAULT_DEPTH};
vertices[1].position = (sf2d_vector_3f){(float)x+w, (float)y, SF2D_DEFAULT_DEPTH};
vertices[2].position = (sf2d_vector_3f){(float)x, (float)y+h, SF2D_DEFAULT_DEPTH};
vertices[3].position = (sf2d_vector_3f){(float)x+w, (float)y+h, SF2D_DEFAULT_DEPTH};
float u = texture->width/(float)texture->pow2_w;
float v = texture->height/(float)texture->pow2_h;
vertices[0].texcoord = (sf2d_vector_2f){0.0f, 0.0f};
vertices[1].texcoord = (sf2d_vector_2f){u, 0.0f};
vertices[2].texcoord = (sf2d_vector_2f){0.0f, v};
vertices[3].texcoord = (sf2d_vector_2f){u, v};
sf2d_bind_texture(texture, GPU_TEXUNIT0);
GPU_SetAttributeBuffers(
2, // number of attributes
(u32*)osConvertVirtToPhys((u32)vertices),
GPU_ATTRIBFMT(0, 3, GPU_FLOAT) | GPU_ATTRIBFMT(1, 2, GPU_FLOAT),
0xFFFC, //0b1100
0x10,
1, //number of buffers
(u32[]){0x0}, // buffer offsets (placeholders)
(u64[]){0x10}, // attribute permutations for each buffer
(u8[]){2} // number of attributes for each buffer
);
GPU_DrawArray(GPU_TRIANGLE_STRIP, 4);
}
void sf2d_draw_texture_rotate(const sf2d_texture *texture, int x, int y, float rad)
{
sf2d_vertex_pos_tex *vertices = sf2d_pool_malloc(4 * sizeof(sf2d_vertex_pos_tex));
if (!vertices) return;
int w2 = texture->width/2.0f;
int h2 = texture->height/2.0f;
vertices[0].position = (sf2d_vector_3f){(float)-w2, (float)-h2, SF2D_DEFAULT_DEPTH};
vertices[1].position = (sf2d_vector_3f){(float) w2, (float)-h2, SF2D_DEFAULT_DEPTH};
vertices[2].position = (sf2d_vector_3f){(float)-w2, (float) h2, SF2D_DEFAULT_DEPTH};
vertices[3].position = (sf2d_vector_3f){(float) w2, (float) h2, SF2D_DEFAULT_DEPTH};
float u = texture->width/(float)texture->pow2_w;
float v = texture->height/(float)texture->pow2_h;
vertices[0].texcoord = (sf2d_vector_2f){0.0f, 0.0f};
vertices[1].texcoord = (sf2d_vector_2f){u, 0.0f};
vertices[2].texcoord = (sf2d_vector_2f){0.0f, v};
vertices[3].texcoord = (sf2d_vector_2f){u, v};
float m[4*4];
matrix_set_z_rotation(m, rad);
sf2d_vector_3f rot[4];
int i;
for (i = 0; i < 4; i++) {
vector_mult_matrix4x4(m, &vertices[i].position, &rot[i]);
vertices[i].position = (sf2d_vector_3f){rot[i].x + x + w2, rot[i].y + y + h2, rot[i].z};
}
sf2d_bind_texture(texture, GPU_TEXUNIT0);
GPU_SetAttributeBuffers(
2, // number of attributes
(u32*)osConvertVirtToPhys((u32)vertices),
GPU_ATTRIBFMT(0, 3, GPU_FLOAT) | GPU_ATTRIBFMT(1, 2, GPU_FLOAT),
0xFFFC, //0b1100
0x10,
1, //number of buffers
(u32[]){0x0}, // buffer offsets (placeholders)
(u64[]){0x10}, // attribute permutations for each buffer
(u8[]){2} // number of attributes for each buffer
);
GPU_DrawArray(GPU_TRIANGLE_STRIP, 4);
}
void sf2d_draw_texture_part(const sf2d_texture *texture, int x, int y, int tex_x, int tex_y, int tex_w, int tex_h)
{
sf2d_vertex_pos_tex *vertices = sf2d_pool_malloc(4 * sizeof(sf2d_vertex_pos_tex));
if (!vertices) return;
vertices[0].position = (sf2d_vector_3f){(float)x, (float)y, SF2D_DEFAULT_DEPTH};
vertices[1].position = (sf2d_vector_3f){(float)x+tex_w, (float)y, SF2D_DEFAULT_DEPTH};
vertices[2].position = (sf2d_vector_3f){(float)x, (float)y+tex_h, SF2D_DEFAULT_DEPTH};
vertices[3].position = (sf2d_vector_3f){(float)x+tex_w, (float)y+tex_h, SF2D_DEFAULT_DEPTH};
float u0 = tex_x/(float)texture->pow2_w;
float v0 = tex_y/(float)texture->pow2_h;
float u1 = (tex_x+tex_w)/(float)texture->pow2_w;
float v1 = (tex_y+tex_h)/(float)texture->pow2_h;
vertices[0].texcoord = (sf2d_vector_2f){u0, v0};
vertices[1].texcoord = (sf2d_vector_2f){u1, v0};
vertices[2].texcoord = (sf2d_vector_2f){u0, v1};
vertices[3].texcoord = (sf2d_vector_2f){u1, v1};
sf2d_bind_texture(texture, GPU_TEXUNIT0);
GPU_SetAttributeBuffers(
2, // number of attributes
(u32*)osConvertVirtToPhys((u32)vertices),
GPU_ATTRIBFMT(0, 3, GPU_FLOAT) | GPU_ATTRIBFMT(1, 2, GPU_FLOAT),
0xFFFC, //0b1100
0x10,
1, //number of buffers
(u32[]){0x0}, // buffer offsets (placeholders)
(u64[]){0x10}, // attribute permutations for each buffer
(u8[]){2} // number of attributes for each buffer
);
GPU_DrawArray(GPU_TRIANGLE_STRIP, 4);
}
void sf2d_draw_texture_scale(const sf2d_texture *texture, int x, int y, float x_scale, float y_scale)
{
sf2d_vertex_pos_tex *vertices = sf2d_pool_malloc(4 * sizeof(sf2d_vertex_pos_tex));
if (!vertices) return;
int ws = texture->width * x_scale;
int hs = texture->height * y_scale;
vertices[0].position = (sf2d_vector_3f){(float)x, (float)y, SF2D_DEFAULT_DEPTH};
vertices[1].position = (sf2d_vector_3f){(float)x+ws, (float)y, SF2D_DEFAULT_DEPTH};
vertices[2].position = (sf2d_vector_3f){(float)x, (float)y+hs, SF2D_DEFAULT_DEPTH};
vertices[3].position = (sf2d_vector_3f){(float)x+ws, (float)y+hs, SF2D_DEFAULT_DEPTH};
float u = texture->width/(float)texture->pow2_w;
float v = texture->height/(float)texture->pow2_h;
vertices[0].texcoord = (sf2d_vector_2f){0.0f, 0.0f};
vertices[1].texcoord = (sf2d_vector_2f){u, 0.0f};
vertices[2].texcoord = (sf2d_vector_2f){0.0f, v};
vertices[3].texcoord = (sf2d_vector_2f){u, v};
sf2d_bind_texture(texture, GPU_TEXUNIT0);
GPU_SetAttributeBuffers(
2, // number of attributes
(u32*)osConvertVirtToPhys((u32)vertices),
GPU_ATTRIBFMT(0, 3, GPU_FLOAT) | GPU_ATTRIBFMT(1, 2, GPU_FLOAT),
0xFFFC, //0b1100
0x10,
1, //number of buffers
(u32[]){0x0}, // buffer offsets (placeholders)
(u64[]){0x10}, // attribute permutations for each buffer
(u8[]){2} // number of attributes for each buffer
);
GPU_DrawArray(GPU_TRIANGLE_STRIP, 4);
}
void sf2d_draw_texture_rotate_cut_scale(const sf2d_texture *texture, int x, int y, float rad, int tex_x, int tex_y, int tex_w, int tex_h, float x_scale, float y_scale)
{
sf2d_vertex_pos_tex *vertices = sf2d_pool_malloc(4 * sizeof(sf2d_vertex_pos_tex));
if (!vertices) return;
//Don't even try to understand what I'm doing here (because I don't even understand it).
//Matrices are boring.
int w2 = (tex_w * x_scale)/2.0f;
int h2 = (tex_h * y_scale)/2.0f;
vertices[0].position = (sf2d_vector_3f){(float)-w2, (float)-h2, SF2D_DEFAULT_DEPTH};
vertices[1].position = (sf2d_vector_3f){(float) w2, (float)-h2, SF2D_DEFAULT_DEPTH};
vertices[2].position = (sf2d_vector_3f){(float)-w2, (float) h2, SF2D_DEFAULT_DEPTH};
vertices[3].position = (sf2d_vector_3f){(float) w2, (float) h2, SF2D_DEFAULT_DEPTH};
float u0 = tex_x/(float)texture->pow2_w;
float v0 = tex_y/(float)texture->pow2_h;
float u1 = (tex_x+tex_w)/(float)texture->pow2_w;
float v1 = (tex_y+tex_h)/(float)texture->pow2_h;
vertices[0].texcoord = (sf2d_vector_2f){u0, v0};
vertices[1].texcoord = (sf2d_vector_2f){u1, v0};
vertices[2].texcoord = (sf2d_vector_2f){u0, v1};
vertices[3].texcoord = (sf2d_vector_2f){u1, v1};
float m[4*4];
matrix_set_z_rotation(m, rad);
sf2d_vector_3f rot[4];
int i;
for (i = 0; i < 4; i++) {
vector_mult_matrix4x4(m, &vertices[i].position, &rot[i]);
vertices[i].position = (sf2d_vector_3f){rot[i].x + x + w2, rot[i].y + y + h2, rot[i].z};
}
sf2d_bind_texture(texture, GPU_TEXUNIT0);
GPU_SetAttributeBuffers(
2, // number of attributes
(u32*)osConvertVirtToPhys((u32)vertices),
GPU_ATTRIBFMT(0, 3, GPU_FLOAT) | GPU_ATTRIBFMT(1, 2, GPU_FLOAT),
0xFFFC, //0b1100
0x10,
1, //number of buffers
(u32[]){0x0}, // buffer offsets (placeholders)
(u64[]){0x10}, // attribute permutations for each buffer
(u8[]){2} // number of attributes for each buffer
);
GPU_DrawArray(GPU_TRIANGLE_STRIP, 4);
}
void sf2d_draw_texture_blend(const sf2d_texture *texture, int x, int y, u32 color)
{
sf2d_vertex_pos_tex *vertices = sf2d_pool_malloc(4 * sizeof(sf2d_vertex_pos_tex));
if (!vertices) return;
int w = texture->width;
int h = texture->height;
vertices[0].position = (sf2d_vector_3f){(float)x, (float)y, SF2D_DEFAULT_DEPTH};
vertices[1].position = (sf2d_vector_3f){(float)x+w, (float)y, SF2D_DEFAULT_DEPTH};
vertices[2].position = (sf2d_vector_3f){(float)x, (float)y+h, SF2D_DEFAULT_DEPTH};
vertices[3].position = (sf2d_vector_3f){(float)x+w, (float)y+h, SF2D_DEFAULT_DEPTH};
float u = texture->width/(float)texture->pow2_w;
float v = texture->height/(float)texture->pow2_h;
vertices[0].texcoord = (sf2d_vector_2f){0.0f, 0.0f};
vertices[1].texcoord = (sf2d_vector_2f){u, 0.0f};
vertices[2].texcoord = (sf2d_vector_2f){0.0f, v};
vertices[3].texcoord = (sf2d_vector_2f){u, v};
sf2d_bind_texture_color(texture, GPU_TEXUNIT0, color);
GPU_SetAttributeBuffers(
2, // number of attributes
(u32*)osConvertVirtToPhys((u32)vertices),
GPU_ATTRIBFMT(0, 3, GPU_FLOAT) | GPU_ATTRIBFMT(1, 2, GPU_FLOAT),
0xFFFC, //0b1100
0x10,
1, //number of buffers
(u32[]){0x0}, // buffer offsets (placeholders)
(u64[]){0x10}, // attribute permutations for each buffer
(u8[]){2} // number of attributes for each buffer
);
GPU_DrawArray(GPU_TRIANGLE_STRIP, 4);
}
void sf2d_draw_texture_part_blend(const sf2d_texture *texture, int x, int y, int tex_x, int tex_y, int tex_w, int tex_h, u32 color)
{
sf2d_vertex_pos_tex *vertices = sf2d_pool_malloc(4 * sizeof(sf2d_vertex_pos_tex));
if (!vertices) return;
vertices[0].position = (sf2d_vector_3f){(float)x, (float)y, SF2D_DEFAULT_DEPTH};
vertices[1].position = (sf2d_vector_3f){(float)x+tex_w, (float)y, SF2D_DEFAULT_DEPTH};
vertices[2].position = (sf2d_vector_3f){(float)x, (float)y+tex_h, SF2D_DEFAULT_DEPTH};
vertices[3].position = (sf2d_vector_3f){(float)x+tex_w, (float)y+tex_h, SF2D_DEFAULT_DEPTH};
float u0 = tex_x/(float)texture->pow2_w;
float v0 = tex_y/(float)texture->pow2_h;
float u1 = (tex_x+tex_w)/(float)texture->pow2_w;
float v1 = (tex_y+tex_h)/(float)texture->pow2_h;
vertices[0].texcoord = (sf2d_vector_2f){u0, v0};
vertices[1].texcoord = (sf2d_vector_2f){u1, v0};
vertices[2].texcoord = (sf2d_vector_2f){u0, v1};
vertices[3].texcoord = (sf2d_vector_2f){u1, v1};
sf2d_bind_texture_color(texture, GPU_TEXUNIT0, color);
GPU_SetAttributeBuffers(
2, // number of attributes
(u32*)osConvertVirtToPhys((u32)vertices),
GPU_ATTRIBFMT(0, 3, GPU_FLOAT) | GPU_ATTRIBFMT(1, 2, GPU_FLOAT),
0xFFFC, //0b1100
0x10,
1, //number of buffers
(u32[]){0x0}, // buffer offsets (placeholders)
(u64[]){0x10}, // attribute permutations for each buffer
(u8[]){2} // number of attributes for each buffer
);
GPU_DrawArray(GPU_TRIANGLE_STRIP, 4);
}
void sf2d_draw_texture_depth(const sf2d_texture *texture, int x, int y, signed short z)
{
sf2d_vertex_pos_tex *vertices = sf2d_pool_malloc(4 * sizeof(sf2d_vertex_pos_tex));
if (!vertices) return;
int w = texture->width;
int h = texture->height;
float depth = z/32768.0f + 0.5f;
vertices[0].position = (sf2d_vector_3f){(float)x, (float)y, depth};
vertices[1].position = (sf2d_vector_3f){(float)x+w, (float)y, depth};
vertices[2].position = (sf2d_vector_3f){(float)x, (float)y+h, depth};
vertices[3].position = (sf2d_vector_3f){(float)x+w, (float)y+h, depth};
float u = texture->width/(float)texture->pow2_w;
float v = texture->height/(float)texture->pow2_h;
vertices[0].texcoord = (sf2d_vector_2f){0.0f, 0.0f};
vertices[1].texcoord = (sf2d_vector_2f){u, 0.0f};
vertices[2].texcoord = (sf2d_vector_2f){0.0f, v};
vertices[3].texcoord = (sf2d_vector_2f){u, v};
sf2d_bind_texture(texture, GPU_TEXUNIT0);
GPU_SetAttributeBuffers(
2, // number of attributes
(u32*)osConvertVirtToPhys((u32)vertices),
GPU_ATTRIBFMT(0, 3, GPU_FLOAT) | GPU_ATTRIBFMT(1, 2, GPU_FLOAT),
0xFFFC, //0b1100
0x10,
1, //number of buffers
(u32[]){0x0}, // buffer offsets (placeholders)
(u64[]){0x10}, // attribute permutations for each buffer
(u8[]){2} // number of attributes for each buffer
);
GPU_DrawArray(GPU_TRIANGLE_STRIP, 4);
}
void sf2d_draw_quad_uv(const sf2d_texture *texture, float left, float top, float right, float bottom, float u0, float v0, float u1, float v1, unsigned int params)
{
sf2d_vertex_pos_tex *vertices = sf2d_pool_malloc(4 * sizeof(sf2d_vertex_pos_tex));
if (!vertices) return;
vertices[0].position = (sf2d_vector_3f){left, top, SF2D_DEFAULT_DEPTH};
vertices[1].position = (sf2d_vector_3f){right, top, SF2D_DEFAULT_DEPTH};
vertices[2].position = (sf2d_vector_3f){left, bottom, SF2D_DEFAULT_DEPTH};
vertices[3].position = (sf2d_vector_3f){right, bottom, SF2D_DEFAULT_DEPTH};
vertices[0].texcoord = (sf2d_vector_2f){u0, v0};
vertices[1].texcoord = (sf2d_vector_2f){u1, v0};
vertices[2].texcoord = (sf2d_vector_2f){u0, v1};
vertices[3].texcoord = (sf2d_vector_2f){u1, v1};
sf2d_bind_texture_parameters(texture, GPU_TEXUNIT0, params);
GPU_SetAttributeBuffers(
2, // number of attributes
(u32*)osConvertVirtToPhys((u32)vertices),
GPU_ATTRIBFMT(0, 3, GPU_FLOAT) | GPU_ATTRIBFMT(1, 2, GPU_FLOAT),
0xFFFC, //0b1100
0x10,
1, //number of buffers
(u32[]){0x0}, // buffer offsets (placeholders)
(u64[]){0x10}, // attribute permutations for each buffer
(u8[]){2} // number of attributes for each buffer
);
GPU_DrawArray(GPU_TRIANGLE_STRIP, 4);
}
// Grabbed from Citra Emulator (citra/src/video_core/utils.h)
static inline u32 morton_interleave(u32 x, u32 y)
{
u32 i = (x & 7) | ((y & 7) << 8); // ---- -210
i = (i ^ (i << 2)) & 0x1313; // ---2 --10
i = (i ^ (i << 1)) & 0x1515; // ---2 -1-0
i = (i | (i >> 7)) & 0x3F;
return i;
}
//Grabbed from Citra Emulator (citra/src/video_core/utils.h)
static inline u32 get_morton_offset(u32 x, u32 y, u32 bytes_per_pixel)
{
u32 i = morton_interleave(x, y);
unsigned int offset = (x & ~7) * 8;
return (i + offset) * bytes_per_pixel;
}
void sf2d_set_pixel(sf2d_texture *texture, int x, int y, u32 new_color)
{
y = (texture->pow2_h - 1 - y);
if (texture->tiled) {
u32 coarse_y = y & ~7;
u32 offset = get_morton_offset(x, y, 4) + coarse_y * texture->pow2_w * 4;
*(u32 *)(texture->data + offset) = __builtin_bswap32(new_color);
} else {
((u32 *)texture->data)[x + y * texture->pow2_w] = __builtin_bswap32(new_color);
}
}
u32 sf2d_get_pixel(sf2d_texture *texture, int x, int y)
{
y = (texture->pow2_h - 1 - y);
if (texture->tiled) {
u32 coarse_y = y & ~7;
u32 offset = get_morton_offset(x, y, 4) + coarse_y * texture->pow2_w * 4;
return __builtin_bswap32(*(u32 *)(texture->data + offset));
} else {
return __builtin_bswap32(((u32 *)texture->data)[x + y * texture->pow2_w]);
}
}
void sf2d_texture_tile32(sf2d_texture *texture)
{
if (texture->tiled) return;
// TODO: add support for non-RGBA8 textures
u8 *tmp = linearAlloc(texture->pow2_w * texture->pow2_h * 4);
int i, j;
for (j = 0; j < texture->pow2_h; j++) {
for (i = 0; i < texture->pow2_w; i++) {
u32 coarse_y = j & ~7;
u32 dst_offset = get_morton_offset(i, j, 4) + coarse_y * texture->pow2_w * 4;
u32 v = ((u32 *)texture->data)[i + (texture->pow2_h - 1 - j)*texture->pow2_w];
*(u32 *)(tmp + dst_offset) = __builtin_bswap32(v);
}
}
memcpy(texture->data, tmp, texture->pow2_w*texture->pow2_h*4);
linearFree(tmp);
texture->tiled = 1;
}

View file

@ -0,0 +1,199 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
TOPDIR ?= $(CURDIR)
include $(DEVKITARM)/3ds_rules
#---------------------------------------------------------------------------------
# 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
#
# NO_SMDH: if set to anything, no SMDH file is generated.
# 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 := sf2d_sample
BUILD := build
SOURCES := source
DATA := data
INCLUDES := include
APP_TITLE := SF2DLIB sample
APP_DESCRIPTION := SF2DLIB sample
APP_AUTHOR := xerpi
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard
CFLAGS := -g -Wall -O2 -mword-relocations \
-fomit-frame-pointer -ffast-math \
$(ARCH)
CFLAGS += $(INCLUDE) -DARM11 -D_3DS
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
LIBS := -lsf2d -lctru -lm
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(CTRULIB) $(CURDIR)/../libsf2d
#---------------------------------------------------------------------------------
# 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,$(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)))
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
#---------------------------------------------------------------------------------
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
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)
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
.PHONY: $(BUILD) clean all
#---------------------------------------------------------------------------------
all: $(BUILD)
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(TARGET).3dsx $(OUTPUT).smdh $(TARGET).elf $(TARGET)-strip.elf $(TARGET).cia $(TARGET).3ds
#---------------------------------------------------------------------------------
$(TARGET)-strip.elf: $(BUILD)
@$(STRIP) --strip-all $(TARGET).elf -o $(TARGET)-strip.elf
#---------------------------------------------------------------------------------
cci: $(TARGET)-strip.elf
@makerom -f cci -rsf resources/$(TARGET).rsf -target d -exefslogo -elf $(TARGET)-strip.elf -o $(TARGET).3ds
@echo "built ... sf2d_sample.3ds"
#---------------------------------------------------------------------------------
cia: $(TARGET)-strip.elf
@makerom -f cia -o $(TARGET).cia -elf $(TARGET)-strip.elf -rsf resources/$(TARGET).rsf -icon resources/icon.icn -banner resources/banner.bnr -exefslogo -target t
@echo "built ... sf2d_sample.cia"
#---------------------------------------------------------------------------------
send: $(BUILD)
@3dslink $(TARGET).3dsx
#---------------------------------------------------------------------------------
run: $(BUILD)
@citra $(TARGET).3dsx
#---------------------------------------------------------------------------------
copy_cia: $(TARGET).cia
@cp $(TARGET).cia /mnt/GATEWAYNAND
sync
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
ifeq ($(strip $(NO_SMDH)),)
$(OUTPUT).3dsx : $(OUTPUT).elf $(OUTPUT).smdh
else
$(OUTPUT).3dsx : $(OUTPUT).elf
endif
$(OUTPUT).elf : $(OFILES)
#---------------------------------------------------------------------------------
# you need a rule like this for each extension you use as binary data
#---------------------------------------------------------------------------------
%.bin.o : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
# WARNING: This is not the right way to do this! TODO: Do it right!
#---------------------------------------------------------------------------------
%.vsh.o : %.vsh
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@python $(AEMSTRO)/aemstro_as.py $< ../$(notdir $<).shbin
@bin2s ../$(notdir $<).shbin | $(PREFIX)as -o $@
@echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(notdir $<).shbin | tr . _)`.h
@echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(notdir $<).shbin | tr . _)`.h
@echo "extern const u32" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(notdir $<).shbin | tr . _)`.h
@rm ../$(notdir $<).shbin
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

View file

@ -0,0 +1,236 @@
BasicInfo:
Title : "sf2dlibS"
CompanyCode : "00"
ProductCode : "CTR-N-S3DS"
ContentType : Application # Application / SystemUpdate / Manual / Child / Trial
Logo : Nintendo # Nintendo / Licensed / Distributed / iQue / iQueForSystem
RomFs:
# Specifies the root path of the file system to include in the ROM.
# HostRoot : "$(ROMFS_ROOT)"
TitleInfo:
UniqueId : 0xf1001 # This was/is the first real homebrew app. I hope this TID range is not used by any retail game/app.
Category : Application # Application / SystemApplication / Applet / Firmware / Base / DlpChild / Demo / Contents / SystemContents / SharedContents / AddOnContents / Patch / AutoUpdateContents
CardInfo:
MediaSize : 128MB # 128MB / 256MB / 512MB / 1GB / 2GB / 4GB / 8GB / 16GB / 32GB
MediaType : Card1 # Card1 / Card2
CardDevice : None # NorFlash / None
Option:
UseOnSD : true # true if App is to be installed to SD
EnableCompress : true # Compresses exefs code
FreeProductCode : true # Removes limitations on ProductCode
EnableCrypt : false # Enables encryption for NCCH and CIA
MediaFootPadding : false # If true CCI files are created with padding
ExeFs: # these are the program segments from the ELF, check your elf for the appropriate segment names
ReadOnly:
- .rodata
- RO
ReadWrite:
- .data
- RO
Text:
- .init
- .text
- STUP_ENTRY
PlainRegion: # only used with SDK ELFs
# - .module_id
AccessControlInfo:
# UseOtherVariationSaveData : true
# UseExtSaveData : true
# ExtSaveDataId: 0xffffffff
# SystemSaveDataId1: 0x220
# SystemSaveDataId2: 0x00040010
# OtherUserSaveDataId1: 0x220
# OtherUserSaveDataId2: 0x330
# OtherUserSaveDataId3: 0x440
# UseExtendedSaveDataAccessControl: true
# AccessibleSaveDataIds: [0x101, 0x202, 0x303, 0x404, 0x505, 0x606]
FileSystemAccess:
# - CategorySystemApplication
# - CategoryHardwareCheck
# - CategoryFileSystemTool
- Debug
# - TwlCardBackup
# - TwlNandData
# - Boss
- DirectSdmc
# - Core
# - CtrNandRo
# - CtrNandRw
# - CtrNandRoWrite
# - CategorySystemSettings
# - CardBoard
# - ExportImportIvs
# - DirectSdmcWrite
# - SwitchCleanup
# - SaveDataMove
# - Shop
# - Shell
# - CategoryHomeMenu
IoAccessControl:
# - FsMountNand
# - FsMountNandRoWrite
# - FsMountTwln
# - FsMountWnand
# - FsMountCardSpi
# - UseSdif3
# - CreateSeed
# - UseCardSpi
IdealProcessor : 0
AffinityMask : 1
Priority : 16
MaxCpu : 0x9E # Default
DisableDebug : true
EnableForceDebug : false
CanWriteSharedPage : true
CanUsePrivilegedPriority : false
CanUseNonAlphabetAndNumber : true
PermitMainFunctionArgument : true
CanShareDeviceMemory : true
RunnableOnSleep : false
SpecialMemoryArrange : true
CoreVersion : 2
DescVersion : 2
ReleaseKernelMajor : "02"
ReleaseKernelMinor : "33"
MemoryType : Application # Application / System / Base
HandleTableSize: 512
IORegisterMapping:
- 1ff50000-1ff57fff
- 1ff70000-1ff77fff
MemoryMapping:
- 1f000000-1f5fffff:r
SystemCallAccess:
ArbitrateAddress: 34
Break: 60
CancelTimer: 28
ClearEvent: 25
ClearTimer: 29
CloseHandle: 35
ConnectToPort: 45
ControlMemory: 1
CreateAddressArbiter: 33
CreateEvent: 23
CreateMemoryBlock: 30
CreateMutex: 19
CreateSemaphore: 21
CreateThread: 8
CreateTimer: 26
DuplicateHandle: 39
ExitProcess: 3
ExitThread: 9
GetCurrentProcessorNumber: 17
GetHandleInfo: 41
GetProcessId: 53
GetProcessIdOfThread: 54
GetProcessIdealProcessor: 6
GetProcessInfo: 43
GetResourceLimit: 56
GetResourceLimitCurrentValues: 58
GetResourceLimitLimitValues: 57
GetSystemInfo: 42
GetSystemTick: 40
GetThreadContext: 59
GetThreadId: 55
GetThreadIdealProcessor: 15
GetThreadInfo: 44
GetThreadPriority: 11
MapMemoryBlock: 31
OutputDebugString: 61
QueryMemory: 2
ReleaseMutex: 20
ReleaseSemaphore: 22
SendSyncRequest1: 46
SendSyncRequest2: 47
SendSyncRequest3: 48
SendSyncRequest4: 49
SendSyncRequest: 50
SetThreadPriority: 12
SetTimer: 27
SignalEvent: 24
SleepThread: 10
UnmapMemoryBlock: 32
WaitSynchronization1: 36
WaitSynchronizationN: 37
InterruptNumbers:
ServiceAccessControl:
- APT:U
- $hioFIO
- $hostio0
- $hostio1
- ac:u
- boss:U
- cam:u
- cecd:u
- cfg:u
- dlp:FKCL
- dlp:SRVR
- dsp::DSP
- frd:u
- fs:USER
- gsp::Gpu
- hid:USER
- http:C
- mic:u
- ndm:u
- news:u
- nwm::UDS
- ptm:u
- pxi:dev
- soc:U
- ssl:C
- y2r:u
- ldr:ro
- ir:USER
SystemControlInfo:
SaveDataSize: 0KB # It doesn't use any save data.
RemasterVersion: 2
StackSize: 0x40000
# JumpId: 0
Dependency:
ac: 0x0004013000002402L
am: 0x0004013000001502L
boss: 0x0004013000003402L
camera: 0x0004013000001602L
cecd: 0x0004013000002602L
cfg: 0x0004013000001702L
codec: 0x0004013000001802L
csnd: 0x0004013000002702L
dlp: 0x0004013000002802L
dsp: 0x0004013000001a02L
friends: 0x0004013000003202L
gpio: 0x0004013000001b02L
gsp: 0x0004013000001c02L
hid: 0x0004013000001d02L
http: 0x0004013000002902L
i2c: 0x0004013000001e02L
ir: 0x0004013000003302L
mcu: 0x0004013000001f02L
mic: 0x0004013000002002L
ndm: 0x0004013000002b02L
news: 0x0004013000003502L
nim: 0x0004013000002c02L
nwm: 0x0004013000002d02L
pdn: 0x0004013000002102L
ps: 0x0004013000003102L
ptm: 0x0004013000002202L
ro: 0x0004013000003702L
socket: 0x0004013000002e02L
spi: 0x0004013000002302L
ssl: 0x0004013000002f02L

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,83 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <3ds.h>
#include <sf2d.h>
extern const struct {
unsigned int width;
unsigned int height;
unsigned int bytes_per_pixel;
unsigned char pixel_data[];
} citra_img;
extern const struct {
unsigned int width;
unsigned int height;
unsigned int bytes_per_pixel;
unsigned char pixel_data[];
} dice_img;
int main()
{
// Set the random seed based on the time
srand(time(NULL));
sf2d_init();
sf2d_set_clear_color(RGBA8(0x40, 0x40, 0x40, 0xFF));
sf2d_texture *tex1 = sf2d_create_texture_mem_RGBA8(dice_img.pixel_data, dice_img.width, dice_img.height, TEXFMT_RGBA8, SF2D_PLACE_RAM);
sf2d_texture *tex2 = sf2d_create_texture_mem_RGBA8(citra_img.pixel_data, citra_img.width, citra_img.height, TEXFMT_RGBA8, SF2D_PLACE_RAM);
float rad = 0.0f;
u16 touch_x = 320/2;
u16 touch_y = 240/2;
touchPosition touch;
circlePosition circle;
u32 held;
while (aptMainLoop()) {
hidScanInput();
hidCircleRead(&circle);
held = hidKeysHeld();
if (held & KEY_START) {
break;
} else if (held & KEY_TOUCH) {
hidTouchRead(&touch);
touch_x = touch.px;
touch_y = touch.py;
} else if (held & (KEY_L | KEY_R)) {
sf2d_set_clear_color(RGBA8(rand()%255, rand()%255, rand()%255, 255));
}
sf2d_start_frame(GFX_TOP, GFX_LEFT);
sf2d_draw_rectangle_rotate(260, 20, 40, 40, RGBA8(0xFF, 0xFF, 0x00, 0xFF), -2.0f*rad);
sf2d_draw_rectangle(20, 60, 40, 40, RGBA8(0xFF, 0x00, 0x00, 0xFF));
sf2d_draw_rectangle(5, 5, 30, 30, RGBA8(0x00, 0xFF, 0xFF, 0xFF));
sf2d_draw_texture_rotate(tex1, 320/2-tex1->width/2 + circle.dx, 240/2-tex1->height/2 - circle.dy, rad);
sf2d_end_frame();
sf2d_start_frame(GFX_BOTTOM, GFX_LEFT);
sf2d_draw_rectangle_rotate(190, 160, 70, 60, RGBA8(0xFF, 0xFF, 0xFF, 0xFF), 3.0f*rad);
sf2d_draw_rectangle(30, 100, 40, 60, RGBA8(0xFF, 0x00, 0xFF, 0xFF));
sf2d_draw_texture_rotate(tex2, touch_x-tex1->width/2, touch_y-tex1->height/2, -rad);
sf2d_draw_rectangle(160-15 + cosf(rad)*50.0f, 120-15 + sinf(rad)*50.0f, 30, 30, RGBA8(0x00, 0xFF, 0xFF, 0xFF));
sf2d_draw_fill_circle(40, 40, 35, RGBA8(0x00, 0xFF, 0x00, 0xFF));
sf2d_end_frame();
rad += 0.2f;
sf2d_swapbuffers();
}
sf2d_free_texture(tex1);
sf2d_free_texture(tex2);
sf2d_fini();
return 0;
}

21
libs/sfillib/LICENSE Normal file
View file

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 Sergi Granell (xerpi), xerpi.g.12@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

7
libs/sfillib/README.md Normal file
View file

@ -0,0 +1,7 @@
## SFILLIB
Simple and Fast Image Loading library for the Nintendo 3DS (using sf2dlib and ctrulib)
### Documentation
http://xerpi.github.io/sfillib/html/sfil_8h.html

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,145 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/3ds_rules
#---------------------------------------------------------------------------------
# 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
#---------------------------------------------------------------------------------
TARGET := sfil
BUILD := build
SOURCES := source
DATA := data
INCLUDES := include
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard
CFLAGS := -g -Wall -O2\
$(ARCH)
CFLAGS += $(INCLUDE) -DARM11 -D_3DS
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
ASFLAGS := -g $(ARCH)
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(CTRULIB) $(PORTLIBS) \
$(CURDIR)/../../3ds_portlibs/build \
$(CURDIR)/../../sf2dlib/libsf2d
#---------------------------------------------------------------------------------
# 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)/lib/lib$(TARGET).a
export VPATH := $(foreach dir,$(SOURCES),$(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)))
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
#---------------------------------------------------------------------------------
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
$(foreach dir,$(PORTLIBS),-I$(dir)/include/freetype2) \
-I$(CURDIR)/$(BUILD)
.PHONY: $(BUILD) clean all
#---------------------------------------------------------------------------------
all: $(BUILD)
lib:
@[ -d $@ ] || mkdir -p $@
$(BUILD): lib
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) lib latex html
#---------------------------------------------------------------------------------
install: $(BUILD)
@cp $(OUTPUT) $(CTRULIB)/lib
@cp include/sfil.h $(CTRULIB)/include
@echo "Installed!"
#---------------------------------------------------------------------------------
docs:
@doxygen Doxyfile
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT) : $(OFILES)
#---------------------------------------------------------------------------------
%.bin.o : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
# WARNING: This is not the right way to do this! TODO: Do it right!
#---------------------------------------------------------------------------------
%_vsh.h %.vsh.o : %.vsh
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@python $(AEMSTRO)/aemstro_as.py $< ../$(notdir $<).shbin
@bin2s ../$(notdir $<).shbin | $(PREFIX)as -o $@
@echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(notdir $<).shbin | tr . _)`.h
@echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(notdir $<).shbin | tr . _)`.h
@echo "extern const u32" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(notdir $<).shbin | tr . _)`.h
@rm ../$(notdir $<).shbin
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

View file

@ -0,0 +1,71 @@
/**
* @file sfil.h
* @author Sergi Granell (xerpi)
* @date 2 April 2015
* @brief sfillib header
*/
#ifndef SFIL_H
#define SFIL_H
#include <3ds.h>
#include <sf2d.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Loads a PNG image from the SD card
* @param filename the path of the image to load
* @param place where to allocate the texture
* @return a pointer to the newly created texture/image
*/
sf2d_texture *sfil_load_PNG_file(const char *filename, sf2d_place place);
/**
* @brief Loads a PNG image from a memory buffer
* @param buffer the pointer of the memory buffer to load the image from
* @param place where to allocate the texture
* @return a pointer to the newly created texture/image
*/
sf2d_texture *sfil_load_PNG_buffer(const void *buffer, sf2d_place place);
/**
* @brief Loads a JPG/JPEG image from the SD card
* @param filename the path of the image to load
* @param place where to allocate the texture
* @return a pointer to the newly created texture/image
*/
sf2d_texture *sfil_load_JPEG_file(const char *filename, sf2d_place place);
/**
* @brief Loads a JPG/JPEG image from a memory buffer
* @param buffer the pointer of the memory buffer to load the image from
* @param buffer_size the size of the memory buffer
* @param place where to allocate the texture
* @return a pointer to the newly created texture/image
*/
sf2d_texture *sfil_load_JPEG_buffer(const void *buffer, unsigned long buffer_size, sf2d_place place);
/**
* @brief Loads a BMP image from the SD card
* @param filename the path of the image to load
* @param place where to allocate the texture
* @return a pointer to the newly created texture/image
*/
sf2d_texture *sfil_load_BMP_file(const char *filename, sf2d_place place);
/**
* @brief Loads a BMP image from a memory buffer
* @param buffer the pointer of the memory buffer to load the image from
* @param place where to allocate the texture
* @return a pointer to the newly created texture/image
*/
sf2d_texture *sfil_load_BMP_buffer(const void *buffer, sf2d_place place);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,171 @@
#include "sfil.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define BMP_SIGNATURE (0x4D42)
typedef struct {
unsigned short bfType;
unsigned int bfSize;
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned int bfOffBits;
}__attribute__((packed)) BITMAPFILEHEADER;
typedef struct {
unsigned int biSize;
unsigned int biWidth;
unsigned int biHeight;
unsigned short biPlanes;
unsigned short biBitCount;
unsigned int biCompression;
unsigned int biSizeImage;
unsigned int biXPelsPerMeter;
unsigned int biYPelsPerMeter;
unsigned int biClrUsed;
unsigned int biClrImportant;
}__attribute__((packed)) BITMAPINFOHEADER;
static sf2d_texture *_sfil_load_BMP_generic(
BITMAPFILEHEADER *bmp_fh,
BITMAPINFOHEADER *bmp_ih,
void *user_data,
void (*seek_fn)(void *user_data, unsigned int offset),
void (*read_fn)(void *user_data, void *buffer, unsigned int length),
sf2d_place place)
{
unsigned int row_size = bmp_ih->biWidth * (bmp_ih->biBitCount/8);
if (row_size%4 != 0) {
row_size += 4-(row_size%4);
}
sf2d_texture *texture = sf2d_create_texture(bmp_ih->biWidth, bmp_ih->biHeight,
GPU_RGBA8, place);
seek_fn(user_data, bmp_fh->bfOffBits);
int stride = texture->pow2_w * 4;
void *buffer = malloc(row_size);
unsigned int *tex_ptr;
unsigned int color;
int i, x, y;
for (i = 0; i < bmp_ih->biHeight; i++) {
read_fn(user_data, buffer, row_size);
y = bmp_ih->biHeight - 1 - i;
tex_ptr = (unsigned int *)(texture->data + y*stride);
for (x = 0; x < bmp_ih->biWidth; x++) {
if (bmp_ih->biBitCount == 32) { //ABGR8888
color = *(unsigned int *)(buffer + x*4);
*tex_ptr = (color&0xFF)<<24 | ((color>>8)&0xFF)<<16 |
((color>>16)&0xFF)<<8 | (color>>24);
} else if (bmp_ih->biBitCount == 24) { //BGR888
unsigned char *address = buffer + x*3;
*tex_ptr = (*address)<<16 | (*(address+1))<<8 |
(*(address+2)) | (0xFF<<24);
} else if (bmp_ih->biBitCount == 16) { //BGR565
color = *(unsigned short *)(buffer + x*2);
unsigned char r = (color & 0x1F) *((float)255/31);
unsigned char g = ((color>>5) & 0x3F) *((float)255/63);
unsigned char b = ((color>>11) & 0x1F) *((float)255/31);
*tex_ptr = ((r<<16) | (g<<8) | b | (0xFF<<24));
}
tex_ptr++;
}
}
free(buffer);
sf2d_texture_tile32(texture);
return texture;
}
static void _sfil_read_bmp_file_seek_fn(void *user_data, unsigned int offset)
{
fseek((FILE *)user_data, offset, SEEK_SET);
}
static void _sfil_read_bmp_file_read_fn(void *user_data, void *buffer, unsigned int length)
{
fread(buffer, 1, length, (FILE *)user_data);
}
static void _sfil_read_bmp_buffer_seek_fn(void *user_data, unsigned int offset)
{
*(unsigned int *)user_data += offset;
}
static void _sfil_read_bmp_buffer_read_fn(void *user_data, void *buffer, unsigned int length)
{
memcpy(buffer, (void *)*(unsigned int *)user_data, length);
*(unsigned int *)user_data += length;
}
sf2d_texture *sfil_load_BMP_file(const char *filename, sf2d_place place)
{
FILE *fp;
if ((fp = fopen(filename, "rb")) == NULL) {
goto exit_error;
}
BITMAPFILEHEADER bmp_fh;
fread((void *)&bmp_fh, 1, sizeof(BITMAPFILEHEADER), fp);
if (bmp_fh.bfType != BMP_SIGNATURE) {
goto exit_close;
}
BITMAPINFOHEADER bmp_ih;
fread((void *)&bmp_ih, 1, sizeof(BITMAPINFOHEADER), fp);
sf2d_texture *texture = _sfil_load_BMP_generic(&bmp_fh,
&bmp_ih,
(void *)&fp,
_sfil_read_bmp_file_seek_fn,
_sfil_read_bmp_file_read_fn,
place);
fclose(fp);
return texture;
exit_close:
fclose(fp);
exit_error:
return NULL;
}
sf2d_texture *sfil_load_BMP_buffer(const void *buffer, sf2d_place place)
{
BITMAPFILEHEADER bmp_fh;
memcpy(&bmp_fh, buffer, sizeof(BITMAPFILEHEADER));
if (bmp_fh.bfType != BMP_SIGNATURE) {
goto exit_error;
}
BITMAPINFOHEADER bmp_ih;
memcpy(&bmp_ih, buffer + sizeof(BITMAPFILEHEADER), sizeof(BITMAPINFOHEADER));
unsigned int buffer_address = (unsigned int)buffer;
sf2d_texture *texture = _sfil_load_BMP_generic(&bmp_fh,
&bmp_ih,
(void *)&buffer_address,
_sfil_read_bmp_buffer_seek_fn,
_sfil_read_bmp_buffer_read_fn,
place);
return texture;
exit_error:
return NULL;
}

View file

@ -0,0 +1,97 @@
#include "sfil.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <jpeglib.h>
static sf2d_texture *_sfil_load_JPEG_generic(struct jpeg_decompress_struct *jinfo, struct jpeg_error_mgr *jerr, sf2d_place place)
{
int row_bytes;
switch (jinfo->out_color_space) {
case JCS_RGB:
row_bytes = jinfo->image_width * 3;
break;
default:
goto exit_error;
}
sf2d_texture *texture = sf2d_create_texture(jinfo->image_width,
jinfo->image_height,
GPU_RGBA8, place);
JSAMPARRAY buffer = (JSAMPARRAY)malloc(sizeof(JSAMPROW));
buffer[0] = (JSAMPROW)malloc(sizeof(JSAMPLE) * row_bytes);
unsigned int i, color, *tex_ptr;
unsigned char *jpeg_ptr;
void *row_ptr = texture->data;
jpeg_start_decompress(jinfo);
int stride = texture->pow2_w * 4;
while (jinfo->output_scanline < jinfo->output_height) {
jpeg_read_scanlines(jinfo, buffer, 1);
tex_ptr = (row_ptr += stride);
for (i = 0, jpeg_ptr = buffer[0]; i < jinfo->output_width; i++) {
color = *(jpeg_ptr++);
color |= *(jpeg_ptr++)<<8;
color |= *(jpeg_ptr++)<<16;
*(tex_ptr++) = color | 0xFF000000;
}
}
free(buffer[0]);
free(buffer);
sf2d_texture_tile32(texture);
return texture;
exit_error:
return NULL;
}
sf2d_texture *sfil_load_JPEG_file(const char *filename, sf2d_place place)
{
FILE *fp;
if ((fp = fopen(filename, "rb")) < 0) {
return NULL;
}
struct jpeg_decompress_struct jinfo;
struct jpeg_error_mgr jerr;
jinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&jinfo);
jpeg_stdio_src(&jinfo, fp);
jpeg_read_header(&jinfo, 1);
sf2d_texture *texture = _sfil_load_JPEG_generic(&jinfo, &jerr, place);
jpeg_finish_decompress(&jinfo);
jpeg_destroy_decompress(&jinfo);
fclose(fp);
return texture;
}
sf2d_texture *sfil_load_JPEG_buffer(const void *buffer, unsigned long buffer_size, sf2d_place place)
{
struct jpeg_decompress_struct jinfo;
struct jpeg_error_mgr jerr;
jinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&jinfo);
jpeg_mem_src(&jinfo, (void *)buffer, buffer_size);
jpeg_read_header(&jinfo, 1);
sf2d_texture *texture = _sfil_load_JPEG_generic(&jinfo, &jerr, place);
jpeg_finish_decompress(&jinfo);
jpeg_destroy_decompress(&jinfo);
return texture;
}

View file

@ -0,0 +1,139 @@
#include "sfil.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <png.h>
#define PNG_SIGSIZE (8)
static void _sfil_read_png_file_fn(png_structp png_ptr, png_bytep data, png_size_t length)
{
FILE *fp = (FILE *)png_get_io_ptr(png_ptr);
fread(data, 1, length, fp);
}
static void _sfil_read_png_buffer_fn(png_structp png_ptr, png_bytep data, png_size_t length)
{
unsigned int *address = png_get_io_ptr(png_ptr);
memcpy(data, (void *)*address, length);
*address += length;
}
static sf2d_texture *_sfil_load_PNG_generic(const void *io_ptr, png_rw_ptr read_data_fn, sf2d_place place)
{
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL) {
goto exit_error;
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) {
goto exit_destroy_read;
}
png_bytep *row_ptrs = NULL;
if (setjmp(png_jmpbuf(png_ptr))) {
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)0);
if (row_ptrs != NULL)
free(row_ptrs);
goto exit_error;
}
png_set_read_fn(png_ptr, (png_voidp)io_ptr, read_data_fn);
png_set_sig_bytes(png_ptr, PNG_SIGSIZE);
png_read_info(png_ptr, info_ptr);
unsigned int width, height;
int bit_depth, color_type;
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
&color_type, NULL, NULL, NULL);
if ((color_type == PNG_COLOR_TYPE_PALETTE && bit_depth <= 8)
|| (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
|| png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)
|| (bit_depth == 16)) {
png_set_expand(png_ptr);
}
if (bit_depth == 8 && color_type == PNG_COLOR_TYPE_RGB)
png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER);
if (color_type == PNG_COLOR_TYPE_PALETTE) {
png_set_palette_to_rgb(png_ptr);
png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER);
}
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
png_set_expand_gray_1_2_4_to_8(png_ptr);
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
png_set_tRNS_to_alpha(png_ptr);
if (bit_depth < 8)
png_set_packing(png_ptr);
png_read_update_info(png_ptr, info_ptr);
row_ptrs = (png_bytep *)malloc(sizeof(png_bytep) * height);
sf2d_texture *texture = sf2d_create_texture(width, height, GPU_RGBA8, place);
int stride = texture->pow2_w * 4;
int i;
for (i = 0; i < height; i++) {
row_ptrs[i] = (png_bytep)(texture->data + i*stride);
}
png_read_image(png_ptr, row_ptrs);
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)0);
free(row_ptrs);
sf2d_texture_tile32(texture);
return texture;
exit_destroy_read:
png_destroy_read_struct(&png_ptr, (png_infopp)0, (png_infopp)0);
exit_error:
return NULL;
}
sf2d_texture *sfil_load_PNG_file(const char *filename, sf2d_place place)
{
png_byte pngsig[PNG_SIGSIZE];
FILE *fp;
if ((fp = fopen(filename, "rb")) == NULL) {
goto exit_error;
}
if (fread(pngsig, 1, PNG_SIGSIZE, fp) != PNG_SIGSIZE) {
goto exit_close;
}
if (png_sig_cmp(pngsig, 0, PNG_SIGSIZE) != 0) {
goto exit_close;
}
sf2d_texture *texture = _sfil_load_PNG_generic((void *)fp, _sfil_read_png_file_fn, place);
fclose(fp);
return texture;
exit_close:
fclose(fp);
exit_error:
return NULL;
}
sf2d_texture *sfil_load_PNG_buffer(const void *buffer, sf2d_place place)
{
if (png_sig_cmp((png_byte *) buffer, 0, PNG_SIGSIZE) != 0) {
return NULL;
}
unsigned int buffer_address = (unsigned int)buffer + PNG_SIGSIZE;
return _sfil_load_PNG_generic((void *)&buffer_address, _sfil_read_png_buffer_fn, place);
}

View file

@ -0,0 +1,207 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
TOPDIR ?= $(CURDIR)
include $(DEVKITARM)/3ds_rules
#---------------------------------------------------------------------------------
# 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
#
# NO_SMDH: if set to anything, no SMDH file is generated.
# 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 := sfil_sample
BUILD := build
SOURCES := source
DATA := data
INCLUDES := include
APP_TITLE := SFILLIB sample
APP_DESCRIPTION := SFILLIB sample
APP_AUTHOR := xerpi
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard
CFLAGS := -g -Wall -O2 -mword-relocations \
-fomit-frame-pointer -ffast-math \
$(ARCH)
CFLAGS += $(INCLUDE) -DARM11 -D_3DS
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
LIBS := -lsfil -lpng -ljpeg -lz -lsf2d -lctru -lm
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(CTRULIB) $(PORTLIBS)
#---------------------------------------------------------------------------------
# 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,$(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)))
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
#---------------------------------------------------------------------------------
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
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)
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
.PHONY: $(BUILD) clean all
#---------------------------------------------------------------------------------
all: $(BUILD)
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(TARGET).3dsx $(OUTPUT).smdh $(TARGET).elf $(TARGET)-strip.elf $(TARGET).cia $(TARGET).3ds
#---------------------------------------------------------------------------------
$(TARGET)-strip.elf: $(BUILD)
@$(STRIP) $(TARGET).elf -o $(TARGET)-strip.elf
#---------------------------------------------------------------------------------
cci: $(TARGET)-strip.elf
@makerom -f cci -rsf resources/$(TARGET).rsf -target d -exefslogo -elf $(TARGET)-strip.elf -o $(TARGET).3ds
@echo "built ... sfil_sample.3ds"
#---------------------------------------------------------------------------------
cia: $(TARGET)-strip.elf
@makerom -f cia -o $(TARGET).cia -elf $(TARGET)-strip.elf -rsf resources/$(TARGET).rsf -exefslogo -target t
@echo "built ... sfil_sample.cia"
#---------------------------------------------------------------------------------
send: $(BUILD)
@3dslink $(TARGET).3dsx
#---------------------------------------------------------------------------------
run: $(BUILD)
@citra $(TARGET).3dsx
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
ifeq ($(strip $(NO_SMDH)),)
$(OUTPUT).3dsx : $(OUTPUT).elf $(OUTPUT).smdh
else
$(OUTPUT).3dsx : $(OUTPUT).elf
endif
$(OUTPUT).elf : $(OFILES)
#---------------------------------------------------------------------------------
# you need a rule like this for each extension you use as binary data
#---------------------------------------------------------------------------------
%.bin.o : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
#---------------------------------------------------------------------------------
%.jpeg.o: %.jpeg
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
#---------------------------------------------------------------------------------
%.png.o : %.png
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
# WARNING: This is not the right way to do this! TODO: Do it right!
#---------------------------------------------------------------------------------
%.vsh.o : %.vsh
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@python $(AEMSTRO)/aemstro_as.py $< ../$(notdir $<).shbin
@bin2s ../$(notdir $<).shbin | $(PREFIX)as -o $@
@echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(notdir $<).shbin | tr . _)`.h
@echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(notdir $<).shbin | tr . _)`.h
@echo "extern const u32" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(notdir $<).shbin | tr . _)`.h
@rm ../$(notdir $<).shbin
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

View file

@ -0,0 +1,236 @@
BasicInfo:
Title : "SFILLIB sample"
CompanyCode : "00"
ProductCode : "sfil-sample"
ContentType : Application # Application / SystemUpdate / Manual / Child / Trial
Logo : Nintendo # Nintendo / Licensed / Distributed / iQue / iQueForSystem
#Rom:
# Specifies the root path of the file system to include in the ROM.
# HostRoot : "$(ROMFS_ROOT)"
TitleInfo:
UniqueId : 0xf0030 # This was/is the first real homebrew app. I hope this TID range is not used by any retail game/app.
Category : Application # Application / SystemApplication / Applet / Firmware / Base / DlpChild / Demo / Contents / SystemContents / SharedContents / AddOnContents / Patch / AutoUpdateContents
CardInfo:
MediaSize : 512MB # 128MB / 256MB / 512MB / 1GB / 2GB / 4GB / 8GB / 16GB / 32GB
MediaType : Card1 # Card1 / Card2
CardDevice : NorFlash # NorFlash(Pick this if you use savedata) / None
Option:
UseOnSD : true # true if App is to be installed to SD
EnableCompress : true # Compresses exefs code
FreeProductCode : true # Removes limitations on ProductCode
EnableCrypt : false # Enables encryption for NCCH and CIA
MediaFootPadding : false # If true CCI files are created with padding
ExeFs: # these are the program segments from the ELF, check your elf for the appropriate segment names
ReadOnly:
- .rodata
- RO
ReadWrite:
- .data
- RO
Text:
- .init
- .text
- STUP_ENTRY
PlainRegion: # only used with SDK ELFs
# - .module_id
AccessControlInfo:
# UseOtherVariationSaveData : true
# UseExtSaveData : true
# ExtSaveDataId: 0xffffffff
# SystemSaveDataId1: 0x220
# SystemSaveDataId2: 0x00040010
# OtherUserSaveDataId1: 0x220
# OtherUserSaveDataId2: 0x330
# OtherUserSaveDataId3: 0x440
# UseExtendedSaveDataAccessControl: true
# AccessibleSaveDataIds: [0x101, 0x202, 0x303, 0x404, 0x505, 0x606]
FileSystemAccess:
# - CategorySystemApplication
# - CategoryHardwareCheck
# - CategoryFileSystemTool
- Debug
# - TwlCardBackup
# - TwlNandData
# - Boss
- DirectSdmc
# - Core
# - CtrNandRo
# - CtrNandRw
# - CtrNandRoWrite
# - CategorySystemSettings
# - CardBoard
# - ExportImportIvs
# - DirectSdmcWrite
# - SwitchCleanup
# - SaveDataMove
# - Shop
# - Shell
# - CategoryHomeMenu
IoAccessControl:
# - FsMountNand
# - FsMountNandRoWrite
# - FsMountTwln
# - FsMountWnand
# - FsMountCardSpi
# - UseSdif3
# - CreateSeed
# - UseCardSpi
IdealProcessor : 0
AffinityMask : 1
Priority : 16
MaxCpu : 0x9E # Default
DisableDebug : true
EnableForceDebug : false
CanWriteSharedPage : true
CanUsePrivilegedPriority : false
CanUseNonAlphabetAndNumber : true
PermitMainFunctionArgument : true
CanShareDeviceMemory : true
RunnableOnSleep : false
SpecialMemoryArrange : true
CoreVersion : 2
DescVersion : 2
ReleaseKernelMajor : "02"
ReleaseKernelMinor : "33"
MemoryType : Application # Application / System / Base
HandleTableSize: 512
IORegisterMapping:
- 1ff50000-1ff57fff
- 1ff70000-1ff77fff
MemoryMapping:
- 1f000000-1f5fffff:r
SystemCallAccess:
ArbitrateAddress: 34
Break: 60
CancelTimer: 28
ClearEvent: 25
ClearTimer: 29
CloseHandle: 35
ConnectToPort: 45
ControlMemory: 1
CreateAddressArbiter: 33
CreateEvent: 23
CreateMemoryBlock: 30
CreateMutex: 19
CreateSemaphore: 21
CreateThread: 8
CreateTimer: 26
DuplicateHandle: 39
ExitProcess: 3
ExitThread: 9
GetCurrentProcessorNumber: 17
GetHandleInfo: 41
GetProcessId: 53
GetProcessIdOfThread: 54
GetProcessIdealProcessor: 6
GetProcessInfo: 43
GetResourceLimit: 56
GetResourceLimitCurrentValues: 58
GetResourceLimitLimitValues: 57
GetSystemInfo: 42
GetSystemTick: 40
GetThreadContext: 59
GetThreadId: 55
GetThreadIdealProcessor: 15
GetThreadInfo: 44
GetThreadPriority: 11
MapMemoryBlock: 31
OutputDebugString: 61
QueryMemory: 2
ReleaseMutex: 20
ReleaseSemaphore: 22
SendSyncRequest1: 46
SendSyncRequest2: 47
SendSyncRequest3: 48
SendSyncRequest4: 49
SendSyncRequest: 50
SetThreadPriority: 12
SetTimer: 27
SignalEvent: 24
SleepThread: 10
UnmapMemoryBlock: 32
WaitSynchronization1: 36
WaitSynchronizationN: 37
InterruptNumbers:
ServiceAccessControl:
- APT:U
- $hioFIO
- $hostio0
- $hostio1
- ac:u
- boss:U
- cam:u
- cecd:u
- cfg:u
- dlp:FKCL
- dlp:SRVR
- dsp::DSP
- frd:u
- fs:USER
- gsp::Gpu
- hid:USER
- http:C
- mic:u
- ndm:u
- news:u
- nwm::UDS
- ptm:u
- pxi:dev
- soc:U
- ssl:C
- y2r:u
- ldr:ro
- ir:USER
SystemControlInfo:
SaveDataSize: 0KB # It doesn't use any save data.
RemasterVersion: 2
StackSize: 0x40000
# JumpId: 0
Dependency:
ac: 0x0004013000002402L
am: 0x0004013000001502L
boss: 0x0004013000003402L
camera: 0x0004013000001602L
cecd: 0x0004013000002602L
cfg: 0x0004013000001702L
codec: 0x0004013000001802L
csnd: 0x0004013000002702L
dlp: 0x0004013000002802L
dsp: 0x0004013000001a02L
friends: 0x0004013000003202L
gpio: 0x0004013000001b02L
gsp: 0x0004013000001c02L
hid: 0x0004013000001d02L
http: 0x0004013000002902L
i2c: 0x0004013000001e02L
ir: 0x0004013000003302L
mcu: 0x0004013000001f02L
mic: 0x0004013000002002L
ndm: 0x0004013000002b02L
news: 0x0004013000003502L
nim: 0x0004013000002c02L
nwm: 0x0004013000002d02L
pdn: 0x0004013000002102L
ps: 0x0004013000003102L
ptm: 0x0004013000002202L
ro: 0x0004013000003702L
socket: 0x0004013000002e02L
spi: 0x0004013000002302L
ssl: 0x0004013000002f02L

View file

@ -0,0 +1,45 @@
#include <3ds.h>
#include <sf2d.h>
#include <sfil.h>
#include "citra_jpeg.h"
#include "3dbrew_png.h"
int main()
{
sf2d_init();
sf2d_set_clear_color(RGBA8(0x40, 0x40, 0x40, 0xFF));
sf2d_texture *tex1 = sfil_load_JPEG_buffer(citra_jpeg, citra_jpeg_size, SF2D_PLACE_RAM);
sf2d_texture *tex2 = sfil_load_PNG_buffer(_3dbrew_png, SF2D_PLACE_RAM);
while (aptMainLoop()) {
hidScanInput();
if (hidKeysHeld() & KEY_START) {
break;
}
sf2d_start_frame(GFX_TOP, GFX_LEFT);
sf2d_draw_texture(tex1, 400/2 - tex1->width/2, 240/2 - tex1->height/2);
sf2d_end_frame();
sf2d_start_frame(GFX_BOTTOM, GFX_LEFT);
sf2d_draw_texture(tex2, 320/2 - tex2->width/2, 240/2 - tex2->height/2);
sf2d_end_frame();
sf2d_swapbuffers();
}
sf2d_free_texture(tex1);
sf2d_free_texture(tex2);
sf2d_fini();
return 0;
}

21
libs/sftdlib/LICENSE Normal file
View file

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 Sergi Granell (xerpi), xerpi.g.12@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

11
libs/sftdlib/README.md Normal file
View file

@ -0,0 +1,11 @@
## SFTDLIB
Simple and Fast Text Drawing library for the Nintendo 3DS (using sf2dlib and ctrulib)
### Prerequisites
ctrulib: https://github.com/smealum/ctrulib
SF2D: https://github.com/xerpi/sf2dlib
FreeType2 (portlib): https://github.com/xerpi/3ds_portlibs

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,141 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/3ds_rules
#---------------------------------------------------------------------------------
# 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
#---------------------------------------------------------------------------------
TARGET := sftd
BUILD := build
SOURCES := source
DATA := data
INCLUDES := include
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard
CFLAGS := -g -Wall -O2\
$(ARCH)
CFLAGS += $(INCLUDE) -DARM11 -D_3DS
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
ASFLAGS := -g $(ARCH)
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(CTRULIB) $(PORTLIBS) \
$(CURDIR)/../../3ds_portlibs/build \
$(CURDIR)/../../sf2dlib/libsf2d
#---------------------------------------------------------------------------------
# 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)/lib/lib$(TARGET).a
export VPATH := $(foreach dir,$(SOURCES),$(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)))
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
#---------------------------------------------------------------------------------
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
$(foreach dir,$(PORTLIBS),-I$(dir)/include/freetype2) \
-I$(CURDIR)/$(BUILD)
.PHONY: $(BUILD) clean all
#---------------------------------------------------------------------------------
all: $(BUILD)
lib:
@[ -d $@ ] || mkdir -p $@
$(BUILD): lib
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) lib latex html
#---------------------------------------------------------------------------------
install: $(BUILD)
@cp $(OUTPUT) $(CTRULIB)/lib
@cp include/sftd.h $(CTRULIB)/include
@echo "Installed!"
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT) : $(OFILES)
#---------------------------------------------------------------------------------
%.bin.o : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
# WARNING: This is not the right way to do this! TODO: Do it right!
#---------------------------------------------------------------------------------
%_vsh.h %.vsh.o : %.vsh
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@python $(AEMSTRO)/aemstro_as.py $< ../$(notdir $<).shbin
@bin2s ../$(notdir $<).shbin | $(PREFIX)as -o $@
@echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(notdir $<).shbin | tr . _)`.h
@echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(notdir $<).shbin | tr . _)`.h
@echo "extern const u32" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(notdir $<).shbin | tr . _)`.h
@rm ../$(notdir $<).shbin
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

View file

@ -0,0 +1,113 @@
/**
* @file sftd.h
* @author Sergi Granell (xerpi)
* @date 2 April 2015
* @brief sftdlib header
*/
#ifndef SFTD_H
#define SFTD_H
#include <3ds.h>
#ifdef __cplusplus
extern "C" {
#endif
// Structs
/**
* @brief Represents a font
*/
typedef struct sftd_font sftd_font;
// Basic functions
/**
* @brief Initializates the library
* @return Whether the initialization has been successful or not
*/
int sftd_init();
/**
* @brief Finishes the library
* @return Whether the finalization has been successful or not
*/
int sftd_fini();
/**
* @brief Loads a font from a file
* @param filename the path to the font
* @return a pointer to the loaded font (NULL on error)
*/
sftd_font *sftd_load_font_file(const char *filename);
/**
* @brief Loads a font from memory
* @param buffer the address of the font
* @param size the size of the font buffer
* @return a pointer to the loaded font (NULL on error)
*/
sftd_font *sftd_load_font_mem(const void *buffer, unsigned int size);
/**
* @brief Frees a font
* @param font pointer to the font to freeze
*/
void sftd_free_font(sftd_font *font);
// Draw functions
/**
* @brief Draws text using a font
* @param font the font to use
* @param x the x coordinate to draw the text to
* @param y the y coordinate to draw the text to
* @param color the color to draw the font
* @param size the font size
* @param text a pointer to the text to draw
*/
void sftd_draw_text(sftd_font *font, int x, int y, unsigned int color, unsigned int size, const char *text);
/**
* @brief Draws formatted text using a font
* @param font the font to use
* @param x the x coordinate to draw the text to
* @param y the y coordinate to draw the text to
* @param color the color to draw the font
* @param size the font size
* @param text a pointer to the text to draw
* @param ... variable arguments
*/
void sftd_draw_textf(sftd_font *font, int x, int y, unsigned int color, unsigned int size, const char *text, ...);
/**
* @brief Draws wide text using a font
* @param font the font to use
* @param x the x coordinate to draw the text to
* @param y the y coordinate to draw the text to
* @param color the color to draw the font
* @param size the font size
* @param text a pointer to the wide text to draw
*/
void sftd_draw_wtext(sftd_font *font, int x, int y, unsigned int color, unsigned int size, const wchar_t *text);
/**
* @brief Draws formatted wide text using a font
* @param font the font to use
* @param x the x coordinate to draw the text to
* @param y the y coordinate to draw the text to
* @param color the color to draw the font
* @param size the font size
* @param text a pointer to the wide text to draw
* @param ... variable arguments
*/
void sftd_draw_wtextf(sftd_font *font, int x, int y, unsigned int color, unsigned int size, const wchar_t *text, ...);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,269 @@
#include "sftd.h"
#include <wchar.h>
#include <sf2d.h>
#include <ft2build.h>
#include FT_CACHE_H
#include FT_FREETYPE_H
static int sftd_initialized = 0;
static FT_Library ftlibrary;
static FTC_Manager ftcmanager;
typedef enum {
SFTD_LOAD_FROM_FILE,
SFTD_LOAD_FROM_MEM
} sftd_font_load_from;
struct sftd_font {
sftd_font_load_from from;
union {
char *filename;
struct {
const void *font_buffer;
unsigned int buffer_size;
};
};
FTC_CMapCache cmapcache;
FTC_ImageCache imagecache;
};
static FT_Error ftc_face_requester(FTC_FaceID face_id, FT_Library library, FT_Pointer request_data, FT_Face *face)
{
sftd_font *font = (sftd_font *)face_id;
FT_Error error = FT_Err_Cannot_Open_Resource;
if (font->from == SFTD_LOAD_FROM_FILE) {
error = FT_New_Face(
library,
font->filename,
0,
face);
} else if (font->from == SFTD_LOAD_FROM_MEM) {
error = FT_New_Memory_Face(
library,
font->font_buffer,
font->buffer_size,
0,
face);
}
return error;
}
int sftd_init()
{
if (sftd_initialized) return 2;
FT_Error error = FT_Init_FreeType(&ftlibrary);
if (error != FT_Err_Ok) {
return 0;
}
error = FTC_Manager_New(
ftlibrary,
0, /* use default */
0, /* use default */
0, /* use default */
&ftc_face_requester, /* use our requester */
NULL, /* user data */
&ftcmanager);
if (error != FT_Err_Ok) {
FT_Done_FreeType(ftlibrary);
return 0;
}
sftd_initialized = 1;
return 1;
}
int sftd_fini()
{
if (!sftd_initialized) return 2;
FT_Error error = FT_Done_FreeType(ftlibrary);
if (error != FT_Err_Ok) {
return 0;
}
FTC_Manager_Done(ftcmanager);
sftd_initialized = 0;
return 1;
}
sftd_font *sftd_load_font_file(const char *filename)
{
sftd_font *font = malloc(sizeof(*font));
size_t len = strlen(filename);
font->filename = malloc(len + 1);
strcpy(font->filename, filename);
font->filename[len] = '\0';
FTC_CMapCache_New(ftcmanager, &font->cmapcache);
FTC_ImageCache_New(ftcmanager, &font->imagecache);
font->from = SFTD_LOAD_FROM_FILE;
return font;
}
sftd_font *sftd_load_font_mem(const void *buffer, unsigned int size)
{
sftd_font *font = malloc(sizeof(*font));
font->font_buffer = buffer;
font->buffer_size = size;
FTC_CMapCache_New(ftcmanager, &font->cmapcache);
FTC_ImageCache_New(ftcmanager, &font->imagecache);
font->from = SFTD_LOAD_FROM_MEM;
return font;
}
void sftd_free_font(sftd_font *font)
{
if (font) {
FTC_FaceID face_id = (FTC_FaceID)font;
FTC_Manager_RemoveFaceID(ftcmanager, face_id);
if (font->from == SFTD_LOAD_FROM_FILE) {
free(font->filename);
}
free(font);
}
}
static void draw_bitmap(FT_Bitmap *bitmap, int x, int y, unsigned int color)
{
//This is too ugly
sf2d_texture *tex = sf2d_create_texture(bitmap->width, bitmap->rows, GPU_RGBA8, SF2D_PLACE_TEMP);
int j, k;
for (j = 0; j < bitmap->rows; j++) {
for (k = 0; k < bitmap->width; k++) {
((u32 *)tex->data)[j*tex->pow2_w + k] = __builtin_bswap32((color & ~0xFF) | bitmap->buffer[j*bitmap->width + k]);
}
}
sf2d_texture_tile32(tex);
sf2d_draw_texture(tex, x, y);
sf2d_free_texture(tex);
}
void sftd_draw_text(sftd_font *font, int x, int y, unsigned int color, unsigned int size, const char *text)
{
FTC_FaceID face_id = (FTC_FaceID)font;
FT_Face face;
FTC_Manager_LookupFace(ftcmanager, face_id, &face);
FT_Int charmap_index;
charmap_index = FT_Get_Charmap_Index(face->charmap);
FT_Glyph glyph;
FT_Bool use_kerning = FT_HAS_KERNING(face);
FT_UInt glyph_index, previous = 0;
int pen_x = x;
int pen_y = y;
FTC_ScalerRec scaler;
scaler.face_id = face_id;
scaler.width = size;
scaler.height = size;
scaler.pixel = 1;
FT_ULong flags = FT_LOAD_RENDER | FT_LOAD_TARGET_NORMAL;
while (*text) {
glyph_index = FTC_CMapCache_Lookup(font->cmapcache, (FTC_FaceID)font, charmap_index, *text);
if (use_kerning && previous && glyph_index) {
FT_Vector delta;
FT_Get_Kerning(face, previous, glyph_index, FT_KERNING_DEFAULT, &delta);
pen_x += delta.x >> 6;
}
FTC_ImageCache_LookupScaler(font->imagecache, &scaler, flags, glyph_index, &glyph, NULL);
if (glyph->format == FT_GLYPH_FORMAT_BITMAP) {
FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph)glyph;
draw_bitmap(&bitmap_glyph->bitmap, pen_x + bitmap_glyph->left + x, pen_y - bitmap_glyph->top + y, color);
pen_x += bitmap_glyph->root.advance.x >> 16;
pen_y += bitmap_glyph->root.advance.y >> 16;
}
previous = glyph_index;
text++;
}
}
void sftd_draw_textf(sftd_font *font, int x, int y, unsigned int color, unsigned int size, const char *text, ...)
{
char buffer[256];
va_list args;
va_start(args, text);
vsnprintf(buffer, 256, text, args);
sftd_draw_text(font, x, y, color, size, buffer);
va_end(args);
}
void sftd_draw_wtext(sftd_font *font, int x, int y, unsigned int color, unsigned int size, const wchar_t *text)
{
FTC_FaceID face_id = (FTC_FaceID)font;
FT_Face face;
FTC_Manager_LookupFace(ftcmanager, face_id, &face);
FT_Int charmap_index;
charmap_index = FT_Get_Charmap_Index(face->charmap);
FT_Glyph glyph;
FT_Bool use_kerning = FT_HAS_KERNING(face);
FT_UInt glyph_index, previous = 0;
int pen_x = x;
int pen_y = y;
FTC_ScalerRec scaler;
scaler.face_id = face_id;
scaler.width = size;
scaler.height = size;
scaler.pixel = 1;
FT_ULong flags = FT_LOAD_RENDER | FT_LOAD_TARGET_NORMAL;
while (*text) {
glyph_index = FTC_CMapCache_Lookup(font->cmapcache, (FTC_FaceID)font, charmap_index, *text);
if (use_kerning && previous && glyph_index) {
FT_Vector delta;
FT_Get_Kerning(face, previous, glyph_index, FT_KERNING_DEFAULT, &delta);
pen_x += delta.x >> 6;
}
FTC_ImageCache_LookupScaler(font->imagecache, &scaler, flags, glyph_index, &glyph, NULL);
if (glyph->format == FT_GLYPH_FORMAT_BITMAP) {
FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph)glyph;
draw_bitmap(&bitmap_glyph->bitmap, pen_x + bitmap_glyph->left + x, pen_y - bitmap_glyph->top + y, color);
pen_x += bitmap_glyph->root.advance.x >> 16;
pen_y += bitmap_glyph->root.advance.y >> 16;
}
previous = glyph_index;
text++;
}
}
void sftd_draw_wtextf(sftd_font *font, int x, int y, unsigned int color, unsigned int size, const wchar_t *text, ...)
{
wchar_t buffer[256];
va_list args;
va_start(args, text);
vswprintf(buffer, 256, text, args);
sftd_draw_wtext(font, x, y, color, size, buffer);
va_end(args);
}

View file

@ -0,0 +1,201 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
TOPDIR ?= $(CURDIR)
include $(DEVKITARM)/3ds_rules
#---------------------------------------------------------------------------------
# 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
#
# NO_SMDH: if set to anything, no SMDH file is generated.
# 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 := sftd_sample
BUILD := build
SOURCES := source
DATA := data
INCLUDES := include
APP_TITLE := SFFTLIB sample
APP_DESCRIPTION := SFFTLIB sample
APP_AUTHOR := xerpi
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard
CFLAGS := -g -Wall -O2 -mword-relocations \
-fomit-frame-pointer -ffast-math \
$(ARCH)
CFLAGS += $(INCLUDE) -DARM11 -D_3DS
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
LIBS := -lsftd -lfreetype -lpng -lz -lsf2d -lctru -lm
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(CTRULIB) $(PORTLIBS)
#---------------------------------------------------------------------------------
# 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,$(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)))
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
#---------------------------------------------------------------------------------
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
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)
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
.PHONY: $(BUILD) clean all
#---------------------------------------------------------------------------------
all: $(BUILD)
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(TARGET).3dsx $(OUTPUT).smdh $(TARGET).elf $(TARGET)-strip.elf $(TARGET).cia $(TARGET).3ds
#---------------------------------------------------------------------------------
$(TARGET)-strip.elf: $(BUILD)
@$(STRIP) $(TARGET).elf -o $(TARGET)-strip.elf
#---------------------------------------------------------------------------------
cci: $(TARGET)-strip.elf
@makerom -f cci -rsf resources/$(TARGET).rsf -target d -exefslogo -elf $(TARGET)-strip.elf -o $(TARGET).3ds
@echo "built ... sf2d_sample.3ds"
#---------------------------------------------------------------------------------
cia: $(TARGET)-strip.elf
@makerom -f cia -o $(TARGET).cia -elf $(TARGET)-strip.elf -rsf resources/$(TARGET).rsf -exefslogo -target t
@echo "built ... sf2d_sample.cia"
#---------------------------------------------------------------------------------
send: $(BUILD)
@3dslink $(TARGET).3dsx
#---------------------------------------------------------------------------------
run: $(BUILD)
@citra $(TARGET).3dsx
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
ifeq ($(strip $(NO_SMDH)),)
$(OUTPUT).3dsx : $(OUTPUT).elf $(OUTPUT).smdh
else
$(OUTPUT).3dsx : $(OUTPUT).elf
endif
$(OUTPUT).elf : $(OFILES)
#---------------------------------------------------------------------------------
# you need a rule like this for each extension you use as binary data
#---------------------------------------------------------------------------------
%.bin.o : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
#---------------------------------------------------------------------------------
%.ttf.o : %.ttf
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
# WARNING: This is not the right way to do this! TODO: Do it right!
#---------------------------------------------------------------------------------
%.vsh.o : %.vsh
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@python $(AEMSTRO)/aemstro_as.py $< ../$(notdir $<).shbin
@bin2s ../$(notdir $<).shbin | $(PREFIX)as -o $@
@echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(notdir $<).shbin | tr . _)`.h
@echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(notdir $<).shbin | tr . _)`.h
@echo "extern const u32" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(notdir $<).shbin | tr . _)`.h
@rm ../$(notdir $<).shbin
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

Binary file not shown.

View file

@ -0,0 +1,236 @@
BasicInfo:
Title : "SFTDLIB sample"
CompanyCode : "00"
ProductCode : "sftd-sample"
ContentType : Application # Application / SystemUpdate / Manual / Child / Trial
Logo : Nintendo # Nintendo / Licensed / Distributed / iQue / iQueForSystem
#Rom:
# Specifies the root path of the file system to include in the ROM.
# HostRoot : "$(ROMFS_ROOT)"
TitleInfo:
UniqueId : 0xf0024 # This was/is the first real homebrew app. I hope this TID range is not used by any retail game/app.
Category : Application # Application / SystemApplication / Applet / Firmware / Base / DlpChild / Demo / Contents / SystemContents / SharedContents / AddOnContents / Patch / AutoUpdateContents
CardInfo:
MediaSize : 512MB # 128MB / 256MB / 512MB / 1GB / 2GB / 4GB / 8GB / 16GB / 32GB
MediaType : Card1 # Card1 / Card2
CardDevice : NorFlash # NorFlash(Pick this if you use savedata) / None
Option:
UseOnSD : true # true if App is to be installed to SD
EnableCompress : true # Compresses exefs code
FreeProductCode : true # Removes limitations on ProductCode
EnableCrypt : false # Enables encryption for NCCH and CIA
MediaFootPadding : false # If true CCI files are created with padding
ExeFs: # these are the program segments from the ELF, check your elf for the appropriate segment names
ReadOnly:
- .rodata
- RO
ReadWrite:
- .data
- RO
Text:
- .init
- .text
- STUP_ENTRY
PlainRegion: # only used with SDK ELFs
# - .module_id
AccessControlInfo:
# UseOtherVariationSaveData : true
# UseExtSaveData : true
# ExtSaveDataId: 0xffffffff
# SystemSaveDataId1: 0x220
# SystemSaveDataId2: 0x00040010
# OtherUserSaveDataId1: 0x220
# OtherUserSaveDataId2: 0x330
# OtherUserSaveDataId3: 0x440
# UseExtendedSaveDataAccessControl: true
# AccessibleSaveDataIds: [0x101, 0x202, 0x303, 0x404, 0x505, 0x606]
FileSystemAccess:
# - CategorySystemApplication
# - CategoryHardwareCheck
# - CategoryFileSystemTool
- Debug
# - TwlCardBackup
# - TwlNandData
# - Boss
- DirectSdmc
# - Core
# - CtrNandRo
# - CtrNandRw
# - CtrNandRoWrite
# - CategorySystemSettings
# - CardBoard
# - ExportImportIvs
# - DirectSdmcWrite
# - SwitchCleanup
# - SaveDataMove
# - Shop
# - Shell
# - CategoryHomeMenu
IoAccessControl:
# - FsMountNand
# - FsMountNandRoWrite
# - FsMountTwln
# - FsMountWnand
# - FsMountCardSpi
# - UseSdif3
# - CreateSeed
# - UseCardSpi
IdealProcessor : 0
AffinityMask : 1
Priority : 16
MaxCpu : 0x9E # Default
DisableDebug : true
EnableForceDebug : false
CanWriteSharedPage : true
CanUsePrivilegedPriority : false
CanUseNonAlphabetAndNumber : true
PermitMainFunctionArgument : true
CanShareDeviceMemory : true
RunnableOnSleep : false
SpecialMemoryArrange : true
CoreVersion : 2
DescVersion : 2
ReleaseKernelMajor : "02"
ReleaseKernelMinor : "33"
MemoryType : Application # Application / System / Base
HandleTableSize: 512
IORegisterMapping:
- 1ff50000-1ff57fff
- 1ff70000-1ff77fff
MemoryMapping:
- 1f000000-1f5fffff:r
SystemCallAccess:
ArbitrateAddress: 34
Break: 60
CancelTimer: 28
ClearEvent: 25
ClearTimer: 29
CloseHandle: 35
ConnectToPort: 45
ControlMemory: 1
CreateAddressArbiter: 33
CreateEvent: 23
CreateMemoryBlock: 30
CreateMutex: 19
CreateSemaphore: 21
CreateThread: 8
CreateTimer: 26
DuplicateHandle: 39
ExitProcess: 3
ExitThread: 9
GetCurrentProcessorNumber: 17
GetHandleInfo: 41
GetProcessId: 53
GetProcessIdOfThread: 54
GetProcessIdealProcessor: 6
GetProcessInfo: 43
GetResourceLimit: 56
GetResourceLimitCurrentValues: 58
GetResourceLimitLimitValues: 57
GetSystemInfo: 42
GetSystemTick: 40
GetThreadContext: 59
GetThreadId: 55
GetThreadIdealProcessor: 15
GetThreadInfo: 44
GetThreadPriority: 11
MapMemoryBlock: 31
OutputDebugString: 61
QueryMemory: 2
ReleaseMutex: 20
ReleaseSemaphore: 22
SendSyncRequest1: 46
SendSyncRequest2: 47
SendSyncRequest3: 48
SendSyncRequest4: 49
SendSyncRequest: 50
SetThreadPriority: 12
SetTimer: 27
SignalEvent: 24
SleepThread: 10
UnmapMemoryBlock: 32
WaitSynchronization1: 36
WaitSynchronizationN: 37
InterruptNumbers:
ServiceAccessControl:
- APT:U
- $hioFIO
- $hostio0
- $hostio1
- ac:u
- boss:U
- cam:u
- cecd:u
- cfg:u
- dlp:FKCL
- dlp:SRVR
- dsp::DSP
- frd:u
- fs:USER
- gsp::Gpu
- hid:USER
- http:C
- mic:u
- ndm:u
- news:u
- nwm::UDS
- ptm:u
- pxi:dev
- soc:U
- ssl:C
- y2r:u
- ldr:ro
- ir:USER
SystemControlInfo:
SaveDataSize: 0KB # It doesn't use any save data.
RemasterVersion: 2
StackSize: 0x40000
# JumpId: 0
Dependency:
ac: 0x0004013000002402L
am: 0x0004013000001502L
boss: 0x0004013000003402L
camera: 0x0004013000001602L
cecd: 0x0004013000002602L
cfg: 0x0004013000001702L
codec: 0x0004013000001802L
csnd: 0x0004013000002702L
dlp: 0x0004013000002802L
dsp: 0x0004013000001a02L
friends: 0x0004013000003202L
gpio: 0x0004013000001b02L
gsp: 0x0004013000001c02L
hid: 0x0004013000001d02L
http: 0x0004013000002902L
i2c: 0x0004013000001e02L
ir: 0x0004013000003302L
mcu: 0x0004013000001f02L
mic: 0x0004013000002002L
ndm: 0x0004013000002b02L
news: 0x0004013000003502L
nim: 0x0004013000002c02L
nwm: 0x0004013000002d02L
pdn: 0x0004013000002102L
ps: 0x0004013000003102L
ptm: 0x0004013000002202L
ro: 0x0004013000003702L
socket: 0x0004013000002e02L
spi: 0x0004013000002302L
ssl: 0x0004013000002f02L

View file

@ -0,0 +1,41 @@
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <3ds.h>
#include <sf2d.h>
#include <sftd.h>
#include "airstrike_ttf.h"
int main()
{
sf2d_init();
sf2d_set_clear_color(RGBA8(0x40, 0x40, 0x40, 0xFF));
consoleInit(GFX_BOTTOM, NULL);
printf("sftd sample\n");
// Font loading
sftd_init();
sftd_font *font = sftd_load_font_mem(airstrike_ttf, airstrike_ttf_size);
while (aptMainLoop()) {
hidScanInput();
if (hidKeysDown() & KEY_START) break;
sf2d_start_frame(GFX_TOP, GFX_LEFT);
sftd_draw_text(font, 10, 10, RGBA8(255, 0, 0, 255), 20, "Font drawing on the top screen!");
sftd_draw_textf(font, 10, 40, RGBA8(0, 255, 0, 255), 20, "FPS %f", sf2d_get_fps());
sf2d_end_frame();
sf2d_swapbuffers();
}
sftd_free_font(font);
sftd_fini();
sf2d_fini();
return 0;
}