diff --git a/src/fixed/common.cpp b/src/fixed/common.cpp index 1b4176e9..62132797 100644 --- a/src/fixed/common.cpp +++ b/src/fixed/common.cpp @@ -1,8 +1,9 @@ #include "common.h" +#include "lang/en.h" -uint32 keys; -RectMinMax viewport; -vec3i cameraViewPos; +EWRAM_DATA uint32 keys; +EWRAM_DATA RectMinMax viewport; +vec3i gCameraViewPos; Matrix matrixStack[MAX_MATRICES]; Matrix* matrixPtr = matrixStack; @@ -10,7 +11,7 @@ EWRAM_DATA Sphere gSpheres[2][MAX_SPHERES]; const FloorData* gLastFloorData; FloorData gLastFloorSlant; -TargetInfo tinfo; +EWRAM_DATA TargetInfo tinfo; EWRAM_DATA SaveGame gSaveGame; EWRAM_DATA Settings gSettings; @@ -22,6 +23,8 @@ int32 gRandTable[MAX_RAND_TABLE]; int32 gCaustics[MAX_CAUSTICS]; int32 gCausticsFrame; +const char* const* STR = STR_EN; + EWRAM_DATA ExtraInfoLara playersExtra[MAX_PLAYERS]; #ifdef __GBA__ @@ -1246,9 +1249,9 @@ void matrixTranslateRel_c(int32 x, int32 y, int32 z) void matrixTranslateAbs_c(int32 x, int32 y, int32 z) { - x -= cameraViewPos.x; - y -= cameraViewPos.y; - z -= cameraViewPos.z; + x -= gCameraViewPos.x; + y -= gCameraViewPos.y; + z -= gCameraViewPos.z; MATRIX_TRANSLATE(x, y, z); m.e03 = tx; m.e13 = ty; @@ -1462,7 +1465,7 @@ void matrixSetView(const vec3i &pos, int32 angleX, int32 angleY) m.e22 = (cx * cy) >> FIXED_SHIFT; m.e23 = 0; - cameraViewPos = pos; + gCameraViewPos = pos; } void CollisionInfo::setSide(CollisionInfo::SideType st, int32 floor, int32 ceiling) @@ -1491,4 +1494,80 @@ void CollisionInfo::setSide(CollisionInfo::SideType st, int32 floor, int32 ceili s->slantType = slantType; s->floor = floor; s->ceiling = ceiling; -} \ No newline at end of file +} + +void palGamma(const uint16* srcPal, uint16* dstPal, int32 value) +{ + for (int32 i = 0; i < 256; i++) + { + uint16 src = *srcPal++; + int32 r = 31 & (src); + int32 g = 31 & (src >> 5); + int32 b = 31 & (src >> 10); + + r = X_MIN(31, r + (((r * r >> 2) - r) * value >> 8)); + g = X_MIN(31, g + (((g * g >> 2) - g) * value >> 8)); + b = X_MIN(31, b + (((b * b >> 2) - b) * value >> 8)); + + *dstPal++ = r | (g << 5) | (b << 10); + } +} + +void palBright(const uint16* srcPal, uint16* dstPal, int32 value) +{ + value >>= 2; + + for (int32 i = 0; i < 256; i++) + { + uint16 src = *srcPal++; + int32 r = 31 & (src); + int32 g = 31 & (src >> 5); + int32 b = 31 & (src >> 10); + + r = X_CLAMP(r + value, 0, 31); + g = X_CLAMP(g + value, 0, 31); + b = X_CLAMP(b + value, 0, 31); + + *dstPal++ = r | (g << 5) | (b << 10); + } +} + +void palGrayRemap(const uint16* palette, uint8* remap) +{ + static const uint8 grad[8] = { + 1, 22, 21, 20, 19, 18, 17, 33 + }; + + for (int32 i = 0; i < 256; i++) + { + uint16 p = *palette++; + uint8 r = (p & 31); + uint8 g = ((p >> 5) & 31); + uint8 b = ((p >> 10) & 31); + + int32 lum = (r * 77 + g * 150 + b * 29) >> (8 + 2); + + *remap++ = grad[lum]; + } +} + +void palSet(const uint16* palette, int32 gamma, int32 bright) +{ + const uint16* pal = palette; + + if (gamma || bright) + { + uint16 tmp[256]; + if (gamma) { + palGamma(pal, tmp, gamma); + pal = tmp; + } + + if (bright) { + palBright(pal, tmp, bright); + pal = tmp; + } + } + + osSetPalette(pal); +} diff --git a/src/fixed/common.h b/src/fixed/common.h index 136342ee..ce301ebb 100644 --- a/src/fixed/common.h +++ b/src/fixed/common.h @@ -178,6 +178,14 @@ X_INLINE int32 abs(int32 x) { } #endif +#if defined(__GBA__) + #define int2str(x,str) itoa(x, str, 10) +#elif defined(__3DO__) + #define int2str(x,str) sprintf(str, "%d", x) +#else + #define int2str(x,str) _itoa(x, str, 10) +#endif + #ifdef __GBA__ #define ARM_CODE __attribute__((target("arm"))) #else @@ -188,8 +196,6 @@ X_INLINE int32 abs(int32 x) { #define EWRAM_BSS #define IWRAM_CODE #define EWRAM_CODE - - #define dmaCopy(src,dst,size) memcpy(dst,src,size) #endif #if defined(_WIN32) @@ -220,7 +226,6 @@ X_INLINE int32 abs(int32 x) { extern int32 osGetSystemTimeMS(); extern void osJoyVibrate(int32 index, int32 L, int32 R); extern void osSetPalette(const uint16* palette); -extern void osSetGamma(int32 value); extern void* osLoadLevel(const char* name); #ifdef PROFILING @@ -432,11 +437,12 @@ extern int32 fps; #define NO_FLOOR -127 #define WALL (NO_FLOOR * 256) +#define ANGLE_360 0x10000 #define ANGLE_0 0 -#define ANGLE_1 (0x10000 / 360) -#define ANGLE_45 (0x10000 / 8) // != 45 * ANGLE_1 !!! -#define ANGLE_90 (0x10000 / 4) // != 90 * ANGLE_1 !!! -#define ANGLE_180 -(0x10000 / 2) // INT16_MIN +#define ANGLE_1 (ANGLE_360 / 360) +#define ANGLE_45 (ANGLE_360 / 8) // != 45 * ANGLE_1 !!! +#define ANGLE_90 (ANGLE_360 / 4) // != 90 * ANGLE_1 !!! +#define ANGLE_180 -(ANGLE_360 / 2) // INT16_MIN #define ANGLE(x) ((x) * ANGLE_1) #define ANGLE_SHIFT_45 13 #define ANGLE_SHIFT_90 14 @@ -491,7 +497,7 @@ enum InputKey { }; // action keys (ItemObj::input) -enum { +enum InputState { IN_LEFT = (1 << 1), IN_RIGHT = (1 << 2), IN_UP = (1 << 3), @@ -500,7 +506,9 @@ enum { IN_WALK = (1 << 6), IN_ACTION = (1 << 7), IN_WEAPON = (1 << 8), - IN_LOOK = (1 << 9) + IN_LOOK = (1 << 9), + IN_START = (1 << 10), + IN_SELECT = (1 << 11) }; struct vec3s { @@ -1472,6 +1480,10 @@ struct ExtraInfoLara Nav nav; + vec3i tmpPos; + + uint16 lastInput; + int8 healthTimer; bool dozy; }; @@ -2049,73 +2061,267 @@ struct IMA_STATE } #endif -enum StringID -{ - STR_EMPTY, - STR_PASSPORT, - STR_COMPASS, - STR_HOME, - STR_MAP, - STR_DETAIL, - STR_SOUND, - STR_CONTROLS, - STR_GAMMA, - STR_PISTOLS, - STR_SHOTGUN, - STR_MAGNUMS, - STR_UZIS, - STR_AMMO_PISTOLS, - STR_AMMO_SHOTGUN, - STR_AMMO_MAGNUMS, - STR_AMMO_UZIS, - STR_EXPLOSIVE, - STR_MEDIKIT_SMALL, - STR_MEDIKIT_BIG, - STR_PUZZLE, - STR_PUZZLE_GOLD_IDOL, - STR_PUZZLE_GOLD_BAR, - STR_PUZZLE_COG, - STR_PUZZLE_FUSE, - STR_PUZZLE_ANKH, - STR_PUZZLE_HORUS, - STR_PUZZLE_ANUBIS, - STR_PUZZLE_SCARAB, - STR_PUZZLE_PYRAMID, - STR_LEADBAR, - STR_KEY, - STR_KEY_SILVER, - STR_KEY_RUSTY, - STR_KEY_GOLD, - STR_KEY_SAPPHIRE, - STR_KEY_NEPTUNE, - STR_KEY_ATLAS, - STR_KEY_DAMOCLES, - STR_KEY_THOR, - STR_KEY_ORNATE, - STR_SCION, +#define STR_LANGUAGES \ + "English" \ + , "Fran|cais" \ + , "Deutsch" + +#define STR_SCALE "25", "50", "75", "100" + +enum StringID { + STR_EMPTY +// common + , STR_LOADING + , STR_LEVEL_STATS + , STR_HINT_SAVING + , STR_HINT_SAVING_DONE + , STR_HINT_SAVING_ERROR + , STR_YES + , STR_NO + , STR_OFF + , STR_ON + , STR_NO_STEREO + , STR_SBS + , STR_ANAGLYPH + , STR_SPLIT + , STR_VR + , STR_QUALITY_LOW + , STR_QUALITY_MEDIUM + , STR_QUALITY_HIGH + , STR_LANG_EN + , STR_LANG_FR + , STR_LANG_DE +// , STR_LANG_ES +// , STR_LANG_IT +// , STR_LANG_PL +// , STR_LANG_PT +// , STR_LANG_RU +// , STR_LANG_JA +// , STR_LANG_GR +// , STR_LANG_FI +// , STR_LANG_CZ +// , STR_LANG_CN +// , STR_LANG_HU +// , STR_LANG_SV + , STR_APPLY + , STR_GAMEPAD_1 + , STR_GAMEPAD_2 + , STR_GAMEPAD_3 + , STR_GAMEPAD_4 + , STR_NOT_READY + , STR_PLAYER_1 + , STR_PLAYER_2 + , STR_PRESS_ANY_KEY + , STR_HELP_SELECT + , STR_HELP_BACK +// inventory pages + , STR_INV_TITLE_OPTIONS + , STR_INV_TITLE_MAIN + , STR_INV_TITLE_KEYS +// save game page + , STR_SAVEGAME + , STR_CURRENT_POSITION +// inventory option + , STR_GAME + , STR_MAP + , STR_COMPASS + , STR_STOPWATCH + , STR_HOME + , STR_DETAIL + , STR_SOUND + , STR_CONTROLS + , STR_GAMMA +// passport menu + , STR_LOAD_GAME + , STR_START_GAME + , STR_RESTART_LEVEL + , STR_EXIT_TO_TITLE + , STR_EXIT_GAME + , STR_SELECT_LEVEL +// detail options + , STR_SELECT_DETAIL + , STR_OPT_DETAIL_FILTER + , STR_OPT_DETAIL_LIGHTING + , STR_OPT_DETAIL_SHADOWS + , STR_OPT_DETAIL_WATER + , STR_OPT_DETAIL_VSYNC + , STR_OPT_DETAIL_STEREO + , STR_OPT_SIMPLE_ITEMS + , STR_OPT_RESOLUTION + , STR_SCALE_25 + , STR_SCALE_50 + , STR_SCALE_75 + , STR_SCALE_100 +// sound options + , STR_SET_VOLUMES + , STR_REVERBERATION + , STR_OPT_SUBTITLES + , STR_OPT_LANGUAGE +// controls options + , STR_SET_CONTROLS + , STR_OPT_CONTROLS_KEYBOARD + , STR_OPT_CONTROLS_GAMEPAD + , STR_OPT_CONTROLS_VIBRATION + , STR_OPT_CONTROLS_RETARGET + , STR_OPT_CONTROLS_MULTIAIM +/* + // controls + , STR_CTRL_FIRST + , STR_CTRL_LAST = STR_CTRL_FIRST + cMAX - 1 + // keys + , STR_KEY_FIRST + , STR_KEY_LAST = STR_KEY_FIRST + ikBack + // gamepad + , STR_JOY_FIRST + , STR_JOY_LAST = STR_JOY_FIRST + jkMAX - 1 +*/ +// inventory items + , STR_UNKNOWN + , STR_EXPLOSIVE + , STR_PISTOLS + , STR_SHOTGUN + , STR_MAGNUMS + , STR_UZIS + , STR_AMMO_PISTOLS + , STR_AMMO_SHOTGUN + , STR_AMMO_MAGNUMS + , STR_AMMO_UZIS + , STR_MEDI_SMALL + , STR_MEDI_BIG + , STR_LEAD_BAR + , STR_SCION +// keys + , STR_KEY + , STR_KEY_SILVER + , STR_KEY_RUSTY + , STR_KEY_GOLD + , STR_KEY_SAPPHIRE + , STR_KEY_NEPTUNE + , STR_KEY_ATLAS + , STR_KEY_DAMOCLES + , STR_KEY_THOR + , STR_KEY_ORNATE +// puzzles + , STR_PUZZLE + , STR_PUZZLE_GOLD_IDOL + , STR_PUZZLE_GOLD_BAR + , STR_PUZZLE_COG + , STR_PUZZLE_FUSE + , STR_PUZZLE_ANKH + , STR_PUZZLE_HORUS + , STR_PUZZLE_ANUBIS + , STR_PUZZLE_SCARAB + , STR_PUZZLE_PYRAMID +#ifdef USE_SUBTITLES +// TR1 subtitles + , STR_TR1_SUB_CAFE + , STR_TR1_SUB_LIFT + , STR_TR1_SUB_CANYON + , STR_TR1_SUB_PRISON + , STR_TR1_SUB_22 // CUT4 + , STR_TR1_SUB_23 // CUT1 + , STR_TR1_SUB_24 + , STR_TR1_SUB_25 // CUT3 + , STR_TR1_SUB_26 + , STR_TR1_SUB_27 + , STR_TR1_SUB_28 + , STR_TR1_SUB_29 + , STR_TR1_SUB_30 + , STR_TR1_SUB_31 + , STR_TR1_SUB_32 + , STR_TR1_SUB_33 + , STR_TR1_SUB_34 + , STR_TR1_SUB_35 + , STR_TR1_SUB_36 + , STR_TR1_SUB_37 + , STR_TR1_SUB_38 + , STR_TR1_SUB_39 + , STR_TR1_SUB_40 + , STR_TR1_SUB_41 + , STR_TR1_SUB_42 + , STR_TR1_SUB_43 + , STR_TR1_SUB_44 + , STR_TR1_SUB_45 + , STR_TR1_SUB_46 + , STR_TR1_SUB_47 + , STR_TR1_SUB_48 + , STR_TR1_SUB_49 + , STR_TR1_SUB_50 + , STR_TR1_SUB_51 + , STR_TR1_SUB_52 + , STR_TR1_SUB_53 + , STR_TR1_SUB_54 + , STR_TR1_SUB_55 + , STR_TR1_SUB_56 +#endif // TR1 levels - STR_TR1_GYM, - STR_TR1_LEVEL1, - STR_TR1_LEVEL2, - STR_TR1_LEVEL3A, - STR_TR1_LEVEL3B, - STR_TR1_LEVEL4, - STR_TR1_LEVEL5, - STR_TR1_LEVEL6, - STR_TR1_LEVEL7A, - STR_TR1_LEVEL7B, - STR_TR1_LEVEL8A, - STR_TR1_LEVEL8B, - STR_TR1_LEVEL8C, - STR_TR1_LEVEL10A, - STR_TR1_LEVEL10B, - STR_TR1_LEVEL10C, - STR_TR1_EGYPT, - STR_TR1_CAT, - STR_TR1_END, - STR_TR1_END2, - STR_MAX -}; + , STR_TR1_GYM + , STR_TR1_LEVEL1 + , STR_TR1_LEVEL2 + , STR_TR1_LEVEL3A + , STR_TR1_LEVEL3B + , STR_TR1_LEVEL4 + , STR_TR1_LEVEL5 + , STR_TR1_LEVEL6 + , STR_TR1_LEVEL7A + , STR_TR1_LEVEL7B + , STR_TR1_LEVEL8A + , STR_TR1_LEVEL8B + , STR_TR1_LEVEL8C + , STR_TR1_LEVEL10A + , STR_TR1_LEVEL10B + , STR_TR1_LEVEL10C + , STR_TR1_EGYPT + , STR_TR1_CAT + , STR_TR1_END + , STR_TR1_END2 +// TR2 levels + , STR_TR2_ASSAULT + , STR_TR2_WALL + , STR_TR2_BOAT + , STR_TR2_VENICE + , STR_TR2_OPERA + , STR_TR2_RIG + , STR_TR2_PLATFORM + , STR_TR2_UNWATER + , STR_TR2_KEEL + , STR_TR2_LIVING + , STR_TR2_DECK + , STR_TR2_SKIDOO + , STR_TR2_MONASTRY + , STR_TR2_CATACOMB + , STR_TR2_ICECAVE + , STR_TR2_EMPRTOMB + , STR_TR2_FLOATING + , STR_TR2_XIAN + , STR_TR2_HOUSE +// TR3 levels + , STR_TR3_HOUSE + , STR_TR3_JUNGLE + , STR_TR3_TEMPLE + , STR_TR3_QUADCHAS + , STR_TR3_TONYBOSS + , STR_TR3_SHORE + , STR_TR3_CRASH + , STR_TR3_RAPIDS + , STR_TR3_TRIBOSS + , STR_TR3_ROOFS + , STR_TR3_SEWER + , STR_TR3_TOWER + , STR_TR3_OFFICE + , STR_TR3_NEVADA + , STR_TR3_COMPOUND + , STR_TR3_AREA51 + , STR_TR3_ANTARC + , STR_TR3_MINES + , STR_TR3_CITY + , STR_TR3_CHAMBER + , STR_TR3_STPAUL + + , STR_MAX +}; + +extern const char* const* STR; enum TrackID { @@ -2175,10 +2381,22 @@ enum LevelID extern const LevelInfo gLevelInfo[LVL_MAX]; extern LevelID gLevelID; +enum BarType { + BAR_HEALTH, + BAR_OXYGEN, + BAR_DASH +}; + +enum TextAlign { + TEXT_ALIGN_LEFT, + TEXT_ALIGN_RIGHT, + TEXT_ALIGN_CENTER +}; + // renderer internal extern uint32 keys; extern RectMinMax viewport; -extern vec3i cameraViewPos; +extern vec3i gCameraViewPos; extern Matrix* matrixPtr; extern Matrix matrixStack[MAX_MATRICES]; extern const uint32 gSinCosTable[4096]; @@ -2192,7 +2410,7 @@ extern SaveGame gSaveGame; extern Settings gSettings; extern int32 gCurTrack; extern int32 gAnimTexFrame; - +extern int32 gBrightness; extern int32 gLightAmbient; extern int32 gRandTable[MAX_RAND_TABLE]; extern int32 gCaustics[MAX_CAUSTICS]; @@ -2356,8 +2574,6 @@ void matrixFrame(const void* pos, const void* angles); void matrixFrameLerp(const void* pos, const void* anglesA, const void* anglesB, int32 delta, int32 rate); void matrixSetView(const vec3i &pos, int32 angleX, int32 angleY); -void drawGlyph(const Sprite *sprite, int32 x, int32 y); - void renderInit(); void setViewport(const RectMinMax &vp); void setPaletteIndex(int32 index); @@ -2367,13 +2583,22 @@ void renderMesh(const Mesh* mesh); void renderShadow(int32 x, int32 z, int32 sx, int32 sz); void renderSprite(int32 vx, int32 vy, int32 vz, int32 vg, int32 index); void renderGlyph(int32 vx, int32 vy, int32 index); +void renderBar(int32 x, int32 y, int32 value, BarType type); void flush(); +void renderBackground(void* background); +void* copyBackground(); void drawInit(); void drawFree(); +void drawText(int32 x, int32 y, const char* text, TextAlign align); void drawModel(const ItemObj* item); void drawItem(const ItemObj* item); void drawRooms(Camera* camera); +void drawHUD(Lara* lara); +void drawNodesLerp(const ItemObj* item, const AnimFrame* frameA, const AnimFrame* frameB, int32 frameDelta, int32 frameRate); + +void calcLightingDynamic(const Room* room, const vec3i &point); +void calcLightingStatic(int32 intensity); void checkTrigger(const FloorData* fd, ItemObj* lara); void readLevel(const uint8 *data); @@ -2400,7 +2625,10 @@ void sndStopTrack(); void sndStopSample(int32 index); void sndStop(); -X_INLINE void dmaFill(void *dst, uint8 value, uint32 count) +void palGrayRemap(const uint16* palette, uint8* remap); +void palSet(const uint16* palette, int32 gamma, int32 bright); + +X_INLINE void dmaFill(void* dst, uint8 value, uint32 count) { ASSERT((count & 3) == 0); #ifdef __GBA__ @@ -2411,4 +2639,14 @@ X_INLINE void dmaFill(void *dst, uint8 value, uint32 count) #endif } +X_INLINE void dmaCopy(const void* src, void* dst, uint32 size) +{ + ASSERT((size & 3) == 0); +#ifdef __GBA__ + dma3_cpy(dst, src, size); +#else + memcpy(dst, src, size); +#endif +} + #endif diff --git a/src/fixed/draw.h b/src/fixed/draw.h index 9dc666fa..bbc73f0f 100644 --- a/src/fixed/draw.h +++ b/src/fixed/draw.h @@ -82,25 +82,6 @@ void calcLightingStatic(int32 intensity) } } -void drawNumber(int32 number, int32 x, int32 y) -{ -#ifdef __3DO__ - return; -#endif - static const int32 widths[] = { - 12, 8, 10, 10, 10, 10, 10, 10, 10, 10 - }; - - const Sprite* glyphSprites = level.sprites + level.models[ITEM_GLYPHS].start; - - while (number > 0) - { - x -= widths[number % 10]; - drawGlyph(glyphSprites + 52 + (number % 10), x, y); - number /= 10; - } -} - const static uint8 char_width[110] = { 14, 11, 11, 11, 11, 11, 11, 13, 8, 11, 12, 11, 13, 13, 12, 11, 12, 12, 11, 12, 13, 13, 13, 12, 12, 11, // A-Z 9, 9, 9, 9, 9, 9, 9, 9, 5, 9, 9, 5, 12, 10, 9, 9, 9, 8, 9, 8, 9, 9, 11, 9, 9, 9, // a-z @@ -136,24 +117,25 @@ int32 getTextWidth(const char* text) w += 6; continue; } - w += char_width[charRemap(c)]; + w += char_width[charRemap(c)] + 1; } return w; } -enum TextAlign { - TEXT_ALIGN_LEFT, - TEXT_ALIGN_RIGHT, - TEXT_ALIGN_CENTER -}; - void drawText(int32 x, int32 y, const char* text, TextAlign align) { + if (!text || !*text) + return; + if (align == TEXT_ALIGN_CENTER) { x += (FRAME_WIDTH - getTextWidth(text)) >> 1; } + if (align == TEXT_ALIGN_RIGHT) { + x += FRAME_WIDTH - getTextWidth(text); + } + char c; while ((c = *text++)) { @@ -163,7 +145,7 @@ void drawText(int32 x, int32 y, const char* text, TextAlign align) } int32 index = charRemap(c); renderGlyph(x, y, level.models[ITEM_GLYPHS].start + index); - x += char_width[index]; + x += char_width[index] + 1; } } @@ -637,7 +619,7 @@ void drawItem(const ItemObj* item) } } -void drawRoom(const Room* room, Camera* camera) +void drawRoom(const Room* room) { setViewport(room->clip); @@ -663,9 +645,9 @@ void drawRoom(const Room* room, Camera* camera) renderSprite(sprite->pos.x + rx, sprite->pos.y, sprite->pos.z + rz, sprite->g << 5, sprite->index); } - rx -= cameraViewPos.x; - ry = -cameraViewPos.y; - rz -= cameraViewPos.z; + rx -= gCameraViewPos.x; + ry = -gCameraViewPos.y; + rz -= gCameraViewPos.z; for (int32 i = 0; i < info->meshesCount; i++) { @@ -756,7 +738,7 @@ void drawRooms(Camera* camera) while (*visRoom) { Room* room = *visRoom++; - drawRoom(room, camera); + drawRoom(room); room->reset(); } @@ -778,4 +760,23 @@ void drawRooms(Camera* camera) setViewport(camera->view.room->clip); } +void drawHUD(Lara* lara) +{ + int32 x = (FRAME_WIDTH - (100 + 2 + 2)) - 4; + int32 y = 4; + + if (lara->waterState == WATER_STATE_SURFACE || lara->waterState == WATER_STATE_UNDER) + { + int32 v = (lara->oxygen << 8) / LARA_MAX_OXYGEN; + renderBar(x, y, v, BAR_OXYGEN); + y += 10; + } + + if (lara->extraL->healthTimer || lara->extraL->weaponState == WEAPON_STATE_READY) + { + int32 v = (lara->health << 8) / LARA_MAX_HEALTH; + renderBar(x, y, v, BAR_HEALTH); + } +} + #endif diff --git a/src/fixed/enemy.h b/src/fixed/enemy.h index d5b09ccd..fe960f42 100644 --- a/src/fixed/enemy.h +++ b/src/fixed/enemy.h @@ -583,7 +583,7 @@ struct Enemy : ItemObj if (health > 0) { if (soundId) { - soundPlay(soundId, pos); + soundPlay(soundId, &pos); } } else { gSaveGame.kills++; diff --git a/src/fixed/game.h b/src/fixed/game.h index 9b17d33a..367301f4 100644 --- a/src/fixed/game.h +++ b/src/fixed/game.h @@ -179,38 +179,33 @@ struct Game sndPlayTrack(getAmbientTrack()); } - for (int32 i = 0; i < frames; i++) + if (inventory.state != INV_STATE_NONE) { - updateItems(); + Lara* lara = (Lara*)inventory.lara; + ASSERT(lara); + lara->updateInput(); + inventory.update(frames); } - updateLevel(frames); - } - - void render() - { - #define TEXT_POSX FRAME_WIDTH - + if (inventory.state == INV_STATE_NONE) { - PROFILE(CNT_RENDER); - - setViewport(RectMinMax(0, 0, FRAME_WIDTH, FRAME_HEIGHT)); - - clear(); - - for (int32 i = 0; i < MAX_PLAYERS; i++) + for (int32 i = 0; i < frames; i++) { - // TODO set viewports for coop - #ifndef PROFILE_SOUNDTIME - drawRooms(&players[i]->extraL->camera); - #endif + updateItems(); } + updateLevel(frames); + } + } - drawText(0, FRAME_HEIGHT - 8, "! early alpha version !", TEXT_ALIGN_CENTER); - flush(); + void showDebugInfo() + { + if (inventory.state != INV_STATE_NONE) + return; - drawNumber(fps, TEXT_POSX, 16); - } + char buf[32]; + int2str(fps, buf); + drawText(2, 16, buf, TEXT_ALIGN_LEFT); + //drawText(0, FRAME_HEIGHT - 8, "! early alpha version !", TEXT_ALIGN_CENTER); #ifdef PROFILING for (int32 i = 0; i < CNT_MAX; i++) @@ -219,10 +214,40 @@ struct Game extern void drawInt(int32 x, int32 y, int32 c); drawInt(FRAME_WIDTH - 8, 4 + 24 + 8 + 8 * i, gCounters[i]); #else - drawNumber(gCounters[i], TEXT_POSX, 32 + i * 16); + int2str(gCounters[i], buf); + drawText(2, 16 + 32 + i * 16, buf, TEXT_ALIGN_LEFT); #endif } #endif + } + + void render() + { + { + PROFILE(CNT_RENDER); + + setViewport(RectMinMax(0, 0, FRAME_WIDTH, FRAME_HEIGHT)); + + if (inventory.state == INV_STATE_NONE) + { + clear(); + + for (int32 i = 0; i < MAX_PLAYERS; i++) + { + // TODO set viewports for coop + #ifndef PROFILE_SOUNDTIME + drawRooms(&players[i]->extraL->camera); + #endif + drawHUD(players[i]); + } + } else { + inventory.draw(); + } + + showDebugInfo(); + + flush(); + } #ifndef PROFILE_SOUNDTIME PROFILE_CLEAR(); diff --git a/src/fixed/inventory.h b/src/fixed/inventory.h index c5f607df..5ed9b334 100644 --- a/src/fixed/inventory.h +++ b/src/fixed/inventory.h @@ -3,146 +3,98 @@ #include "common.h" -const char* InvNames[STR_MAX] = { - "", - "Game", - "Compass", - "Lara's Home", - "Map", - "Detail Levels", - "Sound", - "Controls", - "Gamma", - "Pistols", - "Shotgun", - "Magnums", - "Uzis", - "Pistol Clips", - "Shotgun Shells", - "Magnum Clips", - "Uzi Clips", - "Explosive", - "Small Medi Pack", - "Large Medi Pack", - "Puzzle", - "Gold Idol", - "Gold Bar", - "Machine Cog", - "Fuse", - "Ankh", - "Eye of Horus", - "Seal of Anubis", - "Scarab", - "Pyramid Key", - "Lead Bar", - "Key", - "Silver Key", - "Rusty Key", - "Gold Key", - "Sapphire Key", - "Neptune Key", - "Atlas Key", - "Damocles Key", - "Thor Key", - "Ornate Key", - "Scion", -// TR1 levels - "Lara's Home", - "Caves", - "City of Vilcabamba", - "Lost Valley", - "Tomb of Qualopec", - "St. Francis' Folly", - "Colosseum", - "Palace Midas", - "The Cistern", - "Tomb of Tihocan", - "City of Khamoon", - "Obelisk of Khamoon", - "Sanctuary of the Scion", - "Natla's Mines", - "Atlantis", - "The Great Pyramid", - "Return to Egypt", - "Temple of the Cat", - "Atlantean Stronghold", - "The Hive" +#define INV_CAMERA_HEIGHT -1536 +#define INV_CAMERA_Y 96 +#define INV_CAMERA_Z 768 +#define INV_RING_RADIUS 688 + +enum InvState { + INV_STATE_NONE, + INV_STATE_OPENING, + INV_STATE_READY, + INV_STATE_CLOSING, + INV_STATE_SPIN, + INV_STATE_PAGE_MAIN, + INV_STATE_PAGE_KEYS, + INV_STATE_PAGE_OPTIONS +}; + +enum InvPage { + INV_PAGE_TITLE, + INV_PAGE_SAVE, + INV_PAGE_DEATH, + INV_PAGE_MAIN, + INV_PAGE_KEYS, + INV_PAGE_OPTIONS }; enum InvSlot { // Items - SLOT_LEADBAR - , SLOT_KEY_ITEM_1 - , SLOT_KEY_ITEM_2 - , SLOT_KEY_ITEM_3 - , SLOT_KEY_ITEM_4 - , SLOT_PUZZLE_4 - , SLOT_PUZZLE_3 - , SLOT_PUZZLE_2 - , SLOT_PUZZLE_1 - , SLOT_SCION + SLOT_LEADBAR, + SLOT_KEY_ITEM_1, + SLOT_KEY_ITEM_2, + SLOT_KEY_ITEM_3, + SLOT_KEY_ITEM_4, + SLOT_PUZZLE_4, + SLOT_PUZZLE_3, + SLOT_PUZZLE_2, + SLOT_PUZZLE_1, + SLOT_SCION, // Inventory - , SLOT_COMPASS - , SLOT_MAP - , SLOT_PISTOLS - , SLOT_AMMO_PISTOLS - , SLOT_SHOTGUN - , SLOT_AMMO_SHOTGUN - , SLOT_MAGNUMS - , SLOT_AMMO_MAGNUMS - , SLOT_UZIS - , SLOT_AMMO_UZIS - , SLOT_EXPLOSIVE - , SLOT_MEDIKIT_BIG - , SLOT_MEDIKIT_SMALL + SLOT_COMPASS, + SLOT_PISTOLS, + SLOT_AMMO_PISTOLS, + SLOT_SHOTGUN, + SLOT_AMMO_SHOTGUN, + SLOT_MAGNUMS, + SLOT_AMMO_MAGNUMS, + SLOT_UZIS, + SLOT_AMMO_UZIS, + SLOT_MEDIKIT_BIG, + SLOT_MEDIKIT_SMALL, // Options - , SLOT_PASSPORT - , SLOT_DETAIL - , SLOT_SOUND - , SLOT_CONTROLS - , SLOT_GAMMA - , SLOT_HOME - , SLOT_MAX + SLOT_PASSPORT, + SLOT_DETAIL, + SLOT_SOUND, + SLOT_CONTROLS, + SLOT_HOME, + SLOT_MAX, }; - struct InvItem { uint8 type; - uint8 sid; + StringID str; // TODO params }; const InvItem INV_SLOTS[SLOT_MAX] = { - { ITEM_INV_LEADBAR , STR_LEADBAR } - , { ITEM_INV_KEY_ITEM_1 , STR_KEY } - , { ITEM_INV_KEY_ITEM_2 , STR_KEY } - , { ITEM_INV_KEY_ITEM_3 , STR_KEY } - , { ITEM_INV_KEY_ITEM_4 , STR_KEY } - , { ITEM_INV_PUZZLE_4 , STR_PUZZLE } - , { ITEM_INV_PUZZLE_3 , STR_PUZZLE } - , { ITEM_INV_PUZZLE_2 , STR_PUZZLE } - , { ITEM_INV_PUZZLE_1 , STR_PUZZLE } - , { ITEM_INV_SCION , STR_SCION } - , { ITEM_INV_COMPASS , STR_COMPASS } - , { ITEM_INV_MAP , STR_MAP } - , { ITEM_INV_PISTOLS , STR_PISTOLS } - , { ITEM_INV_AMMO_PISTOLS , STR_AMMO_PISTOLS } - , { ITEM_INV_SHOTGUN , STR_SHOTGUN } - , { ITEM_INV_AMMO_SHOTGUN , STR_AMMO_SHOTGUN } - , { ITEM_INV_MAGNUMS , STR_MAGNUMS } - , { ITEM_INV_AMMO_MAGNUMS , STR_AMMO_MAGNUMS } - , { ITEM_INV_UZIS , STR_UZIS } - , { ITEM_INV_AMMO_UZIS , STR_AMMO_UZIS } - , { ITEM_INV_EXPLOSIVE , STR_EXPLOSIVE } - , { ITEM_INV_MEDIKIT_BIG , STR_MEDIKIT_BIG } - , { ITEM_INV_MEDIKIT_SMALL , STR_MEDIKIT_SMALL } - , { ITEM_INV_PASSPORT , STR_PASSPORT } - , { ITEM_INV_DETAIL , STR_DETAIL } - , { ITEM_INV_SOUND , STR_SOUND } - , { ITEM_INV_CONTROLS , STR_CONTROLS } - , { ITEM_INV_GAMMA , STR_GAMMA } - , { ITEM_INV_HOME , STR_HOME } + { ITEM_INV_LEADBAR , STR_LEAD_BAR }, + { ITEM_INV_KEY_ITEM_1 , STR_KEY }, + { ITEM_INV_KEY_ITEM_2 , STR_KEY }, + { ITEM_INV_KEY_ITEM_3 , STR_KEY }, + { ITEM_INV_KEY_ITEM_4 , STR_KEY }, + { ITEM_INV_PUZZLE_4 , STR_PUZZLE }, + { ITEM_INV_PUZZLE_3 , STR_PUZZLE }, + { ITEM_INV_PUZZLE_2 , STR_PUZZLE }, + { ITEM_INV_PUZZLE_1 , STR_PUZZLE }, + { ITEM_INV_SCION , STR_SCION }, + { ITEM_INV_COMPASS , STR_COMPASS }, + { ITEM_INV_PISTOLS , STR_PISTOLS }, + { ITEM_INV_AMMO_PISTOLS , STR_AMMO_PISTOLS }, + { ITEM_INV_SHOTGUN , STR_SHOTGUN }, + { ITEM_INV_AMMO_SHOTGUN , STR_AMMO_SHOTGUN }, + { ITEM_INV_MAGNUMS , STR_MAGNUMS }, + { ITEM_INV_AMMO_MAGNUMS , STR_AMMO_MAGNUMS }, + { ITEM_INV_UZIS , STR_UZIS }, + { ITEM_INV_AMMO_UZIS , STR_AMMO_UZIS }, + { ITEM_INV_MEDIKIT_BIG , STR_MEDI_BIG }, + { ITEM_INV_MEDIKIT_SMALL , STR_MEDI_SMALL }, + { ITEM_INV_PASSPORT , STR_GAME }, + { ITEM_INV_DETAIL , STR_DETAIL }, + { ITEM_INV_SOUND , STR_SOUND }, + { ITEM_INV_CONTROLS , STR_CONTROLS }, + { ITEM_INV_HOME , STR_HOME }, }; @@ -152,7 +104,34 @@ struct Inventory int32 numKeys; - int32 counts[X_COUNT(INV_SLOTS)]; + int16 counts[SLOT_MAX]; + + int32 height; + int32 radius; + int32 pitch; + int16 rot; + int16 rotItem; + + ItemObj* lara; + InvPage page; + InvState state; + InvState nextState; + int32 timer; + + int32 heightTarget; + int32 heightInc; + int32 radiusTarget; + int32 radiusInc; + int32 pitchTarget; + int32 pitchInc; + int16 rotTarget; + int16 rotInc; + + InvSlot itemsList[SLOT_MAX]; + int32 itemsCount; + int32 itemIndex; + + void* background; Inventory() { @@ -285,12 +264,409 @@ struct Inventory return true; } + void setState(InvState state, InvState nextState, int32 timer) + { + this->state = state; + this->nextState = nextState; + this->timer = timer; + } + + void setHeight(int32 target) + { + heightTarget = target; + heightInc = (target - height) / timer; + } + + void setRadius(int32 target) + { + radiusTarget = target; + radiusInc = (target - radius) / timer; + } + + void setPitch(int32 target) + { + pitchTarget = target; + pitchInc = (target - pitch) / timer; + } + + void setRot(int32 delta, int32 target) + { + rotTarget = target; + rotInc = delta / timer; + } + + void setPage(InvPage page) + { + this->page = page; + + itemsCount = 0; + + #define ADD_SLOT(slot) itemsList[itemsCount++] = slot; + + switch (page) + { + case INV_PAGE_SAVE: + { + break; + } + + case INV_PAGE_TITLE: + case INV_PAGE_DEATH: + case INV_PAGE_OPTIONS: + { + ADD_SLOT(SLOT_PASSPORT); + ADD_SLOT(SLOT_DETAIL); + ADD_SLOT(SLOT_SOUND); + ADD_SLOT(SLOT_CONTROLS); + if (page == INV_PAGE_TITLE) + { + ADD_SLOT(SLOT_HOME); + } + break; + } + + case INV_PAGE_MAIN: + { + ADD_SLOT(SLOT_COMPASS); + ADD_SLOT(SLOT_PISTOLS); + ADD_SLOT(SLOT_SHOTGUN); + ADD_SLOT(SLOT_MAGNUMS); + ADD_SLOT(SLOT_UZIS); + ADD_SLOT(SLOT_MEDIKIT_BIG); + ADD_SLOT(SLOT_MEDIKIT_SMALL); + break; + } + + case INV_PAGE_KEYS: + { + ADD_SLOT(SLOT_LEADBAR); + ADD_SLOT(SLOT_KEY_ITEM_1); + ADD_SLOT(SLOT_KEY_ITEM_2); + ADD_SLOT(SLOT_KEY_ITEM_3); + ADD_SLOT(SLOT_KEY_ITEM_4); + ADD_SLOT(SLOT_PUZZLE_4); + ADD_SLOT(SLOT_PUZZLE_3); + ADD_SLOT(SLOT_PUZZLE_2); + ADD_SLOT(SLOT_PUZZLE_1); + ADD_SLOT(SLOT_SCION); + break; + } + } + + itemIndex = 0; + + setRot(ANGLE_180, itemIndex * ANGLE_360 / itemsCount); // TODO + rot = rotTarget - ANGLE_180; + } + + void open(ItemObj* lara, InvPage page) + { + if (gBrightness != 0) + return; + + soundPlay(SND_INV_SHOW, NULL); + + this->lara = lara; + + background = copyBackground(); + + height = INV_CAMERA_HEIGHT; + pitch = (page == INV_PAGE_TITLE) ? 1024 : 0; + radius = 0; + + setState(INV_STATE_OPENING, INV_STATE_READY, 16); + setHeight(-256); + setRadius(INV_RING_RADIUS); + setPage(page); + + update(1); + } + + void close() + { + soundPlay(SND_INV_HIDE, NULL); + + setState(INV_STATE_CLOSING, INV_STATE_NONE, 16); + setHeight(-1536); + setRadius(0); + setRot(ANGLE_180, rot - ANGLE_180); + } + + int32 getKeysCount() + { + int32 sum = 0; + + for (int32 i = SLOT_LEADBAR; i <= SLOT_SCION; i++) + { + sum += counts[i]; + } + + return sum; + } + + void update(int32 frames) + { + if (timer > 0) + { + timer -= frames; + + height += heightInc * frames; + radius += radiusInc * frames; + pitch += pitchInc * frames; + rot += rotInc * frames; + //rotItem += rotItemInc * frames; + + if (timer <= 0) + { + timer = 0; + state = nextState; + height = heightTarget; + radius = radiusTarget; + pitch = pitchTarget; + rot = rotTarget; + + heightInc = 0; + radiusInc = 0; + pitchInc = 0; + rotInc = 0; + rotItem = 0; + } + } + + rotItem += frames * 256; + + switch (state) + { + case INV_STATE_NONE: + { + break; + } + + case INV_STATE_OPENING: + { + break; + } + + case INV_STATE_READY: + { + if (lara->input & IN_LEFT) { + soundPlay(SND_INV_SPIN, NULL); + itemIndex++; + if (itemIndex >= itemsCount) { + itemIndex -= itemsCount; + } + setState(INV_STATE_SPIN, INV_STATE_READY, 12); + setRot(ANGLE_360 / itemsCount, itemIndex * ANGLE_360 / itemsCount); + } else if (lara->input & IN_RIGHT) { + soundPlay(SND_INV_SPIN, NULL); + itemIndex--; + if (itemIndex < 0) { + itemIndex += itemsCount; + } + setState(INV_STATE_SPIN, INV_STATE_READY, 12); + setRot(-ANGLE_360 / itemsCount, itemIndex * ANGLE_360 / itemsCount); + } else { + if (page != INV_PAGE_TITLE && page != INV_PAGE_SAVE && page != INV_PAGE_DEATH) + { + if (lara->input & IN_UP) { + if (page == INV_PAGE_OPTIONS) { + setState(INV_STATE_CLOSING, INV_STATE_PAGE_MAIN, 12); + setRadius(0); + setRot(ANGLE_180, rot - ANGLE_180); + setPitch(ANGLE_45); + } else if ((page == INV_PAGE_MAIN) && (getKeysCount() > 0)) { + setState(INV_STATE_CLOSING, INV_STATE_PAGE_KEYS, 12); + setRadius(0); + setRot(ANGLE_180, rot - ANGLE_180); + setPitch(ANGLE_45); + } + } else if (lara->input & IN_DOWN) { + if (page == INV_PAGE_KEYS) { + setState(INV_STATE_CLOSING, INV_STATE_PAGE_MAIN, 12); + setRadius(0); + setRot(ANGLE_180, rot - ANGLE_180); + setPitch(-ANGLE_45); + } else if (page == INV_PAGE_MAIN) { + setState(INV_STATE_CLOSING, INV_STATE_PAGE_OPTIONS, 12); + setRadius(0); + setRot(ANGLE_180, rot - ANGLE_180); + setPitch(-ANGLE_45); + } + } else if (lara->input & IN_SELECT) { + close(); + } + } + } + + break; + } + + case INV_STATE_CLOSING: + { + break; + } + + case INV_STATE_PAGE_MAIN: + { + pitch = -pitch; + setState(INV_STATE_OPENING, INV_STATE_READY, 12); + setRadius(INV_RING_RADIUS); + setPitch(0); + setPage(INV_PAGE_MAIN); + break; + } + + case INV_STATE_PAGE_KEYS: + { + pitch = -pitch; + setState(INV_STATE_OPENING, INV_STATE_READY, 12); + setRadius(INV_RING_RADIUS); + setPitch(0); + setPage(INV_PAGE_KEYS); + break; + } + + case INV_STATE_PAGE_OPTIONS: + { + pitch = -pitch; + setState(INV_STATE_OPENING, INV_STATE_READY, 12); + setRadius(INV_RING_RADIUS); + setPitch(0); + setPage(INV_PAGE_OPTIONS); + break; + } + + default: ; + } + } + + void drawSlot(InvSlot slot) + { + int32 type = INV_SLOTS[slot].type; + + if (type == ITEM_INV_PASSPORT) { + type = ITEM_INV_PASSPORT_CLOSED; + } + + ItemObj item; + memset(&item, 0, sizeof(item)); + item.type = type; + item.intensity = 255; + item.visibleMask = 0xFFFFFFFF; + item.animIndex = level.models[item.type].animIndex; // ctor called on existing memory, type is already initialized + item.frameIndex = level.anims[item.animIndex].frameBegin; + item.state = uint8(level.anims[item.animIndex].state); + item.nextState = item.state; + item.goalState = item.state; + + const AnimFrame *frameA, *frameB; + + int32 frameRate; + int32 frameDelta = item.getFrames(frameA, frameB, frameRate); + + calcLightingStatic(255 << 5); + drawNodesLerp(&item, frameA, frameB, frameDelta, frameRate); + } + + void drawPage() + { + int16 angleX, angleY; + + anglesFromVector(0, -(height + INV_CAMERA_Y), -INV_CAMERA_Z, angleX, angleY); + + vec3i pos = _vec3i(0, height, radius + INV_CAMERA_Z); + + matrixSetView(pos, angleX + pitch, angleY); + matrixTranslateAbs(0, 0, 0); + + for (int32 i = 0; i < itemsCount; i++) + { + matrixPush(); + matrixRotateY(i * ANGLE_360 / itemsCount - rot - ANGLE_90); + matrixTranslateRel(radius, 0, 0); + matrixRotateY(ANGLE_90); + matrixRotateX(-3616); + + if (itemIndex == i) { + matrixRotateY(rotItem); + } + + drawSlot(itemsList[i]); + + matrixPop(); + } + } + void draw() { - // + //clear(); + ASSERT(background); + renderBackground(background); + + StringID title = STR_EMPTY; + + switch (page) + { + case INV_PAGE_TITLE: + { + break; + } + + case INV_PAGE_SAVE: + { + break; + } + + case INV_PAGE_DEATH: + { + break; + } + + case INV_PAGE_MAIN: + { + title = STR_INV_TITLE_MAIN; + break; + } + + case INV_PAGE_KEYS: + { + title = STR_INV_TITLE_KEYS; + break; + } + + case INV_PAGE_OPTIONS: + { + title = STR_INV_TITLE_OPTIONS; + break; + } + } + + drawPage(); + + if (state == INV_STATE_READY || state == INV_STATE_SPIN) + { + drawText(0, 20, STR[title], TEXT_ALIGN_CENTER); + + if ((page == INV_PAGE_OPTIONS) || (page == INV_PAGE_MAIN && getKeysCount())) + { + drawText(4, 4 + 16, "[", TEXT_ALIGN_LEFT); + drawText(-6, 4 + 16, "[", TEXT_ALIGN_RIGHT); + } + + if (page == INV_PAGE_MAIN) + { + drawText(4, FRAME_HEIGHT - 5, "]", TEXT_ALIGN_LEFT); + drawText(-6, FRAME_HEIGHT - 5, "]", TEXT_ALIGN_RIGHT); + } + + if (state != INV_STATE_SPIN) + { + drawText(0, FRAME_HEIGHT - 8, STR[INV_SLOTS[itemsList[itemIndex]].str], TEXT_ALIGN_CENTER); + } + } } }; -Inventory inventory; +EWRAM_DATA Inventory inventory; #endif diff --git a/src/fixed/item.h b/src/fixed/item.h index b4c8778f..62eb72c0 100644 --- a/src/fixed/item.h +++ b/src/fixed/item.h @@ -5,7 +5,7 @@ #include "camera.h" #include "room.h" -int32 curItemIndex; +EWRAM_DATA AABBs tmpBox; #define GRAVITY 6 @@ -27,7 +27,7 @@ int32 alignOffset(int32 a, int32 b) return -(a + 1); } -void* soundPlay(int16 id, const vec3i &pos) +void* soundPlay(int16 id, const vec3i* pos) { // TODO gym // 0 -> 200 @@ -43,12 +43,17 @@ void* soundPlay(int16 id, const vec3i &pos) if (b->chance && b->chance < rand_draw()) return NULL; - vec3i d = pos - playersExtra[0].camera.target.pos; // TODO find nearest camera for coop + int32 volume = b->volume; - if (abs(d.x) >= SND_MAX_DIST || abs(d.y) >= SND_MAX_DIST || abs(d.z) >= SND_MAX_DIST) - return NULL; - - int32 volume = b->volume - (phd_sqrt(dot(d, d)) << 2); + if (pos) + { + vec3i d = *pos - playersExtra[0].camera.target.pos; // TODO find nearest camera for coop + + if (abs(d.x) >= SND_MAX_DIST || abs(d.y) >= SND_MAX_DIST || abs(d.z) >= SND_MAX_DIST) + return NULL; + + volume -= (phd_sqrt(dot(d, d)) << 2); + } if (SI_GAIN(b->flags)) { volume -= rand_draw() >> 2; @@ -136,8 +141,6 @@ const AnimFrame* ItemObj::getFrame() const return (frameDelta <= (frameRate >> 1)) ? frameA : frameB; } -AABBs tmpBox; - const AABBs& ItemObj::getBoundingBox(bool lerp) const { if (!lerp) @@ -312,7 +315,7 @@ void ItemObj::animCmd(bool fx, const Anim* anim) case ANIM_CMD_SOUND: { if (fx && frameIndex == ptr[0]) { - soundPlay(ptr[1] & 0x03FFF, pos); + soundPlay(ptr[1] & 0x03FFF, &pos); } ptr += 2; break; @@ -590,7 +593,7 @@ void ItemObj::fxRicochet(Room *fxRoom, const vec3i &fxPos, bool fxSound) ricochet->frameIndex = rand_draw() % (-level.models[ricochet->type].count); if (fxSound) { - soundPlay(SND_RICOCHET, ricochet->pos); + soundPlay(SND_RICOCHET, &ricochet->pos); } } diff --git a/src/fixed/lara.h b/src/fixed/lara.h index 8e818d1b..9e294945 100644 --- a/src/fixed/lara.h +++ b/src/fixed/lara.h @@ -4,6 +4,7 @@ #include "common.h" #include "item.h" #include "camera.h" +#include "inventory.h" #define LARA_STATES(E) \ E( STATE_WALK ) \ @@ -386,7 +387,7 @@ struct Lara : ItemObj return; if (!extraL->hitFrame) { - soundPlay(SND_HIT, pos); + soundPlay(SND_HIT, &pos); } extraL->hitFrame++; @@ -404,7 +405,7 @@ struct Lara : ItemObj void startScreaming() { - soundPlay(SND_SCREAM, pos); + soundPlay(SND_SCREAM, &pos); } void stopScreaming() @@ -2714,20 +2715,25 @@ struct Lara : ItemObj flags.shadow = true; extraL->camera.init(this); + extraL->healthTimer = 100; } // update control void updateInput() { + extraL->lastInput = input; + input = 0; if (extraL->camera.mode == CAMERA_MODE_FREE) return; - if (keys & IK_LEFT) input |= IN_LEFT; - if (keys & IK_RIGHT) input |= IN_RIGHT; - if (keys & IK_UP) input |= IN_UP; - if (keys & IK_DOWN) input |= IN_DOWN; + if (keys & IK_LEFT) input |= IN_LEFT; + if (keys & IK_RIGHT) input |= IN_RIGHT; + if (keys & IK_UP) input |= IN_UP; + if (keys & IK_DOWN) input |= IN_DOWN; + if (keys & IK_START) input |= IN_START; + if (keys & IK_SELECT) input |= IN_SELECT; #ifdef __3DO__ if (keys & IK_A) input |= IN_JUMP; @@ -2771,27 +2777,14 @@ struct Lara : ItemObj input |= IN_WALK; } } - - if (keys & IK_SELECT) - { - int32 gamma = gSaveGame.gamma; - - if (keys & IK_R) { - gamma += 16; - } - - if (keys & IK_L) { - gamma -= 16; - } - - gamma = X_CLAMP(gamma, 0, 256); - if (gamma != gSaveGame.gamma) { - osSetGamma(gSaveGame.gamma = gamma); - } - } #endif } + bool isKeyHit(InputState state) + { + return (input & state) && !(extraL->lastInput & state); + } + void updateLook() { ExtraInfoLara::Arm &R = extraL->armR; @@ -3083,7 +3076,7 @@ struct Lara : ItemObj int16 ammo = extraL->ammo[extraL->weapon]; if (!ammo) { - soundPlay(SND_EMPTY, pos); + soundPlay(SND_EMPTY, &pos); extraL->goalWeapon = WEAPON_PISTOLS; return false; } @@ -3164,7 +3157,7 @@ struct Lara : ItemObj } } - soundPlay(params.soundId, pos); + soundPlay(params.soundId, &pos); return true; } @@ -3230,7 +3223,7 @@ struct Lara : ItemObj if (anim == ANIM_PISTOLS_DRAW) { meshSwapPistols(JOINT_MASK_ARM_R3 | JOINT_MASK_ARM_L3, JOINT_MASK_LEG_R1 | JOINT_MASK_LEG_L1); - soundPlay(SND_DRAW, pos); + soundPlay(SND_DRAW, &pos); } else if (anim == ANIM_PISTOLS_FIRE) { anim = ANIM_PISTOLS_AIM; setWeaponState(WEAPON_STATE_READY); @@ -3283,7 +3276,7 @@ struct Lara : ItemObj } else { meshSwapPistols(JOINT_MASK_LEG_L1, JOINT_MASK_ARM_L3); } - soundPlay(SND_HOLSTER, pos); + soundPlay(SND_HOLSTER, &pos); } else if (anim == ANIM_PISTOLS_FIRE) { anim = ANIM_PISTOLS_AIM; } @@ -3315,7 +3308,7 @@ struct Lara : ItemObj if (frame == 10) { meshSwapShotgun(true); - soundPlay(SND_DRAW, pos); + soundPlay(SND_DRAW, &pos); } if (frame == animLength) { @@ -3358,7 +3351,7 @@ struct Lara : ItemObj } else { if (frame == 10) { meshSwapShotgun(false); - soundPlay(SND_HOLSTER, pos); + soundPlay(SND_HOLSTER, &pos); } frame--; } @@ -3491,7 +3484,7 @@ struct Lara : ItemObj { frame++; if (frame == 10) { - soundPlay(SND_SHOTGUN_RELOAD, pos); + soundPlay(SND_SHOTGUN_RELOAD, &pos); } else if (frame == params.reloadTimer) { anim = ANIM_SHOTGUN_AIM; animPtr = level.anims + level.models[params.animType].animIndex + anim; @@ -3781,6 +3774,7 @@ struct Lara : ItemObj osJoyVibrate(0, 0xFF, 0xFF); health -= damage; + extraL->healthTimer = 40; } virtual void update() @@ -3789,6 +3783,16 @@ struct Lara : ItemObj updateInput(); + if ((input & (IN_JUMP | IN_WEAPON)) == (IN_JUMP | IN_WEAPON)) + { + restore(); + } + + if (isKeyHit(IN_SELECT)) + { + inventory.open(this, INV_PAGE_MAIN); + } + updateLook(); updateWaterState(); @@ -3848,6 +3852,10 @@ struct Lara : ItemObj checkTrigger(cinfo.trigger, this); extraL->camera.update(); + + if (health > 0 && extraL->healthTimer > 0) { + extraL->healthTimer--; + } } void meshSwap(ItemType type, uint32 mask) diff --git a/src/fixed/level.h b/src/fixed/level.h index 9fb475d5..3c260ef2 100644 --- a/src/fixed/level.h +++ b/src/fixed/level.h @@ -26,6 +26,8 @@ EWRAM_DATA StaticMesh staticMeshes[MAX_STATIC_MESHES]; ItemObj* ItemObj::sFirstActive; ItemObj* ItemObj::sFirstFree; +int32 gBrightness; + void readLevel_GBA(const uint8* data) { memcpy(&level, data, sizeof(level)); @@ -58,7 +60,8 @@ void readLevel_GBA(const uint8* data) #ifndef MODEHW // initialize global pointers - osSetPalette(level.palette); + gBrightness = -128; + palSet(level.palette, gSaveGame.gamma, gBrightness); memcpy(lightmap, level.lightmap, sizeof(lightmap)); #endif @@ -158,8 +161,38 @@ void animTexturesShift() } } +#define FADING_RATE 16 + +void updateFading(int32 frames) +{ + if (gBrightness == 0) + return; + + frames *= FADING_RATE; + + if (gBrightness < 0) + { + gBrightness += frames; + if (gBrightness > 0) { + gBrightness = 0; + } + } + + if (gBrightness > 0) + { + gBrightness -= frames; + if (gBrightness < 0) { + gBrightness = 0; + } + } + + palSet(level.palette, gSaveGame.gamma, gBrightness); +} + void updateLevel(int32 frames) { + updateFading(frames); + gCausticsFrame += frames; gAnimTexFrame += frames; diff --git a/src/fixed/object.h b/src/fixed/object.h index d4f62c34..f9665dcd 100644 --- a/src/fixed/object.h +++ b/src/fixed/object.h @@ -24,32 +24,32 @@ struct Limit // armcpp won't initialize structs -int16 LIMIT_SWITCH[] = { +const int16 LIMIT_SWITCH[] = { -200, 200, 0, 0, 312, 512, ANGLE(10), ANGLE(30), ANGLE(10) }; -int16 LIMIT_SWITCH_UW[] = { +const int16 LIMIT_SWITCH_UW[] = { -1024, 1024, -1024, 1024, -1024, 1024, ANGLE(80), ANGLE(80), ANGLE(80) }; -int16 LIMIT_BLOCK[] = { +const int16 LIMIT_BLOCK[] = { -300, 300, 0, 0, -692, -512, ANGLE(10), ANGLE(30), ANGLE(10) }; -int16 LIMIT_PICKUP[] = { +const int16 LIMIT_PICKUP[] = { -256, 256, -100, 100, -256, 100, ANGLE(10), 0, 0 }; -int16 LIMIT_PICKUP_UW[] = { +const int16 LIMIT_PICKUP_UW[] = { -512, 512, -512, 512, -512, 512, ANGLE(45), ANGLE(45), ANGLE(45) }; -int16 LIMIT_HOLE[] = { +const int16 LIMIT_HOLE[] = { -200, 200, 0, 0, 312, 512, ANGLE(10), ANGLE(30), ANGLE(10) }; @@ -168,7 +168,7 @@ struct Bubble : ItemObj { Bubble(Room* room) : ItemObj(room) { - soundPlay(SND_BUBBLE, pos); + soundPlay(SND_BUBBLE, &pos); frameIndex = rand_draw() % (-level.models[type].count); vSpeed = -(10 + (rand_draw() % 6)); angle = _vec3s(0, 0, ANGLE_90); @@ -582,9 +582,6 @@ bool usePickup(ItemObj* item) return ((Pickup*)item)->use(); } - -vec3i tmpPos; - struct Hole : Object // parent class for KeyHole and PuzzleHole { Hole(Room* room) : Object(room) {} @@ -622,14 +619,14 @@ struct Hole : Object // parent class for KeyHole and PuzzleHole return; } - tmpPos.x = ~lara->pos.x; + lara->extraL->tmpPos.x = ~lara->pos.x; inventory.useSlot = SLOT_MAX; } - if (tmpPos != lara->pos) + if (lara->extraL->tmpPos != lara->pos) { - tmpPos = lara->pos; - soundPlay(SND_NO, lara->pos); + lara->extraL->tmpPos = lara->pos; + soundPlay(SND_NO, &lara->pos); } } }; @@ -773,8 +770,7 @@ struct TrapSwingBlade : Object vec3i offsetPos = _vec3i((rand_logic() - 0x4000) >> 8, -256 - (rand_logic() >> 6), (rand_logic() - 0x4000) >> 8); int32 offsetAngle = (rand_logic() - 0x4000) >> 3; lara->fxBlood(lara->pos + offsetPos, lara->angle.y + offsetAngle, lara->hSpeed); - - lara->health -= 100; // TODO TR2 50? + lara->hit(100, pos, 0); // TODO TR2 50? } virtual void update() @@ -808,7 +804,7 @@ struct Dart : Object if (hitMask) { lara->fxBlood(pos, lara->angle.y, lara->hSpeed); - lara->health -= 50; + lara->hit(50, pos, 0); } } @@ -856,7 +852,7 @@ struct TrapDartEmitter : Object if (dart) { - soundPlay(SND_DART, p); + soundPlay(SND_DART, &pos); dart->intensity = 0; dart->flags.status = ITEM_FLAGS_STATUS_ACTIVE; diff --git a/src/fixed/room.h b/src/fixed/room.h index 92950fde..0e14e498 100644 --- a/src/fixed/room.h +++ b/src/fixed/room.h @@ -3,7 +3,7 @@ #include "common.h" -Room* roomsList[MAX_ROOM_LIST]; +EWRAM_DATA Room* roomsList[MAX_ROOM_LIST]; //#ifdef ROM_READ int32 dynSectorsCount; @@ -353,9 +353,9 @@ bool Room::collideStatic(CollisionInfo &cinfo, const vec3i &p, int32 height) bool Room::checkPortal(const Portal* portal) { vec3i d; - d.x = portal->v[0].x - cameraViewPos.x + (info->x << 8); - d.y = portal->v[0].y - cameraViewPos.y; - d.z = portal->v[0].z - cameraViewPos.z + (info->z << 8); + d.x = portal->v[0].x - gCameraViewPos.x + (info->x << 8); + d.y = portal->v[0].y - gCameraViewPos.y; + d.z = portal->v[0].z - gCameraViewPos.z + (info->z << 8); Matrix &m = matrixGet(); diff --git a/src/platform/gba/main.cpp b/src/platform/gba/main.cpp index bc9be8d0..ba923a23 100644 --- a/src/platform/gba/main.cpp +++ b/src/platform/gba/main.cpp @@ -293,30 +293,11 @@ int32 fpsCounter = 0; void osJoyVibrate(int32 index, int32 L, int32 R) {} #endif -void osSetGamma(int32 value) -{ - if (value == 0) { - osSetPalette(level.palette); - return; - } - - uint16 pal[256]; - for (int32 i = 0; i < 256; i++) - { - int32 r = 31 & (level.palette[i]); - int32 g = 31 & (level.palette[i] >> 5); - int32 b = 31 & (level.palette[i] >> 10); - - r = X_MIN(31, r + (((r * r >> 2) - r) * value >> 8)); - g = X_MIN(31, g + (((g * g >> 2) - g) * value >> 8)); - b = X_MIN(31, b + (((b * b >> 2) - b) * value >> 8)); - - pal[i] = r | (g << 5) | (b << 10); - } - osSetPalette(pal); -} - -EWRAM_DATA ALIGN16 uint8 soundBuffer[2 * SND_SAMPLES + 32]; // 32 bytes of silence for DMA overrun while interrupt +//#ifdef __GBA__ +// uint8* soundBuffer = (uint8*)MEM_VRAM + FRAME_WIDTH * FRAME_HEIGHT; // use 2k of VRAM after the first frame buffer as sound buffer +//#else + EWRAM_DATA ALIGN16 uint8 soundBuffer[2 * SND_SAMPLES + 32]; // 32 bytes of silence for DMA overrun while interrupt +//#endif uint32 curSoundBuffer = 0; @@ -540,7 +521,6 @@ int main(void) { int32 startTime = GetTickCount() - 33; int32 lastFrame = 0; - uint32 oldKeys = 0; do { if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { @@ -550,13 +530,6 @@ int main(void) { int32 frame = (GetTickCount() - startTime) / 33; if (GetAsyncKeyState('R')) frame /= 10; - if ((keys & IK_SELECT) && !(oldKeys & IK_SELECT)) - { - nextLevel(); - } - - oldKeys = keys; - int32 count = frame - lastFrame; if (GetAsyncKeyState('T')) count *= 10; game.update(count); @@ -617,14 +590,12 @@ int main(void) { REG_BG2PD = (1 << 8); int32 lastFrameIndex = -1; - uint32 oldKeys = 0; while (1) { rumbleUpdate(); { // input - oldKeys = keys; keys = 0; key_poll(); if (key_is_down(KEY_UP)) keys |= IK_UP; @@ -639,15 +610,18 @@ int main(void) { if (key_is_down(KEY_SELECT)) keys |= IK_SELECT; } - if ((keys & IK_SELECT) && !(oldKeys & IK_SELECT)) - { - nextLevel(); - } int32 frame = frameIndex / 2; - game.update(frame - lastFrameIndex); + int32 delta = frame - lastFrameIndex; + + if (!delta) { + continue; + } + lastFrameIndex = frame; + game.update(delta); + #ifdef PROFILING VBlankIntrWait(); #endif @@ -665,7 +639,6 @@ int main(void) { fpsCounter = 0; } - } #elif defined(__TNS__) if (!has_colors) diff --git a/src/platform/gba/matrixTranslate.s b/src/platform/gba/matrixTranslate.s index db018e68..c24aa68c 100644 --- a/src/platform/gba/matrixTranslate.s +++ b/src/platform/gba/matrixTranslate.s @@ -44,7 +44,7 @@ matrixTranslateRel_asm: matrixTranslateAbs_asm: stmfd sp!, {r4-r5, lr} - ldr v, =cameraViewPos + ldr v, =gCameraViewPos ldmia v, {e0, e1, e2} sub x, x, e0 sub y, y, e1 diff --git a/src/platform/gba/packer/main.cpp b/src/platform/gba/packer/main.cpp index ac520c38..35169903 100644 --- a/src/platform/gba/packer/main.cpp +++ b/src/platform/gba/packer/main.cpp @@ -2547,8 +2547,54 @@ struct LevelPC hideRoom(16); hideRoom(17); hideRoom(18); - // TODO remove unused textures & models - } + + // disable alpha-test + objectTextures[93].attribute = + objectTextures[167].attribute = + objectTextures[175].attribute = + objectTextures[190].attribute = + objectTextures[191].attribute = + objectTextures[211].attribute = + objectTextures[220].attribute = + objectTextures[221].attribute = + objectTextures[580].attribute = + objectTextures[581].attribute = 0; + } + + if (strcmp(name, "LEVEL1") == 0) + { + objectTextures[271].attribute = + objectTextures[272].attribute = + objectTextures[331].attribute = + objectTextures[333].attribute = + objectTextures[334].attribute = + objectTextures[335].attribute = + objectTextures[517].attribute = + objectTextures[518].attribute = + objectTextures[569].attribute = + objectTextures[571].attribute = + objectTextures[685].attribute = + objectTextures[686].attribute = 0; + } + + if (strcmp(name, "LEVEL2") == 0) + { + objectTextures[247].attribute = + objectTextures[248].attribute = + objectTextures[307].attribute = + objectTextures[309].attribute = + objectTextures[310].attribute = + objectTextures[311].attribute = + objectTextures[547].attribute = + objectTextures[661].attribute = + objectTextures[662].attribute = + objectTextures[688].attribute = + objectTextures[905].attribute = + objectTextures[906].attribute = + objectTextures[923].attribute = 0; + } + + // TODO remove unused textures & models } void convertGBA(const char* fileName) @@ -4576,7 +4622,7 @@ struct LevelPC #define COLOR_THRESHOLD_SQ (8 * 8) const char* levelNames[] = { -#if 1 +#if 0 "TITLE", "GYM", "LEVEL1", @@ -5531,8 +5577,12 @@ void convertTracks3DO(const char* inDir, const char* outDir) FindClose(h); } +uint32 palDump[32][256]; + int main() { + memset(palDump, 0, sizeof(palDump)); + //pack_tracks("tracks/conv_demo/*.ima"); return 0; for (int32 i = 0; i < MAX_LEVELS; i++) @@ -5540,6 +5590,15 @@ int main() char path[64]; sprintf(path, "levels/%s.PHD", levelNames[i]); levels[i] = new LevelPC(path); + + for (int32 j = 0; j < 256; j++) + { + int32 r = levels[i]->palette.colors[j * 3 + 0] << 2; + int32 g = levels[i]->palette.colors[j * 3 + 1] << 2; + int32 b = levels[i]->palette.colors[j * 3 + 2] << 2; + palDump[i][j] = b | (g << 8) | (r << 16) | (0xFF << 24); + } + levels[i]->generateLODs(); levels[i]->cutData(levelNames[i]); @@ -5549,6 +5608,8 @@ int main() levels[i]->convert3DO(levelNames[i]); } +// saveBitmap("pal.bmp", (uint8*)palDump, 256, 32, 32); + // convertTracks3DO("C:\\Projects\\OpenLara\\src\\platform\\gba\\packer\\tracks\\orig\\*", "C:\\Projects\\OpenLara\\src\\platform\\3do\\tracks"); return 0; diff --git a/src/platform/gba/rasterizer_mode4.h b/src/platform/gba/rasterizer_mode4.h index f5309ec6..870d873e 100644 --- a/src/platform/gba/rasterizer_mode4.h +++ b/src/platform/gba/rasterizer_mode4.h @@ -26,6 +26,9 @@ extern const uint8* tile; #define rasterizeFTA rasterizeFTA_asm #define rasterizeGTA rasterizeGTA_asm #define rasterizeSprite rasterizeSprite_c + #define rasterizeLineH rasterizeLineH_c + #define rasterizeLineV rasterizeLineV_c + #define rasterizeFillS rasterizeFillS_c #else #define rasterizeS rasterizeS_c #define rasterizeF rasterizeF_c @@ -35,6 +38,9 @@ extern const uint8* tile; #define rasterizeFTA rasterizeFTA_c #define rasterizeGTA rasterizeGTA_c #define rasterizeSprite rasterizeSprite_c + #define rasterizeLineH rasterizeLineH_c + #define rasterizeLineV rasterizeLineV_c + #define rasterizeFillS rasterizeFillS_c void rasterizeS_c(uint16* pixel, const VertexLink* L, const VertexLink* R) { @@ -1032,10 +1038,6 @@ void rasterizeSprite_c(uint16* pixel, const VertexLink* L, const VertexLink* R) } bool alignR = w & 1; - if (alignR) - { - w--; - } w >>= 1; @@ -1049,9 +1051,9 @@ void rasterizeSprite_c(uint16* pixel, const VertexLink* L, const VertexLink* R) if (alignL) { - uint8 indexB = ft_lightmap[xtile[xu >> 8]]; + uint8 indexB = xtile[xu >> 8]; if (indexB) { - *(uint16*)xptr = *xptr | (indexB << 8); + *(uint16*)xptr = *xptr | (ft_lightmap[indexB] << 8); } xptr += 2; @@ -1060,15 +1062,15 @@ void rasterizeSprite_c(uint16* pixel, const VertexLink* L, const VertexLink* R) for (int32 x = 0; x < w; x++) { - uint8 indexA = ft_lightmap[xtile[xu >> 8]]; + uint8 indexA = xtile[xu >> 8]; xu += du; - uint8 indexB = ft_lightmap[xtile[xu >> 8]]; + uint8 indexB = xtile[xu >> 8]; xu += du; if (indexA | indexB) { - if (indexA == 0) indexA = xptr[0]; - if (indexB == 0) indexB = xptr[1]; + indexA = (indexA) ? ft_lightmap[indexA] : xptr[0]; + indexB = (indexB) ? ft_lightmap[indexB] : xptr[1]; *(uint16*)xptr = indexA | (indexB << 8); } @@ -1077,9 +1079,9 @@ void rasterizeSprite_c(uint16* pixel, const VertexLink* L, const VertexLink* R) if (alignR) { - uint8 indexA = ft_lightmap[xtile[xu >> 8]]; + uint8 indexA = xtile[xu >> 8]; if (indexA) { - *(uint16*)xptr = indexA | (xptr[1] << 8); + *(uint16*)xptr = ft_lightmap[indexA] | (xptr[1] << 8); } } @@ -1089,5 +1091,73 @@ void rasterizeSprite_c(uint16* pixel, const VertexLink* L, const VertexLink* R) } } +X_NOINLINE void rasterizeLineH_c(int32 x, int32 y, int32 width, int32 index) +{ + volatile uint8* ptr = (uint8*)fb + y * FRAME_WIDTH + x; + + if (intptr_t(ptr) & 1) + { + ptr--; + *(uint16*)ptr = *ptr | (index << 8); + ptr += 2; + width--; + } + + if (width & 1) + { + *(uint16*)(ptr + width - 1) = index | (ptr[width] << 8); + } + + for (int32 i = 0; i < width / 2; i++) + { + *(uint16*)ptr = index | (index << 8); + ptr += 2; + } +} + +X_NOINLINE void rasterizeLineV_c(int32 x, int32 y, int32 height, int32 index) +{ + volatile uint8* ptr = (uint8*)fb + y * FRAME_WIDTH + x; + + for (int32 i = 0; i < height; i++) + { + if (intptr_t(ptr) & 1) { + *(uint16*)(ptr - 1) = *(ptr - 1) | (index << 8); + } else { + *(uint16*)ptr = index | (*ptr << 8); + } + ptr += FRAME_WIDTH; + } +} + +X_NOINLINE void rasterizeFillS_c(int32 x, int32 y, int32 width, int32 height, int32 shade) +{ + const uint8* lm = &lightmap[shade * 256]; + + for (int32 i = 0; i < height; i++) + { + volatile uint8* ptr = (uint8*)fb + (y + i) * FRAME_WIDTH + x; + int32 w = width; + + if (intptr_t(ptr) & 1) + { + ptr--; + *(uint16*)ptr = ptr[0] | (lm[ptr[1]] << 8); + ptr += 2; + w--; + } + + if (w & 1) + { + *(uint16*)(ptr + w - 1) = lm[ptr[w - 1]] | (ptr[w] << 8); + } + + for (int32 i = 0; i < w / 2; i++) + { + *(uint16*)ptr = lm[ptr[0]] | (lm[ptr[1]] << 8); + ptr += 2; + } + } +} #endif diff --git a/src/platform/gba/render.iwram.cpp b/src/platform/gba/render.iwram.cpp index f9effe6a..b6ec5a6e 100644 --- a/src/platform/gba/render.iwram.cpp +++ b/src/platform/gba/render.iwram.cpp @@ -67,6 +67,7 @@ const uint8* tile; Vertex* gVerticesBase; Face* gFacesBase; +EWRAM_DATA uint8 gBackgroundCopy[FRAME_WIDTH * FRAME_HEIGHT]; // EWRAM 37.5k EWRAM_DATA Vertex gVertices[MAX_VERTICES]; // EWRAM 16k EWRAM_DATA Face gFaces[MAX_FACES]; // EWRAM 5k EWRAM_DATA Face* otFaces[OT_SIZE]; @@ -867,48 +868,6 @@ void drawSprite(Face* face, VertexLink* v) rasterize(face->flags, v); } -void drawGlyph(const Sprite *sprite, int32 x, int32 y) -{ - int32 w = sprite->r - sprite->l; - int32 h = sprite->b - sprite->t; - - w = (w >> 1) << 1; // make it even - - int32 ix = x + sprite->l; - int32 iy = y + sprite->t; - - uint16* pixel = (uint16*)fb + iy * VRAM_WIDTH + (ix >> 1); - - const uint16* glyphData = (uint16*)(level.tiles + (sprite->tile << 16) + 256 * sprite->v + sprite->u); - - while (h--) - { - const uint16* p = glyphData; - - for (int32 i = 0; i < (w / 2); i++) - { - if (p[0]) - { - if (p[0] & 0x00FF) { - if (p[0] & 0xFF00) { - pixel[i] = p[0]; - } else { - pixel[i] = (pixel[i] & 0xFF00) | p[0]; - } - } else { - pixel[i] = (pixel[i] & 0x00FF) | p[0]; - } - } - - p++; - } - - pixel += VRAM_WIDTH; - - glyphData += 256 / 2; - } -} - void faceAddRoom(const Room* room) { if (room->info->quadsCount > 0) { @@ -956,8 +915,8 @@ void flush() v[0].t.uv.u = sprite.u; v[0].t.uv.v = sprite.v; v[1].v = gVertices[face->indices[0] + 1]; - v[1].t.uv.u = sprite.w; - v[1].t.uv.v = sprite.h; + v[1].t.uv.u = sprite.w + 1; + v[1].t.uv.v = sprite.h + 1; ASSERT(v[0].v.x <= v[1].v.x); ASSERT(v[0].v.y <= v[1].v.y); @@ -1140,9 +1099,9 @@ void renderSprite(int32 vx, int32 vy, int32 vz, int32 vg, int32 index) const Matrix &m = matrixGet(); - vx -= cameraViewPos.x; - vy -= cameraViewPos.y; - vz -= cameraViewPos.z; + vx -= gCameraViewPos.x; + vy -= gCameraViewPos.y; + vz -= gCameraViewPos.z; int32 z = DP33(m.e20, m.e21, m.e22, vx, vy, vz); @@ -1218,5 +1177,109 @@ void renderSprite(int32 vx, int32 vy, int32 vz, int32 vg, int32 index) void renderGlyph(int32 vx, int32 vy, int32 index) { - // + if (gVerticesBase - gVertices + 2 > MAX_VERTICES) { + ASSERT(false); + return; + } + + if (gFacesBase - gFaces + 1 > MAX_FACES) { + ASSERT(false); + return; + } + + const Sprite* sprite = level.sprites + index; + + int32 l = vx + sprite->l; + int32 r = vx + sprite->r; + int32 t = vy + sprite->t; + int32 b = vy + sprite->b; + + if (l == r) return; + if (t == b) return; + if (r < 0) return; + if (b < 0) return; + if (l >= FRAME_WIDTH) return; + if (t >= FRAME_HEIGHT) return; + + Vertex* v1 = gVerticesBase++; + v1->x = l; + v1->y = t; + //v1->z = z; + v1->g = 16; + + Vertex* v2 = gVerticesBase++; + v2->x = r; + v2->y = b; + //v2->z = z; + //v2->g = vg; + + Face* f = faceAdd(0); + f->flags = uint16(FACE_SPRITE); + f->indices[0] = v1 - gVertices; + f->indices[1] = index; + + gVerticesBase += 2; +} + +#define BAR_WIDTH 100 +#define BAR_HEIGHT 5 + +void renderBar(int32 x, int32 y, int32 value, BarType type) +{ + // frame + rasterizeLineV(x, y, BAR_HEIGHT + 2 + 2, 19); + rasterizeLineV(x + BAR_WIDTH + 2 + 1, y, BAR_HEIGHT + 2 + 2, 17); + rasterizeLineH(x + 1, y, BAR_WIDTH + 2, 19); + rasterizeLineH(x + 1, y + BAR_HEIGHT + 2 + 1, BAR_WIDTH + 2, 17); + + // background + x++; + y++; + rasterizeFillS(x, y, BAR_WIDTH + 2, BAR_HEIGHT + 2, 27); + + // colored bar + x++; + y++; + int32 w = value * BAR_WIDTH >> 8; + + switch (type) + { + case BAR_HEALTH: + rasterizeLineH(x, y++, w, 8); + rasterizeLineH(x, y++, w, 11); + rasterizeLineH(x, y++, w, 8); + rasterizeLineH(x, y++, w, 6); + rasterizeLineH(x, y++, w, 24); + break; + case BAR_OXYGEN: + rasterizeLineH(x, y++, w, 32); + rasterizeLineH(x, y++, w, 41); + rasterizeLineH(x, y++, w, 32); + rasterizeLineH(x, y++, w, 19); + rasterizeLineH(x, y++, w, 21); + break; + case BAR_DASH: + // TODO + break; + } +} + +void renderBackground(void* background) +{ + dmaCopy(background, (void*)fb, FRAME_WIDTH * FRAME_HEIGHT); +} + +void* copyBackground() +{ + dmaCopy((void*)fb, gBackgroundCopy, FRAME_WIDTH * FRAME_HEIGHT); + + uint8 remap[256]; + palGrayRemap(level.palette, remap); + + for (int32 i = 0; i < FRAME_WIDTH * FRAME_HEIGHT; i++) + { + gBackgroundCopy[i] = remap[gBackgroundCopy[i]]; + } + + return gBackgroundCopy; }