added old 3ds stuff
This commit is contained in:
parent
526bdc91cc
commit
61e90aef4f
13 changed files with 853 additions and 5574 deletions
|
@ -1,5 +1,12 @@
|
||||||
{
|
{
|
||||||
"posts": [
|
"posts": [
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"description": "A guide to using RomFS on the 3DS. (Old)", "date": "2025-01-01", "tags": ["3ds", "programming", "c", "devkitpro", "old"], "previous": "old3ds_helloworld.md", "next": "old3ds_touchscreen.md"
|
||||||
|
},
|
||||||
|
"id": "old3ds_romfs",
|
||||||
|
"url": "/blog/old3ds_romfs.md"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"description": "A curated list of awesome stuff I like", "date": "2024-11-26", "tags": ["awesome", "curated"]
|
"description": "A curated list of awesome stuff I like", "date": "2024-11-26", "tags": ["awesome", "curated"]
|
||||||
|
@ -16,10 +23,24 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"description": "A test post to see how the site styling looks", "date": "2024-12-31", "tags": ["meta", "web"]
|
"description": "A guide to using the touchscreen on the 3DS. (Old)", "date": "2025-01-01", "tags": ["3ds", "programming", "c", "devkitpro", "old"], "previous": "old3ds_romfs.md"
|
||||||
|
},
|
||||||
|
"id": "old3ds_touchscreen",
|
||||||
|
"url": "/blog/old3ds_touchscreen.md"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"description": "A test post to see how the site styling looks", "date": "2025-01-01", "tags": ["meta", "web"]
|
||||||
},
|
},
|
||||||
"id": "styling_test",
|
"id": "styling_test",
|
||||||
"url": "/blog/styling_test.md"
|
"url": "/blog/styling_test.md"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"description": "A guide to creating a simple Hello, World program for the 3DS. (Old)", "date": "2025-01-01", "tags": ["3ds", "programming", "c", "devkitpro", "old"], "next": "old3ds_romfs.md"
|
||||||
|
},
|
||||||
|
"id": "old3ds_helloworld",
|
||||||
|
"url": "/blog/old3ds_helloworld.md"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,17 +31,8 @@ export default function configured_markdown(): MarkdownIt {
|
||||||
"</code></pre>";
|
"</code></pre>";
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
// .use(figure, {
|
|
||||||
// mathFence: true,
|
|
||||||
// render: (content: any, displayMode: any) => {
|
|
||||||
// // render tex here and return svg
|
|
||||||
// console.log("figure render");
|
|
||||||
// console.log(content);
|
|
||||||
// return TeXToSVG(content);
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
|
|
||||||
md = md.use(tab)
|
md = md
|
||||||
.use(tasklist)
|
.use(tasklist)
|
||||||
.use(mark)
|
.use(mark)
|
||||||
.use(footnote)
|
.use(footnote)
|
||||||
|
@ -51,6 +42,8 @@ export default function configured_markdown(): MarkdownIt {
|
||||||
"important", "success", "caution", "question", "done",
|
"important", "success", "caution", "question", "done",
|
||||||
"quote", "deprecated", "example"
|
"quote", "deprecated", "example"
|
||||||
],
|
],
|
||||||
|
}).use(tab, {
|
||||||
|
name: "tabs"
|
||||||
});
|
});
|
||||||
|
|
||||||
md.renderer.rules.text = function (tokens, idx, options, env, self) {
|
md.renderer.rules.text = function (tokens, idx, options, env, self) {
|
||||||
|
|
|
@ -301,5 +301,4 @@ Hosted
|
||||||
@apply border-2 border-purple-600;
|
@apply border-2 border-purple-600;
|
||||||
box-shadow: 0 0 7px #A020F0;
|
box-shadow: 0 0 7px #A020F0;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
|
@ -1,10 +1,17 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, watch } from 'vue';
|
import { ref, watch } from 'vue';
|
||||||
import fm from 'front-matter';
|
import fm from 'front-matter';
|
||||||
|
import { auto } from '@popperjs/core';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
url: String,
|
url: String,
|
||||||
tagFilter: Array
|
tagFilter: Array,
|
||||||
|
// Allow sm, md, and lg
|
||||||
|
size: {
|
||||||
|
type: String,
|
||||||
|
default: 'full',
|
||||||
|
validator: (value) => ['xs', 'sm', 'md', 'full'].includes(value)
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const url = ref(props.url)
|
const url = ref(props.url)
|
||||||
|
@ -19,6 +26,7 @@ const description = ref(null);
|
||||||
const date = ref(null);
|
const date = ref(null);
|
||||||
const tags = ref(null);
|
const tags = ref(null);
|
||||||
|
|
||||||
|
|
||||||
// watch the params of the route to fetch the data again
|
// watch the params of the route to fetch the data again
|
||||||
watch(url, async () => {
|
watch(url, async () => {
|
||||||
await fetchData()
|
await fetchData()
|
||||||
|
@ -38,6 +46,8 @@ async function fetchData() {
|
||||||
description.value = processed.attributes.description
|
description.value = processed.attributes.description
|
||||||
date.value = processed.attributes.date
|
date.value = processed.attributes.date
|
||||||
tags.value = processed.attributes.tags
|
tags.value = processed.attributes.tags
|
||||||
|
|
||||||
|
date.value = new Date(date.value).toLocaleDateString()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
error.value = err.toString()
|
error.value = err.toString()
|
||||||
loading.value = false
|
loading.value = false
|
||||||
|
@ -49,33 +59,119 @@ async function fetchData() {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NuxtLink :href="'/blog?post=' +url">
|
<NuxtLink :href="'/blog?post=' +url">
|
||||||
<div class="m-4 min-h-30 min-width-90 text-white transition hover:bg-purple-600 bg-opacity-50 hover:bg-opacity-70">
|
<!-- Large -->
|
||||||
<Card>
|
<div v-if = "size === 'full'">
|
||||||
<div v-if="loading" class="text-center animate-pulse">
|
<div class="m-4 min-h-30 min-width-90 text-white transition hover:bg-purple-600 bg-opacity-50 hover:bg-opacity-70">
|
||||||
</div>
|
<Card>
|
||||||
<div v-else-if="error" class="text-center">
|
<div v-if="loading" class="text-center animate-pulse">
|
||||||
<h2>Error: {{ error }}</h2>
|
</div>
|
||||||
<button @click="fetchData">Retry</button>
|
<div v-else-if="error" class="text-center">
|
||||||
</div>
|
<h2>Error: {{ error }}</h2>
|
||||||
<div v-else>
|
<button @click="fetchData">Retry</button>
|
||||||
<div class="grid">
|
</div>
|
||||||
<div class="justify-center">
|
<div v-else>
|
||||||
<h1>{{ title }}</h1>
|
<div class="grid">
|
||||||
</div>
|
<div class="justify-center">
|
||||||
<div class="flex justify-center">
|
<h1>{{ title }}</h1>
|
||||||
<div v-for="tag in tags" :key="tag" class="m-1 text-center">
|
<small>{{ date }}</small>
|
||||||
<div v-if="props.tagFilter.includes(tag)">
|
</div>
|
||||||
<span class="text-xs bg-slate-700 border-white border-2 text-white p-1 rounded-md">{{ tag }}</span>
|
<div class="flex justify-center">
|
||||||
|
<div v-for="tag in tags" :key="tag" class="m-1 text-center">
|
||||||
|
<div v-if="props.tagFilter.includes(tag)">
|
||||||
|
<span class="text-xs bg-slate-700 border-white border-2 text-white p-1 rounded-md">{{ tag }}</span>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<span class="text-xs bg-black border-purple-400 border-2 text-white p-1 rounded-md">{{ tag }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<p>{{ description }}</p>
|
||||||
<span class="text-xs bg-black border-purple-400 border-2 text-white p-1 rounded-md">{{ tag }}</span>
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Medium -->
|
||||||
|
<div v-else-if = "size === 'md'">
|
||||||
|
<div class="m-4 min-h-30 min-width-50 text-white transition hover:bg-purple-600 bg-opacity-50 hover:bg-opacity-70">
|
||||||
|
<Card>
|
||||||
|
<div v-if="loading" class="text-center animate-pulse">
|
||||||
|
</div>
|
||||||
|
<div v-else-if="error" class="text-center">
|
||||||
|
<h2>Error: {{ error }}</h2>
|
||||||
|
<button @click="fetchData">Retry</button>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<div class="grid">
|
||||||
|
<div class="justify-center">
|
||||||
|
<h2>{{ title }}</h2>
|
||||||
|
<small>{{ date }}</small>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<div v-for="tag in tags" :key="tag" class="m-1 text-center">
|
||||||
|
<div v-if="props.tagFilter.includes(tag)">
|
||||||
|
<span class="text-xs bg-slate-700 border-white border-2 text-white p-1 rounded-md">{{ tag }}</span>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<div v-for="tag in tags" :key="tag" class="m-1 text-center">
|
||||||
|
<div v-if="props.tagFilter.includes(tag)">
|
||||||
|
<span class="text-xs bg-slate-700 border-white border-2 text-white p-1 rounded-md">{{ tag }}</span>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<span class="text-xs bg-black border-purple-400 border-2 text-white p-1 rounded-md">{{ tag }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span class="text-xs bg-black border-purple-400 border-2 text-white p-1 rounded-md">{{ tag }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Small -->
|
||||||
|
<div v-else-if = "size === 'sm'">
|
||||||
|
<div class="m-4 min-h-30 min-width-30 text-white transition hover:bg-purple-600 bg-opacity-50 hover:bg-opacity-70">
|
||||||
|
<Card>
|
||||||
|
<div v-if="loading" class="text-center animate-pulse">
|
||||||
|
</div>
|
||||||
|
<div v-else-if="error" class="text-center">
|
||||||
|
<h2>Error: {{ error }}</h2>
|
||||||
|
<button @click="fetchData">Retry</button>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<div class="grid">
|
||||||
|
<div class="justify-center">
|
||||||
|
<h3>{{ title }}</h3>
|
||||||
|
<small>{{ date }}</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Extra Small -->
|
||||||
|
<div v-else-if = "size === 'xs'">
|
||||||
|
<div class="m-4 min-h-30 min-width-20 text-white transition hover:bg-purple-600 bg-opacity-50 hover:bg-opacity-70">
|
||||||
|
<Card>
|
||||||
|
<div v-if="loading" class="text-center animate-pulse">
|
||||||
|
</div>
|
||||||
|
<div v-else-if="error" class="text-center">
|
||||||
|
<h3>Error: {{ error }}</h3>
|
||||||
|
<button @click="fetchData">Retry</button>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<div class="grid">
|
||||||
|
<div class="justify-center">
|
||||||
|
<h5>{{ title }}</h5>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
<p>{{ description }}</p>
|
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
|
||||||
</div>
|
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
</template>
|
</template>
|
|
@ -39,6 +39,8 @@ const title = ref(null);
|
||||||
const description = ref(null);
|
const description = ref(null);
|
||||||
const date = ref(null);
|
const date = ref(null);
|
||||||
const tags = ref(null);
|
const tags = ref(null);
|
||||||
|
const previous = ref(null);
|
||||||
|
const next = ref(null);
|
||||||
|
|
||||||
// watch the params of the route to fetch the data again
|
// watch the params of the route to fetch the data again
|
||||||
|
|
||||||
|
@ -62,8 +64,17 @@ async function fetchData(url) {
|
||||||
background.value = processed.attributes.background
|
background.value = processed.attributes.background
|
||||||
title.value = processed.attributes.title
|
title.value = processed.attributes.title
|
||||||
description.value = processed.attributes.description
|
description.value = processed.attributes.description
|
||||||
date.value = processed.attributes.date
|
date.value = processed.attributes.date.toLocaleDateString()
|
||||||
tags.value = processed.attributes.tags
|
tags.value = processed.attributes.tags
|
||||||
|
|
||||||
|
if (processed.attributes.previous)
|
||||||
|
previous.value = "/blog/?post=/blog/" + processed.attributes.previous
|
||||||
|
else
|
||||||
|
previous.value = null
|
||||||
|
if (processed.attributes.next)
|
||||||
|
next.value = "/blog/?post=/blog/" + processed.attributes.next
|
||||||
|
else
|
||||||
|
next.value = null
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
error.value = err.toString()
|
error.value = err.toString()
|
||||||
console.error(err)
|
console.error(err)
|
||||||
|
@ -111,9 +122,15 @@ async function fetchList() {
|
||||||
// Extract the tags
|
// Extract the tags
|
||||||
tagList.value = blog_list.posts.flatMap(post => post.metadata.tags).filter((tag, index, self) => self.indexOf(tag) === index)
|
tagList.value = blog_list.posts.flatMap(post => post.metadata.tags).filter((tag, index, self) => self.indexOf(tag) === index)
|
||||||
|
|
||||||
|
// Sort the posts by date, most recent first
|
||||||
|
list.value.sort((a, b) => new Date(b.metadata.date) - new Date(a.metadata.date))
|
||||||
}
|
}
|
||||||
fetchList()
|
fetchList()
|
||||||
|
|
||||||
|
function resetReadingPosition() {
|
||||||
|
window.scrollTo(0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
// Hook and check if the URL gets changed in the query params
|
// Hook and check if the URL gets changed in the query params
|
||||||
watch(url, async () => {
|
watch(url, async () => {
|
||||||
await fetchData(url.value)
|
await fetchData(url.value)
|
||||||
|
@ -150,14 +167,35 @@ watch(url, async () => {
|
||||||
<Transition name="list">
|
<Transition name="list">
|
||||||
<div class="flex flex-col" :key="url">
|
<div class="flex flex-col" :key="url">
|
||||||
<h1>{{ title }}</h1>
|
<h1>{{ title }}</h1>
|
||||||
|
<small>{{ date }}</small>
|
||||||
<div class="max-w-50 flex flex-row justify-center">
|
<div class="max-w-50 flex flex-row justify-center">
|
||||||
<div v-for="tag in tags" :key="tag" class="m-1 text-center">
|
<div v-for="tag in tags" :key="tag" class="m-1 text-center">
|
||||||
<span class="text-xs bg-black border-purple-400 border-2 text-white p-1 rounded-md">{{
|
<span class="text-xs bg-black border-purple-400 border-2 text-white p-1 rounded-md">{{
|
||||||
tag }}</span>
|
tag }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<!-- Next/Prev controls, on the left and right side using PostCards -->
|
||||||
|
<div class="flex max-w-4xl max-md:w-screen">
|
||||||
|
<div class="justify-start">
|
||||||
|
<NuxtLink v-if="previous" :onclick="resetReadingPosition" :to="previous" class="m-2 text-white">Previous</NuxtLink>
|
||||||
|
</div>
|
||||||
|
<div class="justify-end">
|
||||||
|
<NuxtLink v-if="next" :onclick="resetReadingPosition" :to="next" class="m-2 text-white">Next</NuxtLink>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<Card class="text-pretty max-w-4xl mt-4 max-md:w-screen text-left">
|
<Card class="text-pretty max-w-4xl mt-4 max-md:w-screen text-left">
|
||||||
<Markdown :text="text"></Markdown>
|
<Markdown :text="text"></Markdown>
|
||||||
|
<!-- Aligned next/prev controls -->
|
||||||
|
<div class="flex">
|
||||||
|
<div class="justify-start">
|
||||||
|
<NuxtLink v-if="previous" :onclick="resetReadingPosition" :to="previous" class="m-2 text-white">Previous</NuxtLink>
|
||||||
|
</div>
|
||||||
|
<div class="justify-end">
|
||||||
|
<NuxtLink v-if="next" :onclick="resetReadingPosition" :to="next" class="m-2 text-white">Next</NuxtLink>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
</Transition>
|
</Transition>
|
||||||
|
|
129
public/blog/old3ds_helloworld.md
Normal file
129
public/blog/old3ds_helloworld.md
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
---
|
||||||
|
title: 3DS Programming - Hello World
|
||||||
|
description: A guide to creating a simple Hello, World program for the 3DS. (Old)
|
||||||
|
date: 2025-01-01
|
||||||
|
tags: ['3ds', 'programming', 'c', 'devkitpro', 'old']
|
||||||
|
next: old3ds_romfs.md
|
||||||
|
---
|
||||||
|
|
||||||
|
# Hello, World!
|
||||||
|
|
||||||
|
> [!warning]
|
||||||
|
> This guide of mine is old - Like 3 years old at the time of posting. I prefer to keep it up, but I don't think it very highly - It should still work though.
|
||||||
|
> I might make a new one in the future.
|
||||||
|
> I'm doing some alterations at least to make it more readable.
|
||||||
|
> It doesn't teach why things are done very well is my primary issue with it.
|
||||||
|
|
||||||
|
'Hello, World!' is a very simple program used for checking a program's build system, and showing its basic syntax.
|
||||||
|
We should do both before going forward. You should have your project set up for this.
|
||||||
|
|
||||||
|
And if you are using VSCode, I would recommend you get the include paths set up.
|
||||||
|
|
||||||
|
## Begin coding
|
||||||
|
|
||||||
|
Start by including 'stdio.h' (or 'cstdio'!) and '3ds.h'.
|
||||||
|
A quick explanation of '3ds.h'
|
||||||
|
|
||||||
|
'3ds.h' is the file containing references to all the VITAL things we can use to program on the system.
|
||||||
|
|
||||||
|
It does not include many features, such as (And certainly not limited to) rendering capabilities, aside from running the console)
|
||||||
|
|
||||||
|
## Main loop
|
||||||
|
|
||||||
|
Start by setting up a main function as usual for C/C++.
|
||||||
|
|
||||||
|
To initialize the graphics, we need to run gfxInitDefault().
|
||||||
|
|
||||||
|
To initialize the console, we need to run consoleInit([SCREEN HERE], NULL).
|
||||||
|
|
||||||
|
Replace '[SCREEN HERE]' with either GFX_TOP or GFX_BOTTOM, depending on what screen you want.
|
||||||
|
|
||||||
|
At this point, the code should look something like this:
|
||||||
|
|
||||||
|
<!-- Note: I originally used images for these, but... Why did I do that? -->
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <3ds.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// Initialize the console
|
||||||
|
gfxInitDefault();
|
||||||
|
consoleInit(GFX_BOTTOM, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
As the console is now ready, you can now print to the screen. You can use puts(), printf(), std::cout, etc.
|
||||||
|
|
||||||
|
If we try and run it now, it should immediately close itself, as there is no main loop.
|
||||||
|
|
||||||
|
To create a main loop, we create a while loop with aptMainLoop() as its argument:
|
||||||
|
|
||||||
|
```c
|
||||||
|
// Initialize the console
|
||||||
|
// ...
|
||||||
|
|
||||||
|
/// Main loop
|
||||||
|
while(aptMainLoop()) {
|
||||||
|
// Code here
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This will loop infinitely until the user closes the program.
|
||||||
|
|
||||||
|
## Input
|
||||||
|
|
||||||
|
Okay, so we now have a main loop... How do we exit back to the Homebrew Launcher?
|
||||||
|
|
||||||
|
Simple. We can scan for input, and break if it detects a button, in this case START, being pressed.
|
||||||
|
|
||||||
|
We can scan for input with hidScanInput(), and get which keys are down with hidKeysDown() like so:
|
||||||
|
|
||||||
|
```c
|
||||||
|
// Main loop
|
||||||
|
while(aptMainLoop()) {
|
||||||
|
// Scan for input
|
||||||
|
hidScanInput();
|
||||||
|
u32 kDown = hidKeysDown();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Every button is mapped to a different bit on the unsigned 32-bit integer.
|
||||||
|
|
||||||
|
We can get specific keys via an AND operation between the integer and the desired key:
|
||||||
|
|
||||||
|
```c
|
||||||
|
// Main loop
|
||||||
|
while(aptMainLoop()) {
|
||||||
|
// Scan for input
|
||||||
|
hidScanInput();
|
||||||
|
u32 kDown = hidKeysDown();
|
||||||
|
|
||||||
|
// Break if START is pressed
|
||||||
|
if(kDown & KEY_START) break;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Wrapping up
|
||||||
|
|
||||||
|
We can add V-Sync with gspWaitForVBlank(), which may help if you want that and don't want to draw anything aside from the console. You can disregard this if you want:
|
||||||
|
|
||||||
|
```c
|
||||||
|
// Main loop
|
||||||
|
while(aptMainLoop()) {
|
||||||
|
// Scan for input
|
||||||
|
// ...
|
||||||
|
// Break if START is pressed
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// Wait for V-Blank
|
||||||
|
gspWaitForVBlank();
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
And we are done. You can run the program, and get the words 'Hello, World!' printed on the screen:
|
||||||
|
|
||||||
|
![Failed to load image](/files/old3ds/helloworld/dkp_progress0.png)
|
161
public/blog/old3ds_romfs.md
Normal file
161
public/blog/old3ds_romfs.md
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
---
|
||||||
|
title: 3DS Programming - Using RomFS
|
||||||
|
description: A guide to using RomFS on the 3DS. (Old)
|
||||||
|
date: 2025-01-01
|
||||||
|
tags: ['3ds', 'programming', 'c', 'devkitpro', 'old']
|
||||||
|
previous: old3ds_helloworld.md
|
||||||
|
next: old3ds_touchscreen.md
|
||||||
|
---
|
||||||
|
|
||||||
|
# Accessing ROM files with RomFS
|
||||||
|
|
||||||
|
> [!warning]
|
||||||
|
> This guide of mine is old - Like 3 years old at the time of posting. I prefer to keep it up, but I don't think it very highly - It should still work though.
|
||||||
|
> I might make a new one in the future.
|
||||||
|
> I'm doing some alterations at least to make it more readable.
|
||||||
|
> It doesn't teach why things are done very well is my primary issue with it.
|
||||||
|
|
||||||
|
RomFS allows us to access files stored on the ROM file, cartridge, or application.
|
||||||
|
|
||||||
|
It can be used to read things such as graphics assets, audio data, and other data.
|
||||||
|
|
||||||
|
## RomFS folder
|
||||||
|
|
||||||
|
You may have noticed while building that there is a folder named 'romfs' in your project:
|
||||||
|
|
||||||
|
```
|
||||||
|
- Project
|
||||||
|
- build
|
||||||
|
- **romfs**
|
||||||
|
- source
|
||||||
|
- Makefile
|
||||||
|
- Project.3dsx
|
||||||
|
```
|
||||||
|
|
||||||
|
(If it is not already present, create it now.)
|
||||||
|
|
||||||
|
This is where all the program files are stored. These files are mounted on 'romfs:/' when the app is running.
|
||||||
|
|
||||||
|
If you have any sprites, they will appear in the 'gfx' directory inside of 'romfs:/', and are accessed accordingly.
|
||||||
|
|
||||||
|
Create a text file inside of 'romfs', name it something like 'sample.txt' (or 'sample' if you have file extensions off):
|
||||||
|
|
||||||
|
```
|
||||||
|
- Project
|
||||||
|
- build
|
||||||
|
- **romfs**
|
||||||
|
- sample.txt
|
||||||
|
- source
|
||||||
|
- Makefile
|
||||||
|
- Project.3dsx
|
||||||
|
```
|
||||||
|
|
||||||
|
This file will appear as 'romfs:/sample.txt' in the program.
|
||||||
|
|
||||||
|
## Using RomFS
|
||||||
|
|
||||||
|
We will initialize RomFS, check if a file exists, and then deinitialize.
|
||||||
|
|
||||||
|
### Initializing
|
||||||
|
|
||||||
|
Initializing RomFS is trivial - It only takes one simple function to do it:
|
||||||
|
|
||||||
|
```c
|
||||||
|
// Initialize the console
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// Initialize RomFS
|
||||||
|
romfsInit();
|
||||||
|
|
||||||
|
// Main loop
|
||||||
|
// ...
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using
|
||||||
|
|
||||||
|
To access a file, we do basically the exact same thing we could do on a home computer in C or C++, just with a different drive.
|
||||||
|
|
||||||
|
We will check if the file exists, first by trying to open it, and checking if it failed to open. This is what you would normally do in C:
|
||||||
|
|
||||||
|
```c
|
||||||
|
// Check if the file exists
|
||||||
|
FILE* file = fopen("romfs:/sample.txt", "r");
|
||||||
|
|
||||||
|
if (file == NULL) {
|
||||||
|
// File does not exist
|
||||||
|
puts("File does not exist.");
|
||||||
|
} else {
|
||||||
|
// File exists
|
||||||
|
puts("File exists.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the file
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
// Main loop
|
||||||
|
```
|
||||||
|
|
||||||
|
You can play with this by adding or removing sample.txt from the 'romfs' folder.
|
||||||
|
|
||||||
|
### De-initializing
|
||||||
|
|
||||||
|
Like initializing RomFS, it only takes another simple function to de-initialize:
|
||||||
|
|
||||||
|
```c
|
||||||
|
// Main loop
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// De-initialize RomFS
|
||||||
|
romfsExit();
|
||||||
|
|
||||||
|
// Return...
|
||||||
|
```
|
||||||
|
|
||||||
|
And that is all you need to access files on the ROM.
|
||||||
|
|
||||||
|
## Wrapping up
|
||||||
|
|
||||||
|
Our code should now look like this:
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <3ds.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// Initialize the console
|
||||||
|
gfxInitDefault();
|
||||||
|
consoleInit(GFX_BOTTOM, NULL);
|
||||||
|
|
||||||
|
// Initialize RomFS
|
||||||
|
romfsInit();
|
||||||
|
|
||||||
|
// Check if the file exists
|
||||||
|
FILE* file = fopen("romfs:/sample.txt", "r");
|
||||||
|
|
||||||
|
if (file == NULL) {
|
||||||
|
// File does not exist
|
||||||
|
puts("File does not exist.");
|
||||||
|
} else {
|
||||||
|
// File exists
|
||||||
|
puts("File exists.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the file
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
// Main loop
|
||||||
|
while(aptMainLoop()) {
|
||||||
|
// Scan for input
|
||||||
|
hidScanInput();
|
||||||
|
u32 kDown = hidKeysDown();
|
||||||
|
|
||||||
|
// Close the program if START is pressed
|
||||||
|
if (kDown & KEY_START) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// De-initialize RomFS
|
||||||
|
romfsExit();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
98
public/blog/old3ds_touchscreen.md
Normal file
98
public/blog/old3ds_touchscreen.md
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
---
|
||||||
|
title: 3DS Programming - Touchscreen Input
|
||||||
|
description: A guide to using the touchscreen on the 3DS. (Old)
|
||||||
|
date: 2025-01-01
|
||||||
|
tags: ['3ds', 'programming', 'c', 'devkitpro', 'old']
|
||||||
|
previous: old3ds_romfs.md
|
||||||
|
---
|
||||||
|
|
||||||
|
# Touchscreen Input
|
||||||
|
|
||||||
|
> [!warning]
|
||||||
|
> This guide of mine is old - Like 3 years old at the time of posting. I prefer to keep it up, but I don't think it very highly - It should still work though.
|
||||||
|
> I might make a new one in the future.
|
||||||
|
> I'm doing some alterations at least to make it more readable.
|
||||||
|
> It doesn't teach why things are done very well is my primary issue with it.
|
||||||
|
|
||||||
|
Here we will find the position of a touch on the touchscreen.
|
||||||
|
|
||||||
|
It is very simple to do this.
|
||||||
|
|
||||||
|
## Getting the touch position
|
||||||
|
|
||||||
|
To find the touch position, we need to request the touchPosition type from the OS, and read from that.
|
||||||
|
|
||||||
|
We must first create a touchPosition like so:
|
||||||
|
|
||||||
|
```c
|
||||||
|
// Check for input
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// Will contain the position of the touch
|
||||||
|
touchPosition touch;
|
||||||
|
|
||||||
|
// Will obtain that information
|
||||||
|
hidTouchRead(&touch);
|
||||||
|
|
||||||
|
// Exit program if START is pressed
|
||||||
|
// ...
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, we must read from it like so:
|
||||||
|
|
||||||
|
The touch position is stored in our touchPosition as 'px' and 'py'.
|
||||||
|
|
||||||
|
## Printing the information to the screen
|
||||||
|
|
||||||
|
To print the position so we may see it, we should, instead of spamming the console with it, overwrite the X and Y position output by setting the position of the output first.
|
||||||
|
|
||||||
|
This would make it much easier to read, although we would need some whitespace after it to prevent anything getting printed without overwriting:
|
||||||
|
|
||||||
|
```c
|
||||||
|
// Print the touch screen coordinates
|
||||||
|
// Keep the whitespace if you do not want issues
|
||||||
|
printf("\x1b[1;0H X=%u Y=%u ", touch.px, touch.py);
|
||||||
|
|
||||||
|
// Exit program if START is pressed
|
||||||
|
// ...
|
||||||
|
```
|
||||||
|
|
||||||
|
The position should default to [0, 0] when no touch is found:
|
||||||
|
|
||||||
|
![Failed to load image](/files/old3ds/touchscreen/dkp_touch0.png)
|
||||||
|
|
||||||
|
## Wrapping up
|
||||||
|
|
||||||
|
Our code should now look like this:
|
||||||
|
```c
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <3ds.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// Initialize the console
|
||||||
|
gfxInitDefault();
|
||||||
|
consoleInit(GFX_BOTTOM, NULL);
|
||||||
|
|
||||||
|
// Will contain the position of the touch
|
||||||
|
// This can either be inside or outside the main loop
|
||||||
|
touchPosition touch;
|
||||||
|
|
||||||
|
while (aptMainLoop()) {
|
||||||
|
// Check for input
|
||||||
|
hidScanInput();
|
||||||
|
|
||||||
|
// Will obtain that information
|
||||||
|
hidTouchRead(&touch);
|
||||||
|
|
||||||
|
// Print the touch screen coordinates
|
||||||
|
// Keep the whitespace if you do not want issues
|
||||||
|
printf("\x1b[1;0H X=%u Y=%u ", touch.px, touch.py);
|
||||||
|
|
||||||
|
// Exit program if START is pressed
|
||||||
|
if (hidKeysDown() & KEY_START)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
title: Styling Test
|
title: Styling Test
|
||||||
description: A test post to see how the site styling looks
|
description: A test post to see how the site styling looks
|
||||||
date: 2024-12-31
|
date: 2025-01-01
|
||||||
tags: ['meta', 'web']
|
tags: ['meta', 'web']
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
BIN
public/files/old3ds/helloworld/dkp_progress0.png
Normal file
BIN
public/files/old3ds/helloworld/dkp_progress0.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
BIN
public/files/old3ds/touchscreen/dkp_touch0.png
Normal file
BIN
public/files/old3ds/touchscreen/dkp_touch0.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
|
@ -46,7 +46,9 @@ extract_front_matter() {
|
||||||
# use awk
|
# use awk
|
||||||
local front_matter=$(echo "$data" | awk '/---/ && !f {f=1; next} f; /---/ {exit}')
|
local front_matter=$(echo "$data" | awk '/---/ && !f {f=1; next} f; /---/ {exit}')
|
||||||
|
|
||||||
echo "$front_matter" | sed '1d;$d' | sed 's/^/ "/' | sed 's/: /": "/' | sed 's/$/"/' | tr '\n' ',' | sed 's/,$//' | sed 's/"tags": "\[\(.*\)\]"/"tags": \[\1\]/g' | sed "s/'/\"/g"
|
local processed=$(echo "$front_matter" | sed '1d;$d' | sed 's/^/ "/' | sed 's/: /": "/' | sed 's/$/"/' | tr '\n' ',' | sed 's/,$//' | sed 's/"tags": "\[\(.*\)\]"/"tags": \[\1\]/g' | sed "s/'/\"/g")
|
||||||
|
|
||||||
|
echo "$processed"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Find files via Regex
|
# Find files via Regex
|
||||||
|
|
Loading…
Add table
Reference in a new issue