mirror of
https://github.com/wiiu-env/ftpiiu_plugin.git
synced 2024-12-23 03:11:49 +01:00
initial commit
This commit is contained in:
commit
6d4b259324
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
build/
|
||||||
|
*.3dsx
|
||||||
|
*.smdh
|
||||||
|
*.elf
|
168
Makefile
Normal file
168
Makefile
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
.SUFFIXES:
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
CTRULIB:=/home/mtheall/workspace/ninjhax/ctrulib/libctru
|
||||||
|
|
||||||
|
ifeq ($(strip $(DEVKITARM)),)
|
||||||
|
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(strip $(CTRULIB)),)
|
||||||
|
# THIS IS TEMPORARY - in the future it should be at $(DEVKITPRO)/libctru
|
||||||
|
$(error "Please set CTRULIB in your environment. export CTRULIB=<path to>libctru")
|
||||||
|
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 := $(notdir $(CURDIR))
|
||||||
|
BUILD := build
|
||||||
|
SOURCES := source
|
||||||
|
DATA := data
|
||||||
|
INCLUDES := include
|
||||||
|
|
||||||
|
APP_TITLE := ftBRONY
|
||||||
|
APP_DESCRIPTION := Like ftPONY but magical.
|
||||||
|
APP_AUTHOR := mtheall
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# options for code generation
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=softfp
|
||||||
|
|
||||||
|
CFLAGS := -g -Wall -O3 -mword-relocations \
|
||||||
|
-fomit-frame-pointer -ffast-math \
|
||||||
|
$(ARCH) \
|
||||||
|
-DSTATUS_STRING="\"ftpd v1.0\""
|
||||||
|
|
||||||
|
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,$(TARGET).map
|
||||||
|
|
||||||
|
LIBS := -lctru
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# 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)/$(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
|
||||||
|
|
||||||
|
.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
|
||||||
|
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
|
||||||
|
DEPENDS := $(OFILES:.o=.d)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# main targets
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifeq ($(strip $(NO_SMDH)),)
|
||||||
|
.PHONY: all
|
||||||
|
all : $(OUTPUT).3dsx $(OUTPUT).smdh
|
||||||
|
endif
|
||||||
|
$(OUTPUT).3dsx: $(OUTPUT).elf
|
||||||
|
$(OUTPUT).elf: $(OFILES)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# you need a rule like this for each extension you use as binary data
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
%.bin.o: %.bin
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
@echo $(notdir $<)
|
||||||
|
@$(bin2o)
|
||||||
|
|
||||||
|
-include $(DEPENDS)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#---------------------------------------------------------------------------------------
|
BIN
data/sans.10.kerning.bin
Normal file
BIN
data/sans.10.kerning.bin
Normal file
Binary file not shown.
BIN
data/sans.10.render.bin
Normal file
BIN
data/sans.10.render.bin
Normal file
Binary file not shown.
BIN
data/sans.12.kerning.bin
Normal file
BIN
data/sans.12.kerning.bin
Normal file
Binary file not shown.
BIN
data/sans.12.render.bin
Normal file
BIN
data/sans.12.render.bin
Normal file
Binary file not shown.
BIN
data/sans.14.kerning.bin
Normal file
BIN
data/sans.14.kerning.bin
Normal file
Binary file not shown.
BIN
data/sans.14.render.bin
Normal file
BIN
data/sans.14.render.bin
Normal file
Binary file not shown.
BIN
data/sans.16.kerning.bin
Normal file
BIN
data/sans.16.kerning.bin
Normal file
Binary file not shown.
BIN
data/sans.16.render.bin
Normal file
BIN
data/sans.16.render.bin
Normal file
Binary file not shown.
BIN
data/sans.8.kerning.bin
Normal file
BIN
data/sans.8.kerning.bin
Normal file
Binary file not shown.
BIN
data/sans.8.render.bin
Normal file
BIN
data/sans.8.render.bin
Normal file
Binary file not shown.
BIN
ftbrony.png
Normal file
BIN
ftbrony.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.4 KiB |
12
include/console.h
Normal file
12
include/console.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
void console_init(void);
|
||||||
|
void console_exit(void);
|
||||||
|
|
||||||
|
__attribute__((format(printf,1,2)))
|
||||||
|
void console_set_status(const char *fmt, ...);
|
||||||
|
|
||||||
|
__attribute__((format(printf,1,2)))
|
||||||
|
void console_print(const char *fmt, ...);
|
||||||
|
|
||||||
|
void console_render(void);
|
54
include/debug.h
Normal file
54
include/debug.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#ifdef _3DS
|
||||||
|
#include <3ds.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! print debug message
|
||||||
|
*
|
||||||
|
* @param[in] fmt format string
|
||||||
|
* @param[in] ap varargs list
|
||||||
|
*
|
||||||
|
* @returns number of characters written
|
||||||
|
*/
|
||||||
|
static inline int
|
||||||
|
vdebug(const char *fmt,
|
||||||
|
va_list ap)
|
||||||
|
{
|
||||||
|
#ifdef _3DS
|
||||||
|
int rc;
|
||||||
|
char buffer[256];
|
||||||
|
|
||||||
|
memset(buffer, 0, sizeof(buffer));
|
||||||
|
|
||||||
|
/* print to buffer */
|
||||||
|
rc = vsnprintf(buffer, sizeof(buffer)-1, fmt, ap);
|
||||||
|
|
||||||
|
/* call debug service with buffer */
|
||||||
|
svcOutputDebugString(buffer, rc < sizeof(buffer) ? rc : sizeof(buffer));
|
||||||
|
return rc;
|
||||||
|
#else
|
||||||
|
/* just print to stdout */
|
||||||
|
return vprintf(fmt, ap);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((format(printf,1,2)))
|
||||||
|
/*! print debug message
|
||||||
|
*
|
||||||
|
* @param[in] fmt format string
|
||||||
|
* @param[in] ... format arguments
|
||||||
|
*
|
||||||
|
* @returns number of characters written
|
||||||
|
*/
|
||||||
|
static inline int
|
||||||
|
debug(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
rc = vdebug(fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
return rc;
|
||||||
|
}
|
5
include/ftp.h
Normal file
5
include/ftp.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
int ftp_init(void);
|
||||||
|
int ftp_loop(void);
|
||||||
|
void ftp_exit(void);
|
735
source/console.c
Normal file
735
source/console.c
Normal file
@ -0,0 +1,735 @@
|
|||||||
|
#include "console.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#ifdef _3DS
|
||||||
|
#include <3ds.h>
|
||||||
|
#endif
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
#ifdef _3DS
|
||||||
|
#include "sans_8_kerning_bin.h"
|
||||||
|
#include "sans_8_render_bin.h"
|
||||||
|
#include "sans_10_kerning_bin.h"
|
||||||
|
#include "sans_10_render_bin.h"
|
||||||
|
#include "sans_12_kerning_bin.h"
|
||||||
|
#include "sans_12_render_bin.h"
|
||||||
|
#include "sans_14_kerning_bin.h"
|
||||||
|
#include "sans_14_render_bin.h"
|
||||||
|
#include "sans_16_kerning_bin.h"
|
||||||
|
#include "sans_16_render_bin.h"
|
||||||
|
|
||||||
|
/* TODO: add support for non-ASCII characters */
|
||||||
|
|
||||||
|
/*! rendering information */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int c; /*!< character */
|
||||||
|
int y_off; /*!< vertical offset */
|
||||||
|
int width; /*!< width */
|
||||||
|
int height; /*!< height */
|
||||||
|
int x_adv; /*!< horizontal advance */
|
||||||
|
u8 data[]; /*!< width*height bitmap */
|
||||||
|
} render_info_t;
|
||||||
|
|
||||||
|
/*! kerning information */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int prev; /*!< previous character */
|
||||||
|
int next; /*!< next character */
|
||||||
|
int x_off; /*!< horizontal adjustment */
|
||||||
|
} kerning_info_t;
|
||||||
|
|
||||||
|
/*! font data */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
const char *name; /*!< font name */
|
||||||
|
render_info_t **render_info; /*!< render information list */
|
||||||
|
kerning_info_t *kerning_info; /*!< kerning information list */
|
||||||
|
size_t num_render_info; /*!< number of render information nodes */
|
||||||
|
size_t num_kerning_info; /*!< number of kerning information nodes */
|
||||||
|
int pt; /*!< font size */
|
||||||
|
} font_t;
|
||||||
|
|
||||||
|
/*! font information */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
const char *name; /*!< font name */
|
||||||
|
int pt; /*!< font size */
|
||||||
|
const u8 *render_data; /*!< render data */
|
||||||
|
const u8 *kerning_data; /*!< kerning data */
|
||||||
|
const u32 *render_data_size; /*!< render data size */
|
||||||
|
const u32 *kerning_data_size; /*!< kerning data size */
|
||||||
|
} font_info_t;
|
||||||
|
|
||||||
|
/*! font descriptors */
|
||||||
|
static font_info_t font_info[] =
|
||||||
|
{
|
||||||
|
#define FONT_INFO(name, pt) \
|
||||||
|
{ #name, pt, name##_##pt##_render_bin, name##_##pt##_kerning_bin, \
|
||||||
|
&name##_##pt##_render_bin_size, &name##_##pt##_kerning_bin_size, }
|
||||||
|
FONT_INFO(sans, 8),
|
||||||
|
FONT_INFO(sans, 10),
|
||||||
|
FONT_INFO(sans, 12),
|
||||||
|
FONT_INFO(sans, 14),
|
||||||
|
FONT_INFO(sans, 16),
|
||||||
|
};
|
||||||
|
/*! number of font descriptors */
|
||||||
|
static const size_t num_font_info = sizeof(font_info)/sizeof(font_info[0]);
|
||||||
|
|
||||||
|
/*! find next render info
|
||||||
|
*
|
||||||
|
* @param[in] info current render info
|
||||||
|
*
|
||||||
|
* @returns next render info
|
||||||
|
*/
|
||||||
|
static render_info_t*
|
||||||
|
next_render_info(render_info_t *info)
|
||||||
|
{
|
||||||
|
char *ptr = (char*)info;
|
||||||
|
ptr += sizeof(*info) + info->width*info->height;
|
||||||
|
ptr = (char*)(((int)ptr + sizeof(int)-1) & ~(sizeof(int)-1));
|
||||||
|
|
||||||
|
return (render_info_t*)ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! free font info
|
||||||
|
*
|
||||||
|
* @param[in] font
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
free_font(font_t *font)
|
||||||
|
{
|
||||||
|
free(font->render_info);
|
||||||
|
free(font);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! load font info
|
||||||
|
*
|
||||||
|
* @param[in] name
|
||||||
|
* @param[in] pt
|
||||||
|
* @param[in] render_data
|
||||||
|
* @param[in] render_data_size
|
||||||
|
* @param[in] kerning data
|
||||||
|
* @param[in] kerning_data_size
|
||||||
|
*
|
||||||
|
* @returns font info
|
||||||
|
*/
|
||||||
|
static font_t*
|
||||||
|
load_font(const char *name,
|
||||||
|
int pt,
|
||||||
|
const u8 *render_data,
|
||||||
|
size_t render_data_size,
|
||||||
|
const u8 *kerning_data,
|
||||||
|
size_t kerning_data_size)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
render_info_t *rinfo;
|
||||||
|
font_t *font;
|
||||||
|
|
||||||
|
/* allocate new font info */
|
||||||
|
font = (font_t*)calloc(1, sizeof(font_t));
|
||||||
|
if(font != NULL)
|
||||||
|
{
|
||||||
|
/* count number of render entries */
|
||||||
|
rinfo = (render_info_t*)render_data;
|
||||||
|
while((u8*)rinfo < render_data + render_data_size)
|
||||||
|
{
|
||||||
|
++font->num_render_info;
|
||||||
|
rinfo = next_render_info(rinfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate array of render info pointers */
|
||||||
|
font->render_info = (render_info_t**)calloc(font->num_render_info, sizeof(render_info_t));
|
||||||
|
if(font->render_info != NULL)
|
||||||
|
{
|
||||||
|
/* fill in the pointer list */
|
||||||
|
rinfo = (render_info_t*)render_data;
|
||||||
|
i = 0;
|
||||||
|
while((u8*)rinfo < render_data + render_data_size)
|
||||||
|
{
|
||||||
|
font->render_info[i++] = rinfo;
|
||||||
|
rinfo = next_render_info(rinfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fill in the kerning info */
|
||||||
|
font->kerning_info = (kerning_info_t*)kerning_data;
|
||||||
|
font->num_kerning_info = kerning_data_size / sizeof(kerning_info_t);
|
||||||
|
|
||||||
|
/* set font size and name */
|
||||||
|
font->pt = pt;
|
||||||
|
font->name = name;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* failed to allocate render info list */
|
||||||
|
free_font(font);
|
||||||
|
font = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! list of font info entries */
|
||||||
|
static font_t **fonts;
|
||||||
|
/*! number of font info entries */
|
||||||
|
static size_t num_fonts = 0;
|
||||||
|
|
||||||
|
/*! compare two fonts
|
||||||
|
*
|
||||||
|
* @param[in] p1 left side of comparison (font_t**)
|
||||||
|
* @param[in] p2 right side of comparison (font_t**)
|
||||||
|
*
|
||||||
|
* @returns <0 if p1 < p2
|
||||||
|
* @returns 0 if p1 == p2
|
||||||
|
* @returns >0 if p1 > p2
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
font_cmp(const void *p1,
|
||||||
|
const void *p2)
|
||||||
|
{
|
||||||
|
/* interpret parameters */
|
||||||
|
font_t *f1 = *(font_t**)p1;
|
||||||
|
font_t *f2 = *(font_t**)p2;
|
||||||
|
|
||||||
|
/* major key is font name */
|
||||||
|
int rc = strcmp(f1->name, f2->name);
|
||||||
|
if(rc != 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* minor key is font size */
|
||||||
|
if(f1->pt < f2->pt)
|
||||||
|
return -1;
|
||||||
|
if(f1->pt > f2->pt)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! search for a font by name and size
|
||||||
|
*
|
||||||
|
* @param[in] name font name
|
||||||
|
* @param[in] pt font size
|
||||||
|
*
|
||||||
|
* @returns matching font
|
||||||
|
*/
|
||||||
|
static font_t*
|
||||||
|
find_font(const char *name,
|
||||||
|
int pt)
|
||||||
|
{
|
||||||
|
/* create a key to search for */
|
||||||
|
font_t key, *keyptr;
|
||||||
|
key.name = name;
|
||||||
|
key.pt = pt;
|
||||||
|
keyptr = &key;
|
||||||
|
|
||||||
|
/* search for the key */
|
||||||
|
void *font = bsearch(&keyptr, fonts, num_fonts, sizeof(font_t*), font_cmp);
|
||||||
|
if(font == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* found it */
|
||||||
|
return *(font_t**)font;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! initialize console subsystem */
|
||||||
|
void
|
||||||
|
console_init(void)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
/* allocate font list */
|
||||||
|
fonts = (font_t**)calloc(num_font_info, sizeof(font_t*));
|
||||||
|
if(fonts == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* load fonts */
|
||||||
|
for(i = 0; i < num_font_info; ++i)
|
||||||
|
{
|
||||||
|
font_info_t *info = &font_info[i];
|
||||||
|
fonts[num_fonts] = load_font(info->name, info->pt,
|
||||||
|
info->render_data,
|
||||||
|
*info->render_data_size,
|
||||||
|
info->kerning_data,
|
||||||
|
*info->kerning_data_size);
|
||||||
|
if(fonts[num_fonts] != NULL)
|
||||||
|
++num_fonts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sort the list for bsearch later */
|
||||||
|
qsort(fonts, num_fonts, sizeof(font_t*), font_cmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! deinitialize console subsystem */
|
||||||
|
void
|
||||||
|
console_exit(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* free the font info */
|
||||||
|
for(i = 0; i < num_fonts; ++i)
|
||||||
|
free_font(fonts[i]);
|
||||||
|
|
||||||
|
/* free the font info list */
|
||||||
|
free(fonts);
|
||||||
|
fonts = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! status bar contents */
|
||||||
|
static char status[64];
|
||||||
|
/*! console buffer */
|
||||||
|
static char buffer[8192];
|
||||||
|
/*! pointer to end of buffer */
|
||||||
|
static char *buffer_end = buffer + sizeof(buffer);
|
||||||
|
/*! pointer to end of console contents */
|
||||||
|
static char *end = buffer;
|
||||||
|
|
||||||
|
/*! count lines in console contents */
|
||||||
|
static size_t
|
||||||
|
count_lines(void)
|
||||||
|
{
|
||||||
|
size_t lines = 0;
|
||||||
|
char *p = buffer;
|
||||||
|
|
||||||
|
/* search for each newline character */
|
||||||
|
while(p < end && (p = strchr(p, '\n')) != NULL)
|
||||||
|
{
|
||||||
|
++lines;
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! remove lines that have "scrolled" off screen */
|
||||||
|
static void
|
||||||
|
reduce_lines(void)
|
||||||
|
{
|
||||||
|
int lines = count_lines();
|
||||||
|
char *p = buffer;
|
||||||
|
|
||||||
|
/* we can fit 18 lines on the screen */
|
||||||
|
/* TODO make based on pt size */
|
||||||
|
while(lines > 18)
|
||||||
|
{
|
||||||
|
p = strchr(p, '\n');
|
||||||
|
++p;
|
||||||
|
--lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* move the new beginning to where it needs to be */
|
||||||
|
ptrdiff_t distance = p - buffer;
|
||||||
|
memmove(buffer, buffer+distance, end - p);
|
||||||
|
end -= distance;
|
||||||
|
*end = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! set status bar contents
|
||||||
|
*
|
||||||
|
* @param[in] fmt format string
|
||||||
|
* @param[in] ... format arguments
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
console_set_status(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
memset(status, 0, sizeof(status));
|
||||||
|
vsnprintf(status, sizeof(status)-1, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! add text to the console
|
||||||
|
*
|
||||||
|
* @param[in] fmt format string
|
||||||
|
* @param[in] ... format arguments
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
console_print(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
/* append to the end of the console buffer */
|
||||||
|
va_start(ap, fmt);
|
||||||
|
rc = vsnprintf(end, buffer_end - end - 1, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
/* null terminate buffer */
|
||||||
|
end += rc;
|
||||||
|
if(end >= buffer_end)
|
||||||
|
end = buffer_end - 1;
|
||||||
|
*end = 0;
|
||||||
|
|
||||||
|
/* scroll */
|
||||||
|
reduce_lines();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! compare render information
|
||||||
|
*
|
||||||
|
* @param[in] p1 left side of comparison (render_info_t**)
|
||||||
|
* @param[in] p2 right side of comparison (render_info_t**)
|
||||||
|
*
|
||||||
|
* @returns <0 if p1 < p2
|
||||||
|
* @returns 0 if p1 == p2
|
||||||
|
* @returns >0 if p1 > p2
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
render_info_cmp(const void *p1,
|
||||||
|
const void *p2)
|
||||||
|
{
|
||||||
|
/* interpret parameters */
|
||||||
|
render_info_t *r1 = *(render_info_t**)p1;
|
||||||
|
render_info_t *r2 = *(render_info_t**)p2;
|
||||||
|
|
||||||
|
/* ordered by character */
|
||||||
|
if(r1->c < r2->c)
|
||||||
|
return -1;
|
||||||
|
else if(r1->c > r2->c)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! search for render info by character
|
||||||
|
*
|
||||||
|
* @param[in] font font info
|
||||||
|
* @param[in] char character
|
||||||
|
*
|
||||||
|
* @returns matching render info
|
||||||
|
*/
|
||||||
|
static render_info_t*
|
||||||
|
find_render_info(font_t *font,
|
||||||
|
char c)
|
||||||
|
{
|
||||||
|
/* create a key to search for */
|
||||||
|
render_info_t key, *keyptr;
|
||||||
|
key.c = c;
|
||||||
|
keyptr = &key;
|
||||||
|
|
||||||
|
/* search for the key */
|
||||||
|
void *info = bsearch(&keyptr, font->render_info, font->num_render_info,
|
||||||
|
sizeof(render_info_t*), render_info_cmp);
|
||||||
|
if(info == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* found it */
|
||||||
|
return *(render_info_t**)info;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! compare kerning information
|
||||||
|
*
|
||||||
|
* @param[in] p1 left side of comparison (kerning_info_t*)
|
||||||
|
* @param[in] p2 right side of comparison (kerning_info_t*)
|
||||||
|
*
|
||||||
|
* @returns <0 if p1 < p2
|
||||||
|
* @returns 0 if p1 == p2
|
||||||
|
* @returns >0 if p1 > p2
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
kerning_info_cmp(const void *p1,
|
||||||
|
const void *p2)
|
||||||
|
{
|
||||||
|
/* interpret parameters */
|
||||||
|
kerning_info_t *k1 = (kerning_info_t*)p1;
|
||||||
|
kerning_info_t *k2 = (kerning_info_t*)p2;
|
||||||
|
|
||||||
|
/* major key is prev */
|
||||||
|
if(k1->prev < k2->prev)
|
||||||
|
return -1;
|
||||||
|
if(k1->prev > k2->prev)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* minor key is next */
|
||||||
|
if(k1->next < k2->next)
|
||||||
|
return -1;
|
||||||
|
if(k1->next > k2->next)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! search for kerning info by character pair
|
||||||
|
*
|
||||||
|
* @param[in] font font info
|
||||||
|
* @param[in] prev prev character
|
||||||
|
* @param[in] next next character
|
||||||
|
*
|
||||||
|
* @returns matching render info
|
||||||
|
*/
|
||||||
|
static kerning_info_t*
|
||||||
|
find_kerning_info(font_t *font,
|
||||||
|
char prev,
|
||||||
|
char next)
|
||||||
|
{
|
||||||
|
/* create a key to search for */
|
||||||
|
kerning_info_t key;
|
||||||
|
key.prev = prev;
|
||||||
|
key.next = next;
|
||||||
|
|
||||||
|
/* search for the key */
|
||||||
|
void *info = bsearch(&key, font->kerning_info, font->num_kerning_info,
|
||||||
|
sizeof(kerning_info_t), kerning_info_cmp);
|
||||||
|
if(info == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* found it */
|
||||||
|
return (kerning_info_t*)info;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! clear framebuffer
|
||||||
|
*
|
||||||
|
* @param[in] screen screen to clear
|
||||||
|
* @param[in] side which side on the stereoscopic display
|
||||||
|
* @param[in] rgbColor clear color
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
clear_screen(gfxScreen_t screen,
|
||||||
|
gfx3dSide_t side,
|
||||||
|
u8 rgbColor[3])
|
||||||
|
{
|
||||||
|
/* get the framebuffer information */
|
||||||
|
u16 fbWidth, fbHeight;
|
||||||
|
u8 *fb = gfxGetFramebuffer(screen, side, &fbWidth, &fbHeight);
|
||||||
|
|
||||||
|
/* fill the framebuffer with the clear color */
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < fbWidth*fbHeight; ++i)
|
||||||
|
{
|
||||||
|
*(fb++) = rgbColor[2];
|
||||||
|
*(fb++) = rgbColor[1];
|
||||||
|
*(fb++) = rgbColor[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! draw a quad
|
||||||
|
*
|
||||||
|
* @param[in] screen screen to draw to
|
||||||
|
* @param[in] side which side on the stereoscopic display
|
||||||
|
* @param[in] data quad data
|
||||||
|
* @param[in] x quad x position
|
||||||
|
* @param[in] y quad y position
|
||||||
|
* @param[in] w quad width
|
||||||
|
* @param[in] h quad height
|
||||||
|
*
|
||||||
|
* @note this quad data is 8-bit alpha-only
|
||||||
|
* @note uses framebuffer native coordinates
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
draw_quad(gfxScreen_t screen,
|
||||||
|
gfx3dSide_t side,
|
||||||
|
const u8 *data,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
int w,
|
||||||
|
int h)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
int index = 0;
|
||||||
|
int stride = w;
|
||||||
|
|
||||||
|
/* get the framebuffer information */
|
||||||
|
u16 width, height;
|
||||||
|
u8 *fb = gfxGetFramebuffer(screen, side, &width, &height);
|
||||||
|
|
||||||
|
/* this quad is totally offscreen; don't draw */
|
||||||
|
if(x > width || y > height)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* this quad is totally offscreen; don't draw */
|
||||||
|
if(x + w < 0 || y + h < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* adjust parameters for partially visible quad */
|
||||||
|
if(x < 0)
|
||||||
|
{
|
||||||
|
index -= x;
|
||||||
|
w += x;
|
||||||
|
x = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* adjust parameters for partially visible quad */
|
||||||
|
if(y < 0)
|
||||||
|
{
|
||||||
|
index -= y*stride;
|
||||||
|
h += y;
|
||||||
|
y = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* adjust parameters for partially visible quad */
|
||||||
|
if(x + w > width)
|
||||||
|
w = width - x;
|
||||||
|
|
||||||
|
/* adjust parameters for partially visible quad */
|
||||||
|
if(y + h > height)
|
||||||
|
h = height - y;
|
||||||
|
|
||||||
|
/* move framebuffer pointer to quad start position */
|
||||||
|
fb += (y*width + x)*3;
|
||||||
|
|
||||||
|
/* fill in data */
|
||||||
|
for(j = 0; j < h; ++j)
|
||||||
|
{
|
||||||
|
for(i = 0; i < w; ++i)
|
||||||
|
{
|
||||||
|
/* alpha blending; assuming color is white */
|
||||||
|
int v = data[index];
|
||||||
|
fb[0] = fb[0]*(0xFF-v)/0xFF + v;
|
||||||
|
fb[1] = fb[1]*(0xFF-v)/0xFF + v;
|
||||||
|
fb[2] = fb[2]*(0xFF-v)/0xFF + v;
|
||||||
|
|
||||||
|
++index;
|
||||||
|
fb += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
index += (stride-w);
|
||||||
|
fb += (width-w)*3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! draw text to framebuffer
|
||||||
|
*
|
||||||
|
* @param[in] screen screen to draw to
|
||||||
|
* @param[in] side which side on the stereoscopic display
|
||||||
|
* @param[in] font font to use when rendering
|
||||||
|
* @param[in] data quad data
|
||||||
|
* @param[in] x quad x position
|
||||||
|
* @param[in] y quad y position
|
||||||
|
*
|
||||||
|
* @note uses intuitive coordinates
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
draw_text(gfxScreen_t screen,
|
||||||
|
gfx3dSide_t side,
|
||||||
|
font_t *font,
|
||||||
|
const char *data,
|
||||||
|
int x,
|
||||||
|
int y)
|
||||||
|
{
|
||||||
|
render_info_t *rinfo;
|
||||||
|
kerning_info_t *kinfo;
|
||||||
|
const char *p;
|
||||||
|
int xoff = x, yoff = y;
|
||||||
|
char prev = 0;
|
||||||
|
|
||||||
|
/* draw each character */
|
||||||
|
for(p = data; *p != 0; ++p)
|
||||||
|
{
|
||||||
|
/* newline; move down a line and all the way left */
|
||||||
|
if(*p == '\n')
|
||||||
|
{
|
||||||
|
xoff = x;
|
||||||
|
yoff += font->pt + font->pt/2;
|
||||||
|
prev = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* look up the render info for this character */
|
||||||
|
rinfo = find_render_info(font, *p);
|
||||||
|
|
||||||
|
/* couldn't find it; just ignore it */
|
||||||
|
if(rinfo == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* find kerning data */
|
||||||
|
kinfo = NULL;
|
||||||
|
if(prev != 0)
|
||||||
|
kinfo = find_kerning_info(font, prev, *p);
|
||||||
|
|
||||||
|
/* adjust for kerning */
|
||||||
|
if(kinfo != NULL)
|
||||||
|
xoff += kinfo->x_off >> 6;
|
||||||
|
|
||||||
|
/* save this character for next kerning lookup */
|
||||||
|
prev = *p;
|
||||||
|
|
||||||
|
/* render character */
|
||||||
|
if(rinfo->width != 0 && rinfo->height != 0)
|
||||||
|
{
|
||||||
|
int x, y;
|
||||||
|
|
||||||
|
/* get framebuffer info */
|
||||||
|
u16 width, height;
|
||||||
|
gfxGetFramebuffer(screen, side, &width, &height);
|
||||||
|
|
||||||
|
/* transform intuitive coordinates to framebuffer-native */
|
||||||
|
x = width - yoff - font->pt - 2 - (rinfo->height - rinfo->y_off);
|
||||||
|
y = xoff;
|
||||||
|
|
||||||
|
/* draw character */
|
||||||
|
draw_quad(screen, side, rinfo->data, x, y,
|
||||||
|
rinfo->height, rinfo->width);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* advance to next character coordinate */
|
||||||
|
xoff += rinfo->x_adv >> 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! draw console to screen */
|
||||||
|
void
|
||||||
|
console_render(void)
|
||||||
|
{
|
||||||
|
font_t *font;
|
||||||
|
|
||||||
|
/* clear all screens */
|
||||||
|
u8 bluish[] = { 0, 0, 127 };
|
||||||
|
clear_screen(GFX_TOP, GFX_LEFT, bluish);
|
||||||
|
clear_screen(GFX_BOTTOM, GFX_LEFT, bluish);
|
||||||
|
|
||||||
|
/* look up font for status bar and draw status bar */
|
||||||
|
font = find_font("sans", 10);
|
||||||
|
if(font != NULL)
|
||||||
|
draw_text(GFX_TOP, GFX_LEFT, font, status, 4, 4);
|
||||||
|
else
|
||||||
|
debug("%s: couldn't find 'sans 10pt'\n", __func__);
|
||||||
|
|
||||||
|
/* look up font for console and draw console */
|
||||||
|
font = find_font("sans", 8);
|
||||||
|
if(font != NULL)
|
||||||
|
draw_text(GFX_TOP, GFX_LEFT, font, buffer, 4, 20);
|
||||||
|
else
|
||||||
|
debug("%s: couldn't find 'sans 8pt'\n", __func__);
|
||||||
|
|
||||||
|
/* flush framebuffer */
|
||||||
|
gfxFlushBuffers();
|
||||||
|
gspWaitForVBlank();
|
||||||
|
gfxSwapBuffers();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* this is a lot easier when you have a real console */
|
||||||
|
|
||||||
|
void
|
||||||
|
console_init(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
console_exit(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
console_set_status(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vprintf(fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
fputc('\n', stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
console_print(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vprintf(fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void console_render(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
2136
source/ftp.c
Normal file
2136
source/ftp.c
Normal file
File diff suppressed because it is too large
Load Diff
114
source/main.c
Normal file
114
source/main.c
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
#include <malloc.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#ifdef _3DS
|
||||||
|
#include <3ds.h>
|
||||||
|
#endif
|
||||||
|
#include "console.h"
|
||||||
|
#include "ftp.h"
|
||||||
|
|
||||||
|
/*! looping mechanism
|
||||||
|
*
|
||||||
|
* @param[in] callback function to call during each iteration
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
loop(int (*callback)(void))
|
||||||
|
{
|
||||||
|
#ifdef _3DS
|
||||||
|
int rc;
|
||||||
|
APP_STATUS status;
|
||||||
|
|
||||||
|
/* check apt status */
|
||||||
|
while((status = aptGetStatus()) != APP_EXITING)
|
||||||
|
{
|
||||||
|
rc = 0;
|
||||||
|
if(status == APP_RUNNING)
|
||||||
|
rc = callback();
|
||||||
|
else if(status == APP_SUSPENDING)
|
||||||
|
aptReturnToMenu();
|
||||||
|
else if(status == APP_SLEEPMODE)
|
||||||
|
aptWaitStatusEvent();
|
||||||
|
|
||||||
|
if(rc == 0)
|
||||||
|
console_render();
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
for(;;)
|
||||||
|
callback();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! wait until the B button is pressed
|
||||||
|
*
|
||||||
|
* @returns -1 if B was pressed
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
wait_for_b(void)
|
||||||
|
{
|
||||||
|
#ifdef _3DS
|
||||||
|
/* update button state */
|
||||||
|
hidScanInput();
|
||||||
|
|
||||||
|
/* check if B was pressed */
|
||||||
|
if(hidKeysDown() & KEY_B)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* B was not pressed */
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! entry point
|
||||||
|
*
|
||||||
|
* @param[in] argc unused
|
||||||
|
* @param[in] argv unused
|
||||||
|
*
|
||||||
|
* returns exit status
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
main(int argc,
|
||||||
|
char *argv[])
|
||||||
|
{
|
||||||
|
#ifdef _3DS
|
||||||
|
/* initialize needed 3DS services */
|
||||||
|
srvInit();
|
||||||
|
aptInit();
|
||||||
|
hidInit(NULL);
|
||||||
|
irrstInit(NULL);
|
||||||
|
gfxInit();
|
||||||
|
gfxSet3D(false);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* initialize console subsystem */
|
||||||
|
console_init();
|
||||||
|
console_set_status(STATUS_STRING);
|
||||||
|
|
||||||
|
/* initialize ftp subsystem */
|
||||||
|
if(ftp_init() == 0)
|
||||||
|
{
|
||||||
|
/* ftp loop */
|
||||||
|
loop(ftp_loop);
|
||||||
|
|
||||||
|
/* done with ftp */
|
||||||
|
ftp_exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
console_print("Press B to exit\n");
|
||||||
|
loop(wait_for_b);
|
||||||
|
console_exit();
|
||||||
|
|
||||||
|
#ifdef _3DS
|
||||||
|
/* deinitialize 3DS services */
|
||||||
|
gfxExit();
|
||||||
|
irrstExit();
|
||||||
|
hidExit();
|
||||||
|
aptExit();
|
||||||
|
srvExit();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user