mirror of
https://github.com/AntonioND/nitro-engine.git
synced 2025-06-19 00:55:38 -04:00
297 lines
7.8 KiB
C
297 lines
7.8 KiB
C
// SPDX-License-Identifier: CC0-1.0
|
||
//
|
||
// SPDX-FileContributor: Antonio Niño Díaz, 2008-2024
|
||
// SPDX-FileContributor: NightFox, 2009-2011
|
||
//
|
||
// This file is part of Nitro Engine
|
||
|
||
// NightFox’s Lib (NFlib) is a library that can supports the 2D hardware of the
|
||
// NDS. It's ideal to complement Nitro Engine, as it only supports the 3D
|
||
// hardware. The latest version can be found at the following link:
|
||
//
|
||
// https://github.com/knightfox75/nds_nflib
|
||
//
|
||
// A few notes:
|
||
//
|
||
// - Remember to avoid using 3D features of NFlib.
|
||
//
|
||
// - Don't use the dual 3D mode in Nitro Engine.
|
||
//
|
||
// - You are free to use any features of NFlib in the secondary screen, but you
|
||
// need to assign VRAM C and D to NFlib to get space for sprites and
|
||
// backgrounds.
|
||
//
|
||
// - You could load 2D background and sprites in the same screen as the 3D
|
||
// rendering, but you will have to give up VRAM banks A and B. If you also use
|
||
// banks C and D for the secondary screen, it will leave you without any VRAM
|
||
// for textures.
|
||
|
||
#include <stdbool.h>
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
|
||
#include <filesystem.h>
|
||
#include <nds.h>
|
||
#include <NEMain.h>
|
||
#include <nf_lib.h>
|
||
|
||
typedef struct {
|
||
NE_Camera *Camera;
|
||
NE_Model *Model;
|
||
NE_Animation *Animation;
|
||
NE_Material *Material;
|
||
} SceneData;
|
||
|
||
void Draw3DScene(void *arg)
|
||
{
|
||
SceneData *Scene = arg;
|
||
|
||
NE_CameraUse(Scene->Camera);
|
||
|
||
NE_PolyFormat(31, 0, NE_LIGHT_0, NE_CULL_NONE, 0);
|
||
NE_ModelDraw(Scene->Model);
|
||
}
|
||
|
||
void WaitLoop(void)
|
||
{
|
||
while (1)
|
||
swiWaitForVBlank();
|
||
}
|
||
|
||
void LoadAndSetupGraphics3D(SceneData *Scene)
|
||
{
|
||
// When using nflib for the 2D sub screen engine, banks C and H are used for
|
||
// backgrounds and banks D and I are used for sprites. Nitro Engine only
|
||
// uses bank E for palettes, so the only thing we need to do is to tell
|
||
// Nitro Engine to only use banks A and B and leave C and D unused.
|
||
|
||
NE_Init3D();
|
||
NE_TextureSystemReset(0, 0, NE_VRAM_AB);
|
||
|
||
// Create objects
|
||
|
||
Scene->Model = NE_ModelCreate(NE_Animated);
|
||
Scene->Camera = NE_CameraCreate();
|
||
Scene->Material = NE_MaterialCreate();
|
||
Scene->Animation = NE_AnimationCreate();
|
||
|
||
// Load assets from the filesystem
|
||
|
||
if (NE_ModelLoadDSMFAT(Scene->Model, "robot.dsm") == 0)
|
||
{
|
||
consoleDemoInit();
|
||
printf("Couldn't load model...");
|
||
WaitLoop();
|
||
}
|
||
|
||
if (NE_AnimationLoadFAT(Scene->Animation, "robot_wave.dsa") == 0)
|
||
{
|
||
consoleDemoInit();
|
||
printf("Couldn't load animation...");
|
||
WaitLoop();
|
||
}
|
||
|
||
if (NE_MaterialTexLoadFAT(Scene->Material, NE_A1RGB5, 256, 256,
|
||
NE_TEXGEN_TEXCOORD, "texture_tex.bin") == 0)
|
||
{
|
||
consoleDemoInit();
|
||
printf("Couldn't load texture...");
|
||
WaitLoop();
|
||
}
|
||
|
||
// Assign material to the model
|
||
NE_ModelSetMaterial(Scene->Model, Scene->Material);
|
||
|
||
// Assign animation to the model and start it
|
||
NE_ModelSetAnimation(Scene->Model, Scene->Animation);
|
||
NE_ModelAnimStart(Scene->Model, NE_ANIM_LOOP, floattof32(0.1));
|
||
|
||
// Setup light
|
||
NE_LightSet(0, NE_White, 0, -1, -1);
|
||
|
||
// Setup background color
|
||
NE_ClearColorSet(NE_Black, 31, 63);
|
||
|
||
// Setup camera
|
||
NE_CameraSet(Scene->Camera,
|
||
6, 3, -4,
|
||
0, 3, 0,
|
||
0, 1, 0);
|
||
}
|
||
|
||
void LoadAndSetupGraphics2D(void)
|
||
{
|
||
// Initialize sub 2D engine
|
||
NF_Set2D(1, 0);
|
||
|
||
// Initialize sprites for sub screen (it uses VRAM D and I)
|
||
NF_InitSpriteBuffers();
|
||
NF_InitSpriteSys(1);
|
||
|
||
// Load assets from filesystem to RAM
|
||
NF_LoadSpriteGfx("sprite/personaje", 1, 64, 64);
|
||
NF_LoadSpritePal("sprite/personaje", 1);
|
||
|
||
// Copy all frames to VRAM
|
||
NF_VramSpriteGfx(1, 1, 0, false);
|
||
NF_VramSpritePal(1, 1, 0);
|
||
|
||
// Display sprite on the screen
|
||
NF_CreateSprite(1, 0, 0, 0, 0, 0);
|
||
|
||
// Initialize tiled backgrounds and text systems for the 2D sub engine (it
|
||
// uses VRAM C and H)
|
||
NF_InitTiledBgBuffers();
|
||
NF_InitTiledBgSys(1);
|
||
NF_InitTextSys(1);
|
||
|
||
// Load assets from filesystem to RAM
|
||
NF_LoadTiledBg("bg/bg3", "capa_3", 256, 256);
|
||
NF_LoadTiledBg("bg/bg1", "capa_1", 1536, 256);
|
||
NF_LoadTiledBg("bg/bg0", "capa_0", 2048, 256);
|
||
NF_LoadTextFont("fnt/default", "normal", 256, 256, 0);
|
||
|
||
// Create tiled backgrounds
|
||
NF_CreateTiledBg(1, 3, "capa_3");
|
||
NF_CreateTiledBg(1, 2, "capa_1");
|
||
NF_CreateTiledBg(1, 1, "capa_0");
|
||
|
||
// Create text layer
|
||
NF_CreateTextLayer(1, 0, 0, "normal");
|
||
}
|
||
|
||
int main(int argc, char *argv[])
|
||
{
|
||
SceneData Scene = { 0 };
|
||
|
||
// Initialize nitroFS before doing anything else
|
||
NF_Set2D(0, 0);
|
||
NF_Set2D(1, 0);
|
||
consoleDemoInit();
|
||
printf("Starting nitroFS...\n");
|
||
if (!nitroFSInit(NULL))
|
||
{
|
||
printf("Failed to start nitroFS\n");
|
||
printf("Press START to exit\n");
|
||
|
||
while (1)
|
||
{
|
||
swiWaitForVBlank();
|
||
scanKeys();
|
||
if (keysHeld() & KEY_START)
|
||
return -1;
|
||
}
|
||
}
|
||
|
||
swiWaitForVBlank();
|
||
|
||
// Set the root folder to the nitroFS filesystem
|
||
NF_SetRootFolder("NITROFS");
|
||
|
||
// Setup interrupt handlers
|
||
irqEnable(IRQ_HBLANK);
|
||
irqSet(IRQ_VBLANK, NE_VBLFunc);
|
||
irqSet(IRQ_HBLANK, NE_HBLFunc);
|
||
|
||
// Load and setup graphics
|
||
LoadAndSetupGraphics3D(&Scene);
|
||
LoadAndSetupGraphics2D();
|
||
|
||
// Initialize variables to control the sprite
|
||
int pj_x = 0;
|
||
int pj_y = 127;
|
||
unsigned int pj_frame = 0;
|
||
unsigned int pj_anim_ticks = 0;
|
||
int pj_speed = 1;
|
||
|
||
// Initialize variables to control the backgrounds
|
||
int bg_x[4] = {0, 0, 0};
|
||
|
||
// Print instructions for the user
|
||
NF_WriteText(1, 0, 1, 1, "PAD: Rotate model");
|
||
NF_WriteText(1, 0, 1, 2, "L/R: Scroll background");
|
||
NF_WriteText(1, 0, 1, 3, "START: Exit");
|
||
NF_UpdateTextLayers();
|
||
|
||
while (1)
|
||
{
|
||
NE_WaitForVBL(NE_UPDATE_ANIMATIONS);
|
||
|
||
// At this point we are in the vertical blank period. This is where 2D
|
||
// elements have to be updated to avoid flickering.
|
||
|
||
// Update the scroll of the backgrounds
|
||
for (int n = 0; n < 3; n ++)
|
||
NF_ScrollBg(1, n + 1, bg_x[n], 0);
|
||
|
||
// Copy shadow OAM copy to the OAM of the 2D sub engine
|
||
oamUpdate(&oamSub);
|
||
|
||
// Start processing a new frame after the 2D elements have been updated.
|
||
|
||
scanKeys();
|
||
uint32_t keys = keysHeld();
|
||
|
||
if (keys & KEY_START)
|
||
break;
|
||
|
||
if (keys & KEY_RIGHT)
|
||
NE_ModelRotate(Scene.Model, 0, 2, 0);
|
||
if (keys & KEY_LEFT)
|
||
NE_ModelRotate(Scene.Model, 0, -2, 0);
|
||
if (keys & KEY_UP)
|
||
NE_ModelRotate(Scene.Model, 0, 0, 2);
|
||
if (keys & KEY_DOWN)
|
||
NE_ModelRotate(Scene.Model, 0, 0, -2);
|
||
|
||
if (keys & KEY_L)
|
||
{
|
||
bg_x[0] -= 2;
|
||
if (bg_x[0] < 0)
|
||
bg_x[0] = 0;
|
||
}
|
||
|
||
if (keys & KEY_R)
|
||
{
|
||
bg_x[0] += 2;
|
||
if (bg_x[0] > 1152)
|
||
bg_x[0] = 1152;
|
||
}
|
||
|
||
// For the parallax effect, calculate the scroll of the second layer
|
||
// based on the scroll of the first one.
|
||
bg_x[1] = bg_x[0] / 2;
|
||
|
||
// Move sprite
|
||
pj_x += pj_speed;
|
||
if ((pj_x < 0) || (pj_x > 191))
|
||
{
|
||
pj_speed = -pj_speed;
|
||
if (pj_speed > 0)
|
||
NF_HflipSprite(1, 0, false);
|
||
else
|
||
NF_HflipSprite(1, 0, true);
|
||
}
|
||
NF_MoveSprite(1, 0, pj_x, pj_y);
|
||
|
||
// Animate sprite
|
||
pj_anim_ticks++;
|
||
if (pj_anim_ticks > 5)
|
||
{
|
||
pj_anim_ticks = 0;
|
||
pj_frame++;
|
||
if (pj_frame > 11)
|
||
pj_frame = 0;
|
||
NF_SpriteFrame(1, 0, pj_frame);
|
||
}
|
||
|
||
// Refresh shadow OAM copy
|
||
NF_SpriteOamSet(1);
|
||
|
||
// Draw 3D scene
|
||
NE_ProcessArg(Draw3DScene, &Scene);
|
||
}
|
||
|
||
return 0;
|
||
}
|