diff --git a/CMakeLists.txt b/CMakeLists.txt index a36b832..2522d19 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,7 @@ project(Nooncraft LANGUAGES CXX) include(GenerateG3A) include(Fxconv) find_package(Gint 2.8 REQUIRED) +find_package(LibProf 2.1 REQUIRED) set(SOURCES src/block.cpp @@ -20,7 +21,7 @@ fxconv_declare_converters(converters.py) add_executable(addin ${SOURCES} ${ASSETS}) target_compile_options(addin PRIVATE -Wall -Wextra -Wno-narrowing -Os -std=c++20) -target_link_libraries(addin Gint::Gint -lsupc++) +target_link_libraries(addin LibProf::LibProf Gint::Gint -lsupc++) if("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G) message(FATAL_ERROR "This game is not supported on fx-9860G!") diff --git a/src/graphics.cpp b/src/graphics.cpp index 02ceb78..73fc02b 100644 --- a/src/graphics.cpp +++ b/src/graphics.cpp @@ -1,5 +1,19 @@ #include "graphics.h" #include "render.h" +#include + +WorldRect Camera::validCenters() const +{ + WorldRect b = this->world->worldBorder; + + /* Allow up to just next to the world border */ + return WorldRect(b.xmin + 1, b.xmax - 1, b.ymin + 1, b.ymax - 1); +} + +void Camera::moveBy(WorldCoord direction) +{ + this->center = this->validCenters().clampPoint(this->center + direction); +} namespace Nooncraft { @@ -8,11 +22,25 @@ void renderCamera(int x, int y, Camera *camera) if(!camera) return; - WorldRect r = camera->region; + WorldRect r = camera->visible; for(int dy = r.ymin; dy <= r.ymax; dy++) for(int dx = r.xmin; dx <= r.xmax; dx++) { - GlyphCluster c('@', '#', '~', '&'); - renderCluster(x+2*dx, y+2*dy, c); + int wx = camera->center.x + dx; + int wy = camera->center.y + dy; + + if(!camera->world->worldBorder.contains(WorldCoord(wx, wy))) { + continue; + } + else if(camera->world->isPointOnWorldBorder(wx, wy)) { + GlyphCluster c('{', '}', '{', '}'); + renderCluster(x+2*dx, y+2*dy, c); + } + else { + char str[5]; + sprintf(str, "%02X%02X", wx & 0xff, wy & 0xff); + GlyphCluster c(str[0], str[1], str[2], str[3]); + renderCluster(x+2*dx, y+2*dy, c); + } } } diff --git a/src/graphics.h b/src/graphics.h index e807159..9a3fecc 100644 --- a/src/graphics.h +++ b/src/graphics.h @@ -5,7 +5,7 @@ struct Camera { - Camera(World const *w): world {w}, center {0,0}, region {-1,1,-1,1} {} + Camera(World const *w): world {w}, center {0,0}, visible {-1,1,-1,1} {} /* Underlying world object */ World const *world; @@ -14,7 +14,13 @@ struct Camera WorldCoord center; /* Local rectangle around center at (0,0). This influences how much of the screen the camera will take up when rendered */ - WorldRect region; + WorldRect visible; + + /* Range of possible values for center */ + WorldRect validCenters() const; + + /* Move the camera by a fixed vector */ + void moveBy(WorldCoord direction); }; namespace Nooncraft { diff --git a/src/main.cpp b/src/main.cpp index 336bf9d..c005742 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,21 +2,13 @@ #include "world.h" #include "graphics.h" #include +#include +#include +#include #include -int main(void) +static void renderGame(Camera *camera, int frameDuration) { - World *world = Nooncraft::mkWorld(128, 128); - if(!world) - return 0; - - Nooncraft::genWorld(world); - - Camera *camera = new Camera(world); - camera->region = WorldRect(-13, 14, -6, 6); - - // - - char separator[57]; memset(separator, '-', 56); separator[56] = 0; @@ -24,30 +16,72 @@ int main(void) renderClear(); Nooncraft::renderCamera(26, 12, camera); - // HUD - GlyphCluster invLeft(' ', GLYPH_PARALLEL_TO, ' ', GLYPH_PARALLEL_TO); GlyphCluster invRight(GLYPH_PARALLEL_TO, ' ', GLYPH_PARALLEL_TO, ' '); int hudY = 27; renderText(0, hudY, separator); renderText(24, hudY+1, "COBBLESTONE"); + renderFormat(24, hudY+2, "FRAME: %d MS", frameDuration); renderCluster(0, hudY+1, invLeft); renderCluster(2, hudY+1, Nooncraft::getBlockInfo(2)->cluster); renderCluster(20, hudY+1, invRight); renderText(2, hudY+3, "1 2 3 4 5 6 7 8 9"); +} - // - +int main(void) +{ + prof_init(); - renderText(0, 0, "NOONCRAFT"); - renderUpdate(); + World *world = Nooncraft::mkWorld(128, 128); + if(!world) + return 0; - getkey(); + Nooncraft::genWorld(world); - //- + Camera *camera = new Camera(world); + camera->visible = WorldRect(-13, 14, -6, 6); + volatile int nextFrame = 1; + int t = timer_configure(TIMER_ANY, 1000000/20, GINT_CALL_SET(&nextFrame)); + timer_start(t); + + bool runMainLoop = true; + int frameDuration = 0; + + while(runMainLoop) { + while(!nextFrame) + sleep(); + nextFrame = 0; + + frameDuration = prof_exec({ + renderGame(camera, frameDuration); + renderUpdate(); + }) / 1000; + + key_event_t ev; + while((ev = pollevent()).type != KEYEV_NONE) { + if(ev.type == KEYEV_UP) + continue; + + if(ev.key == KEY_MENU) + runMainLoop = false; + } + + if(keydown(KEY_LEFT)) + camera->moveBy(WorldCoord::Left); + if(keydown(KEY_RIGHT)) + camera->moveBy(WorldCoord::Right); + if(keydown(KEY_UP)) + camera->moveBy(WorldCoord::Up); + if(keydown(KEY_DOWN)) + camera->moveBy(WorldCoord::Down); + } + + timer_stop(t); delete camera; delete world; + prof_quit(); return 1; } diff --git a/src/world.h b/src/world.h index 8c651cc..125ce82 100644 --- a/src/world.h +++ b/src/world.h @@ -4,6 +4,7 @@ #include "block.h" #include #include +#include struct WorldCoord { @@ -50,6 +51,17 @@ struct WorldRect int height() const { return ymax - ymin + 1; } + + WorldCoord clampPoint(WorldCoord p) const { + p.x = max(p.x, xmin); + p.x = min(p.x, xmax); + p.y = max(p.y, ymin); + p.y = min(p.y, ymax); + return p; + } + bool contains(WorldCoord p) const { + return xmin <= p.x && p.x <= xmax && ymin <= p.y && p.y <= ymax; + } }; struct World @@ -76,6 +88,11 @@ struct World int ix = (x + limits.xmin) + (y + limits.ymin) * limits.width(); return cells[ix]; } + + bool isPointOnWorldBorder(int16_t x, int16_t y) const { + return x == worldBorder.xmin || x == worldBorder.xmax + || y == worldBorder.ymin || y == worldBorder.ymax; + } }; namespace Nooncraft {