diff --git a/assets.h b/assets.h index bbf8f22..3c7cc65 100644 --- a/assets.h +++ b/assets.h @@ -16,6 +16,13 @@ #include #include "map.h" + +static const char *LCR_maps[] = +{ + "LM;aaa; bbb; 2; #=s0s0#=s1s0#f4120" +}; + +/* static const uint8_t map1[] = { LCR_MAP_MAGIC_NUMBER, @@ -64,6 +71,7 @@ LCR_MAP_BLOCK(LCR_BLOCK_CHECKPOINT_0,3,1,4,LCR_BLOCK_MATERIAL_CONCRETE,0), LCR_MAP_BLOCK(LCR_BLOCK_CHECKPOINT_0,3,1,8,LCR_BLOCK_MATERIAL_CONCRETE,0), LCR_MAP_BLOCK(LCR_BLOCK_FINISH,2,1,10,LCR_BLOCK_MATERIAL_CONCRETE,0), +*/ /* LCR_MAP_BLOCK(LCR_BLOCK_FULL,2,1,9,LCR_BLOCK_MATERIAL_CONCRETE,0), @@ -85,10 +93,10 @@ LCR_MAP_BLOCK(LCR_BLOCK_CUBOID_FILL,10,1,15,0,0), LCR_MAP_BLOCK(LCR_BLOCK_FULL,35,0,0,LCR_BLOCK_MATERIAL_DIRT,0), LCR_MAP_BLOCK(LCR_BLOCK_CUBOID_FILL,10,1,15,0,0), -*/ LCR_MAP_TERMINATOR }; +*/ #define LCR_IMAGE_SIZE 64 ///< one-dimension resolution of bitmap image #define LCR_IMAGE_STORE_SIZE (LCR_IMAGE_SIZE * LCR_IMAGE_SIZE + 256 * 2) diff --git a/game.h b/game.h index 57cd3b7..bd04455 100644 --- a/game.h +++ b/game.h @@ -117,8 +117,17 @@ uint8_t LCR_gameStep(uint32_t timeMs); #define LCR_CONTROL_MODE_FREECAM 0x00 #define LCR_CONTROL_MODE_DRIVE 0x01 +#define LCR_GAME_STATE_MENU 0x00 +#define LCR_GAME_STATE_RUN_STARTING 0x01 +#define LCR_GAME_STATE_RUN 0x02 +#define LCR_GAME_STATE_RUN_FINISHED 0x03 + struct { + uint8_t state; + uint32_t stateStartTime; + + uint32_t time; uint32_t nextRenderFrameTime; uint32_t nextRacingTickTime; uint8_t controlMode; @@ -163,12 +172,29 @@ static inline void LCR_drawPixelXYSafe(unsigned int x, unsigned int y, LCR_drawPixelXYUnsafe(x,y,color); } +void LCR_gameSetState(uint8_t state) +{ + LCR_LOG1("changing state"); + LCR_game.state = state; + LCR_game.stateStartTime = LCR_game.time; +} + void LCR_gameResetRun(void) { LCR_LOG0("resetting run"); LCR_game.checkpointsTaken = 0; LCR_mapReset(); LCR_rendererUnmarkCPs(); + LCR_gameSetState(LCR_GAME_STATE_RUN_STARTING); +} + +//void LCR_gameStartRun(const uint8_t *map) +void LCR_gameStartRun(const char *mapStr) +{ + LCR_mapLoadFromStr(mapStr); + LCR_rendererLoadMap(); + LCR_gameResetRun(); + LCR_racingRestart(); } void LCR_gameInit(void) @@ -178,7 +204,6 @@ void LCR_gameInit(void) for (int i = 0; i < LCR_KEYS_TOTAL; ++i) LCR_keyStates[i] = 0; - LCR_mapLoad(map1); LCR_rendererInit(); LCR_racingInit(); @@ -188,7 +213,7 @@ void LCR_gameInit(void) LCR_game.controlMode = LCR_CONTROL_MODE_FREECAM; LCR_game.debugDraw = 0; - LCR_gameResetRun(); + LCR_gameStartRun(LCR_maps[0]); } void LCR_gameEnd(void) @@ -200,6 +225,8 @@ uint8_t LCR_gameStep(uint32_t time) { LCR_LOG2("game step start"); + LCR_game.time = time; + LCR_GameUnit carTransform[6]; for (int i = 0; i < LCR_KEYS_TOTAL; ++i) diff --git a/map.h b/map.h index ed706fd..2773639 100644 --- a/map.h +++ b/map.h @@ -43,8 +43,42 @@ The PREPROCESSED map format is similar, but only consists of block values but there are only normal blocks (no special blocks) and they are sorted by their coordinate number. + + + The TEXT FORMAT serves for editing maps in human readable format, it more or + less corresponds to the binary storage format and has the following structure: + - Magic number string: "LM;". + - Until next ';': name. + - Until next ';': description. + - Until next ';': tags. Currently this may contain the following: + - digit N: set the map environment to N. + - Then a series of block strings follow. Blocks may be separated by + characters that aren't '#'. Block format is following: + + #BXYZMT + + where: + - B: is block type + - X, Y and Z are block coordinates, each one a single character. The + following are characters signifying numbers 0 to 63: + 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$@ + - M is block material ('0' to '3') + - T is an optinal transform string consisting from 0 to 3 characters, + which may be: + - '|': flip horizontally + - '-': flip vertically + - 'L': rotate 90 degrees + - 'I': rotate 180 degrees + - 'J': rotate 270 degrees + + + + */ + + + #define LCR_BLOCK_TRANSFORM_FLIP_H 0x10 #define LCR_BLOCK_TRANSFORM_ROT_90 0x20 #define LCR_BLOCK_TRANSFORM_ROT_180 0x40 @@ -55,6 +89,8 @@ #define LCR_MAP_MAGIC_NUMBER1 'L' #define LCR_MAP_MAGIC_NUMBER2 'M' +#define LCR_MAP_SEPARATOR ';' + #define LCR_MAP_MAGIC_NUMBER LCR_MAP_MAGIC_NUMBER1, LCR_MAP_MAGIC_NUMBER2 #define LCR_MAP_TERMINATOR 0xff #define LCR_MAP_BLOCK(t,x,y,z,m,r) t,(uint8_t) (x | (y << 6)), \ @@ -68,24 +104,38 @@ #define LCR_BLOCK_MATERIAL_DIRT 0x02 #define LCR_BLOCK_MATERIAL_ICE 0x03 -#define LCR_MAP_COUNT 1 - // normal blocks: -#define LCR_BLOCK_FULL 0x00 ///< completely filled block -#define LCR_BLOCK_BOTTOM 0x01 ///< filled bottom half -#define LCR_BLOCK_LEFT 0x02 ///< filled left half -#define LCR_BLOCK_BOTTOM_LEFT 0x03 ///< filled bottom left quarter -#define LCR_BLOCK_BOTTOM_LEFT_FRONT 0x04 ///< filled bottom left front eigth -#define LCR_BLOCK_RAMP 0x05 ///< plain ramp -#define LCR_BLOCK_RAMP_34 0x06 ///< plain ramp, 3/4 size -#define LCR_BLOCK_RAMP_12 0x07 ///< plain ramp, 1/2 size -#define LCR_BLOCK_RAMP_14 0x08 ///< plain ramp, 1/4 size -#define LCR_BLOCK_RAMP_CURVED_PLAT 0x09 ///< curved ramp with top platgform -#define LCR_BLOCK_RAMP_CURVED 0x0a ///< curv. ramp without top platf. -#define LCR_BLOCK_RAMP_CURVED_WALL 0x0b ///< curved ramp plus small wall -#define LCR_BLOCK_RAMP_STEEP 0x0c ///< extremely steep ramp -#define LCR_BLOCK_CORNER 0x0d ///< diagonal corner -#define LCR_BLOCK_CORNER_12 0x0e ///< diagonal corner (1/2 wide) +#define LCR_BLOCK_FULL 0x00 ///< completely filled block +#define LCR_BLOCK_BOTTOM 0x01 ///< filled bottom half +#define LCR_BLOCK_LEFT 0x02 ///< filled left half +#define LCR_BLOCK_BOTTOM_LEFT 0x03 ///< filled bottom left quarter +#define LCR_BLOCK_BOTTOM_LEFT_FRONT 0x04 ///< filled bottom left front eigth +#define LCR_BLOCK_RAMP 0x05 ///< plain ramp +#define LCR_BLOCK_RAMP_34 0x06 ///< plain ramp, 3/4 size +#define LCR_BLOCK_RAMP_12 0x07 ///< plain ramp, 1/2 size +#define LCR_BLOCK_RAMP_14 0x08 ///< plain ramp, 1/4 size +#define LCR_BLOCK_RAMP_CURVED_PLAT 0x09 ///< curved ramp with top platgform +#define LCR_BLOCK_RAMP_CURVED 0x0a ///< curv. ramp without top platf. +#define LCR_BLOCK_RAMP_CURVED_WALL 0x0b ///< curved ramp plus small wall +#define LCR_BLOCK_RAMP_STEEP 0x0c ///< extremely steep ramp +#define LCR_BLOCK_CORNER 0x0d ///< diagonal corner +#define LCR_BLOCK_CORNER_12 0x0e ///< diagonal corner (1/2 wide) +#define LCR_BLOCK_FULL_ACCEL 0x20 +#define LCR_BLOCK_FULL_FAN 0x30 +#define LCR_BLOCK_CHECKPOINT_0 0x40 ///< checkpoint, not taken +#define LCR_BLOCK_CHECKPOINT_1 0x41 ///< checkpoint, taken + +#define LCR_BLOCK_FINISH 0x42 ///< finish + +// special blocks: +#define LCR_BLOCK_NONE 0x80 ///< no block, e.g to make holes + +#define LCR_BLOCK_CUBOID_FILL 0x81 /**< makes a cuboid from the + previously specified block, the + size is given by block coords */ +#define LCR_BLOCK_CUBOID_HOLLOW 0x82 /**< same as cuboid special block, + but makes a hollow one */ +#define LCR_BLOCK_START 0x83 ///< specifies start block position /* TODO: @@ -96,21 +146,7 @@ - bumpy road */ -#define LCR_BLOCK_FULL_ACCEL 0x20 -#define LCR_BLOCK_FULL_FAN 0x30 -#define LCR_BLOCK_CHECKPOINT_0 0x40 ///< checkpoint, not taken -#define LCR_BLOCK_CHECKPOINT_1 0x41 ///< checkpoint, taken -#define LCR_BLOCK_FINISH 0x42 ///< finish - -// special blocks: -#define LCR_BLOCK_NONE 0x80 ///< no block, e.g to make holes -#define LCR_BLOCK_CUBOID_FILL 0x81 /**< makes a cuboid from the - previously specified block, the - size is given by block coords */ -#define LCR_BLOCK_CUBOID_HOLLOW 0x82 /**< same as cuboid special block, - but makes a hollow one */ -#define LCR_BLOCK_START 0x83 ///< specifies start block position #define LCR_MAP_BLOCK_CACHE_SIZE (8 * 2) /// do not change @@ -134,26 +170,6 @@ struct // TODO: name, desc? possibly as a single '\n' separated string? } LCR_currentMap; -static const uint8_t LCR_map0[] = -{ - LCR_MAP_MAGIC_NUMBER, - 77, 48, 10, // map name: M0 - 10, // map comment: - - LCR_MAP_BLOCK( LCR_BLOCK_NONE, 3, 0, 0, LCR_BLOCK_MATERIAL_CONCRETE, 0), - LCR_MAP_BLOCK( LCR_BLOCK_FULL, 3, 0, 0, LCR_BLOCK_MATERIAL_CONCRETE, 0), - LCR_MAP_BLOCK( LCR_BLOCK_FULL, 0, 1, 0, LCR_BLOCK_MATERIAL_CONCRETE, 0), - LCR_MAP_BLOCK( LCR_BLOCK_FULL, 2, 0, 0, LCR_BLOCK_MATERIAL_CONCRETE, 0), - LCR_MAP_BLOCK( LCR_BLOCK_FULL, 0, 1, 0, LCR_BLOCK_MATERIAL_CONCRETE, 0), - LCR_MAP_BLOCK( LCR_BLOCK_FULL, 3, 0, 0, LCR_BLOCK_MATERIAL_CONCRETE, 0), - LCR_MAP_TERMINATOR -}; - -static const uint8_t *LCR_maps[LCR_MAP_COUNT] = -{ - LCR_map0 -}; - void LCR_makeMapBlock(uint8_t type, uint8_t x, uint8_t y, uint8_t z, uint8_t material, uint8_t transform, uint8_t block[LCR_BLOCK_SIZE]) { @@ -252,14 +268,17 @@ uint8_t *LCR_getMapBlockAtCoordNumber(uint32_t coord) /** Adds given block to current map, including possibly deleting a block by adding LCR_BLOCK_NONE. The function handles sorting the block to the right - position. Returns 1 on success, else 0. + position. Returns pointer to the block on success, else 0. */ -uint8_t _LCR_mapAddBlock(const uint8_t block[LCR_BLOCK_SIZE]) +uint8_t *_LCR_mapAddBlock(const uint8_t block[LCR_BLOCK_SIZE]) { LCR_LOG2("adding map block"); if (LCR_currentMap.blockCount >= LCR_SETTING_MAP_MAX_BLOCKS) + { + LCR_LOG0("couldn't add block"); return 0; + } uint32_t coord = LCR_mapBlockGetCoordNumber(block); uint16_t insertAt = 0; @@ -269,6 +288,8 @@ uint8_t _LCR_mapAddBlock(const uint8_t block[LCR_BLOCK_SIZE]) insertAt * LCR_BLOCK_SIZE)) insertAt++; + uint8_t *result = LCR_currentMap.blocks + insertAt * LCR_BLOCK_SIZE; + if (block[0] == LCR_BLOCK_NONE) { if (insertAt < LCR_currentMap.blockCount && @@ -283,7 +304,7 @@ uint8_t _LCR_mapAddBlock(const uint8_t block[LCR_BLOCK_SIZE]) LCR_currentMap.blockCount--; } - return 1; + return result; } if (insertAt == LCR_currentMap.blockCount || @@ -306,7 +327,7 @@ uint8_t _LCR_mapAddBlock(const uint8_t block[LCR_BLOCK_SIZE]) for (uint8_t j = 0; j < LCR_BLOCK_SIZE; ++j) LCR_currentMap.blocks[insertAt + j] = block[j]; - return 1; + return result; } /** @@ -321,9 +342,265 @@ void LCR_mapReset(void) LCR_currentMap.blocks[i * LCR_BLOCK_SIZE] = LCR_BLOCK_CHECKPOINT_0; } + +uint8_t _LCR_mapCharToBlockType(char c) +{ + switch (c) + { + case '=': return LCR_BLOCK_FULL; break; + case '-': return LCR_BLOCK_BOTTOM; break; + case ';': return LCR_BLOCK_LEFT; break; + case ',': return LCR_BLOCK_BOTTOM_LEFT; break; + case '.': return LCR_BLOCK_BOTTOM_LEFT_FRONT; break; + case '^': return LCR_BLOCK_RAMP; break; + case '/': return LCR_BLOCK_RAMP_34; break; + case '<': return LCR_BLOCK_RAMP_12; break; + case '_': return LCR_BLOCK_RAMP_14; break; + case ']': return LCR_BLOCK_RAMP_CURVED_PLAT; break; + case ')': return LCR_BLOCK_RAMP_CURVED; break; + case '}': return LCR_BLOCK_RAMP_CURVED_WALL; break; + case '|': return LCR_BLOCK_RAMP_STEEP; break; + case 'A': return LCR_BLOCK_CORNER; break; + case '\\': return LCR_BLOCK_CORNER_12; break; + case '>': return LCR_BLOCK_FULL_ACCEL; break; + case 'o': return LCR_BLOCK_FULL_FAN; break; + case '+': return LCR_BLOCK_CHECKPOINT_0; break; + case '!': return LCR_BLOCK_FINISH; break; + case 'x': return LCR_BLOCK_NONE; break; + case 'f': return LCR_BLOCK_CUBOID_FILL; break; + case 'h': return LCR_BLOCK_CUBOID_HOLLOW; break; + case '*': return LCR_BLOCK_START; break; + default: + LCR_LOG1("unknown block char"); + return LCR_BLOCK_NONE; break; + } +} + +int _LCR_mapCharToCoord(char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + + if (c >= 'a' && c <= 'z') + return c - 'a' + 10; + + if (c >= 'A' && c <= 'Z') + return c - 'A' + 36; + + if (c == '@') + return 62; + + if (c == '&') + return 63; + + return -1; +} + +uint8_t LCR_mapLoadFromStr(const char *mapStr) +{ + LCR_LOG0("loading map string"); + + const uint8_t *prevBlock = 0; + + for (int i = 0; i < 4; ++i) + LCR_currentMap.startPos[i] = 0; + + LCR_currentMap.checkpointCount = 0; + LCR_currentMap.blockCount = 0; + LCR_currentMap.environment = 0; + + if (mapStr[0] != LCR_MAP_MAGIC_NUMBER1 || mapStr[1] != LCR_MAP_MAGIC_NUMBER2 + || mapStr[2] != LCR_MAP_SEPARATOR) + { + LCR_LOG0("bad magic number"); + return 0; + } + + mapStr += 3; + + while (*mapStr != LCR_MAP_SEPARATOR) // read map name + { + if (mapStr[0] == 0) + return 0; + + // TODO + mapStr++; + } + + mapStr++; + + while (*mapStr != LCR_MAP_SEPARATOR) // read map description + { + if (mapStr[0] == 0) + return 0; + + // TODO + mapStr++; + } + + mapStr++; + + while (*mapStr != LCR_MAP_SEPARATOR) // read map tags + { + if (mapStr[0] >= '0' && mapStr[0] <= '9') + LCR_currentMap.environment = mapStr[0] - '0'; + else if (mapStr[0] == 0) + return 0; + + // TODO + mapStr++; + } + + mapStr++; + + while (*mapStr) + { + if (*mapStr == '#') + { + mapStr++; + + uint8_t block = _LCR_mapCharToBlockType(*mapStr); + uint8_t trans = 0; + uint8_t mat = 0; + int coords[3]; + + for (int i = 0; i < 3; ++i) + { + mapStr++; + coords[i] = _LCR_mapCharToCoord(*mapStr); + + if (coords[i] < 0) + { + LCR_LOG0("bad coord"); + return 0; + } + } + + mapStr++; + + if (*mapStr >= '0' && *mapStr <= '3') + mat = *mapStr - '0'; + else + { + LCR_LOG0("bad material"); + return 0; + } + + mapStr++; + + while (1) + { + if (*mapStr == '|') + trans |= LCR_BLOCK_TRANSFORM_FLIP_H; + else if (*mapStr == '-') + trans |= LCR_BLOCK_TRANSFORM_FLIP_V; + else if (*mapStr == 'L') + trans |= LCR_BLOCK_TRANSFORM_ROT_90; + else if (*mapStr == 'I') + trans |= LCR_BLOCK_TRANSFORM_ROT_180; + else if (*mapStr == 'J') + trans |= LCR_BLOCK_TRANSFORM_ROT_270; + else + break; + + mapStr++; + } + + switch (block) + { + case LCR_BLOCK_CUBOID_FILL: + case LCR_BLOCK_CUBOID_HOLLOW: + { + uint8_t x, y, z, mat, transform; + uint8_t tmpBlock[LCR_BLOCK_SIZE]; + + if (prevBlock == 0 || LCR_currentMap.blockCount == 0) + { + LCR_LOG0("no previous block"); + return 0; + } + + mat = LCR_mapBlockGetMaterial(prevBlock); + transform = LCR_mapBlockGetTransform(prevBlock); + LCR_mapBlockGetCoords(prevBlock,&x,&y,&z); + + for (uint8_t k = 0; k < coords[2]; ++k) + for (uint8_t j = 0; j < coords[1]; ++j) + for (uint8_t i = 0; i < coords[0]; ++i) + if (block == LCR_BLOCK_CUBOID_FILL || + k == 0 || k == coords[2] - 1 || + j == 0 || j == coords[1] - 1 || + i == 0 || i == coords[0] - 1) + { + LCR_makeMapBlock(prevBlock[0],x + i,y + j,z + k,mat,transform, + tmpBlock); + + prevBlock = _LCR_mapAddBlock(tmpBlock); + + if (!prevBlock) + return 0; + } + + break; + } + + case LCR_BLOCK_START: + LCR_currentMap.startPos[0] = coords[0]; + LCR_currentMap.startPos[1] = coords[1]; + LCR_currentMap.startPos[2] = coords[2]; + LCR_currentMap.startPos[3] = trans & 0x60; + break; + + case LCR_BLOCK_CHECKPOINT_0: + LCR_currentMap.checkpointCount++; + // fall through + default: // normal block + { + uint8_t tmpBlock[LCR_BLOCK_SIZE]; + + LCR_makeMapBlock(block,coords[0],coords[1],coords[2],mat,trans, + tmpBlock); + + prevBlock = _LCR_mapAddBlock(tmpBlock); + + if (prevBlock == 0) + return 0; + + break; + } + } + } + + if (*mapStr != '#') + mapStr++; + } + + LCR_LOG2("clearing map block cache") + + for (int i = 0; i < LCR_MAP_BLOCK_CACHE_SIZE; ++i) + _LCR_mapBlockCache[i] = 0xffffffff; + + LCR_LOG2("map loaded") + + LCR_mapReset(); + + return 1; +} + + + + + + + + + + /** Loads and preprocesses given map. Returns 1 on success, otherwise 0. */ + +/* uint8_t LCR_mapLoad(const uint8_t *map) { LCR_LOG0("loading map") @@ -430,6 +707,13 @@ uint8_t LCR_mapLoad(const uint8_t *map) return 1; } +*/ + + + + + + /** Same as LCR_mapGetBlockAt, but allows to specify start and end block of the of the search to make it faster. diff --git a/racing.h b/racing.h index d95946b..facfea8 100644 --- a/racing.h +++ b/racing.h @@ -430,10 +430,6 @@ LCR_racing.carNotOKCount = 0; // TODO } - - - - /** Initializes the racing module, only call once. */ @@ -468,8 +464,6 @@ void LCR_racingInit(void) function with large min. distance which would lead to slow iteration over all map blocks. */ LCR_racing.carBody.flags |= TPE_BODY_FLAG_NO_BSPHERE; - - LCR_racingRestart(); } /** diff --git a/renderer.h b/renderer.h index 9128e3d..691d87a 100644 --- a/renderer.h +++ b/renderer.h @@ -848,22 +848,9 @@ void LCR_rendererMarkTakenCP(int x, int y, int z) } } -/** - Call to reset currently loaded map, i.e. mark all checkpoints as untaken etc. -*/ -void LCR_rendererRestart(void) +uint8_t LCR_rendererLoadMap(void) { - for (int i = 0; i < LCR_renderer.mapModel.triangleCount; ++i) - if ((LCR_renderer.mapTriangleData[i] & 0x0f) == LCR_RENDERER_MAT_CP1) - LCR_renderer.mapTriangleData[i] = (LCR_renderer.mapTriangleData[i] & 0xf0) - | LCR_RENDERER_MAT_CP0; -} - -uint8_t LCR_rendererInit(void) -{ - LCR_LOG0("initializing renderer"); - - LCR_renderer.frame = 0; + LCR_LOG0("loading map"); if (!_LCR_buildMapModel()) return 0; @@ -871,6 +858,18 @@ uint8_t LCR_rendererInit(void) _LCR_makeMapChunks(); _LCR_rendererComputeLOD(); + return 1; +} + +/** + Initializes renderer, only call once. +*/ +uint8_t LCR_rendererInit(void) +{ + LCR_LOG0("initializing renderer"); + + LCR_renderer.frame = 0; + LCR_renderer.carModel = LCR_renderer.models + 8; LCR_renderer.ghostModel = LCR_renderer.models + 9; @@ -1557,7 +1556,7 @@ void LCR_rendererDraw(void) _LCR_rendererLoadMapChunks(); // TODO: call only once in a while? - LCR_rendererDrawSky(1, + LCR_rendererDrawSky(LCR_currentMap.environment, LCR_renderer.scene.camera.transform.rotation.y, -4 * LCR_renderer.scene.camera.transform.rotation.x);