]> git.lizzy.rs Git - shadowclad.git/blob - src/game/level.c
Rename `Vector3D` to `Vector`
[shadowclad.git] / src / game / level.c
1 #include "level.h"
2
3 #include <stdlib.h>
4 #include <GL/gl.h>
5
6 #include "engine/logger.h"
7 #include "engine/scene.h"
8 #include "engine/tga.h"
9
10 #include "player.h"
11
12 BlockGrid levelGrid;
13
14 static const float BLOCKGRID_CELL_SIZE = 2.5f;
15
16 static Block blockEmpty = { .type = BLOCKTYPE_SPACE,
17                             .solid = NULL };
18 static Block blockWall01 = { .type = BLOCKTYPE_OBSTACLE,
19                              .solid = NULL };
20
21 static Transform playerSpawnTransform;
22
23 static void buildLevelFromImage(const TgaImage* image);
24 static inline Block* getBlockFromGrid(BlockGrid grid, size_t x, size_t z);
25 static inline void setBlockInGrid(BlockGrid grid, size_t x, size_t z, Block* block);
26
27
28
29 void initLevel() {
30         playerSpawnTransform = identity();
31         translate(&playerSpawnTransform, (Vector) { .x = -BLOCKGRID_CELL_SIZE,
32                                                     .y = 0.0f,
33                                                     .z = -BLOCKGRID_CELL_SIZE });
34
35         blockWall01.solid = importSolid("assets/wall01.3ds");
36
37         buildLevelFromImage(readTga("assets/level01.tga"));
38
39         Scene* levelScene = newScene();
40
41         for (size_t z = 0; z < levelGrid.depth; ++z) {
42                 for (size_t x = 0; x < levelGrid.width; ++x) {
43                         Scene* blockScene = newScene();
44                         translate(&blockScene->transform, (Vector) { .x = x * BLOCKGRID_CELL_SIZE,
45                                                                      .y = 0.0f,
46                                                                      .z = z * BLOCKGRID_CELL_SIZE });
47                         blockScene->solid = getBlockFromGrid(levelGrid, x, z)->solid;
48                         insertChildScene(levelScene, blockScene);
49                 }
50         }
51
52         currentScene = levelScene;
53 }
54
55 void startLevel() {
56         spawnPlayer(playerSpawnTransform);
57 }
58
59 static void buildLevelFromImage(const TgaImage* image) {
60         if (image == NULL) {
61                 logError("Null image received, cannot build level");
62                 return;
63         }
64         
65         if (image->header.imageBpp != 32) {
66                 logError("Invalid level image format (%d bpp)", image->header.imageBpp);
67                 return;
68         }
69         
70         BlockGrid newGrid = { .width = image->header.imageWidth,
71                               .depth = image->header.imageHeight,
72                               .blocks = malloc(image->header.imageWidth
73                                                * image->header.imageHeight
74                                                * sizeof(Block*)) };
75         
76         for (size_t row = 0; row < newGrid.depth; ++row) {
77                 for (size_t x = 0; x < newGrid.width; ++x) {
78                         // Flip the image vertically due to (0, 0) being bottom left
79                         size_t z = newGrid.depth - row - 1;
80                         
81                         uint32_t pixelColorARGB = ((uint32_t*) image->bytes)[(row * newGrid.width) + x];
82                         Block* block;
83                         switch (pixelColorARGB) {
84                                 case 0xFFFF0000:
85                                         block = &blockWall01;
86                                         break;
87                                 case 0xFF00FFFF:
88                                         block = &blockEmpty;
89                                         playerSpawnTransform = identity();
90                                         translate(&playerSpawnTransform, (Vector) { .x = x * BLOCKGRID_CELL_SIZE,
91                                                                                     .y = 0.0f,
92                                                                                     .z = z * BLOCKGRID_CELL_SIZE });
93                                         break;
94                                 default:
95                                         block = &blockEmpty;
96                                         break;
97                         }
98                         setBlockInGrid(newGrid, x, z, block);
99                 }
100         }
101         
102         levelGrid = newGrid;
103 }
104
105 static inline Block* getBlockFromGrid(BlockGrid grid, size_t x, size_t z) {
106         return grid.blocks[(z * grid.width) + x];
107 }
108
109 static inline void setBlockInGrid(BlockGrid grid, size_t x, size_t z, Block* block) {
110         grid.blocks[(z * grid.width) + x] = block;
111 }