summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.c149
1 files changed, 118 insertions, 31 deletions
diff --git a/src/main.c b/src/main.c
index dcd0335..225af5f 100644
--- a/src/main.c
+++ b/src/main.c
@@ -31,9 +31,13 @@ static constexpr R Fovy = (R)(90 * TO_RAD);
31static constexpr R Near = 0.1f; 31static constexpr R Near = 0.1f;
32static constexpr R Far = 100.0f; 32static constexpr R Far = 100.0f;
33 33
34#define DEBUG_EVENT_LOOP 1 34static constexpr size_t MaxTextures = 256;
35 35
36#ifdef DEBUG_EVENT_LOOP 36static const char* StateFile = "game.bin";
37
38#define DEBUG_EVENT_LOOP 0
39
40#if DEBUG_EVENT_LOOP
37#define EVENT_LOOP_PRINT printf 41#define EVENT_LOOP_PRINT printf
38#else 42#else
39#define EVENT_LOOP_PRINT(...) 43#define EVENT_LOOP_PRINT(...)
@@ -68,13 +72,55 @@ typedef struct State {
68 SDL_Window* window; 72 SDL_Window* window;
69 void* gfx_mem; 73 void* gfx_mem;
70 swgfx* gfx; 74 swgfx* gfx;
71 Model* model;
72 sgImage texture;
73 Camera camera; 75 Camera camera;
74 CameraController camera_controller; 76 CameraController camera_controller;
75 Uint64 last_tick; 77 Uint64 last_tick;
78 Model* model;
79 size_t numTextures;
80 sgImage textures[MaxTextures];
76} State; 81} State;
77 82
83static bool StateWrite(const State* state, FILE* file) {
84 assert(state);
85 assert(file);
86 return fwrite(&state->camera, sizeof(state->camera), 1, file) == 1;
87}
88
89static bool StateRead(FILE* file, State* state) {
90 assert(file);
91 assert(state);
92 Camera camera;
93 if (fread(&camera, sizeof(camera), 1, file) != 1) {
94 return false;
95 }
96 state->camera = camera;
97 return true;
98}
99
100static bool StateSave(const State* state, const char* path) {
101 assert(state);
102 assert(path);
103 FILE* file = fopen(path, "wb");
104 if (!file) {
105 return false;
106 }
107 const bool result = StateWrite(state, file);
108 fclose(file);
109 return result;
110}
111
112static bool StateLoad(const char* path, State* state) {
113 assert(path);
114 assert(state);
115 FILE* file = fopen(path, "rb");
116 if (!file) {
117 return false;
118 }
119 const bool result = StateRead(file, state);
120 fclose(file);
121 return result;
122}
123
78static sgVec3 SgVec3FromMathVec3(vec3 v) { 124static sgVec3 SgVec3FromMathVec3(vec3 v) {
79 return (sgVec3){v.x, v.y, v.z}; 125 return (sgVec3){v.x, v.y, v.z};
80} 126}
@@ -82,8 +128,9 @@ static sgVec3 SgVec3FromMathVec3(vec3 v) {
82static CameraCommand CameraCommandFromInput( 128static CameraCommand CameraCommandFromInput(
83 const bool* keyboard_state, const SDL_MouseButtonFlags mouse_flags) { 129 const bool* keyboard_state, const SDL_MouseButtonFlags mouse_flags) {
84 assert(keyboard_state); 130 assert(keyboard_state);
85 if (keyboard_state[SDL_SCANCODE_W]) { 131 // Control is used for save/load/quit, etc.
86 printf("W: %d\n", keyboard_state[SDL_SCANCODE_W]); 132 if (keyboard_state[SDL_SCANCODE_LCTRL]) {
133 return (CameraCommand){};
87 } 134 }
88 return (CameraCommand){ 135 return (CameraCommand){
89 .CameraMoveLeft = keyboard_state[SDL_SCANCODE_A], 136 .CameraMoveLeft = keyboard_state[SDL_SCANCODE_A],
@@ -146,22 +193,34 @@ static bool Update(State* state, R dt) {
146 return true; 193 return true;
147} 194}
148 195
149static void RenderIndexedModel(swgfx* gfx, const IndexedModel* model) { 196static void RenderIndexedModel(swgfx* gfx, const IndexedModel* model, const ModelObject* object) {
150 assert(gfx); 197 assert(gfx);
151 assert(model); 198 assert(model);
152 const sgTriIdx* tris = (const sgTriIdx*)(model->data + model->offsetTris); 199 assert(object);
200 assert((object->offset + object->count) <= model->numTris);
201 const sgTriIdx* tris = (const sgTriIdx*)(model->data + model->offsetTris) + object->offset;
153 const sgVec3* positions = (const sgVec3*) (model->data + model->offsetPositions); 202 const sgVec3* positions = (const sgVec3*) (model->data + model->offsetPositions);
154 const sgVec2* texcoords = (const sgVec2*)(model->data + model->offsetTexcoords); 203 const sgVec2* texcoords = (const sgVec2*) (model->data + model->offsetTexcoords);
155 sgTrianglesIndexedNonUniform(gfx, model->numTris, tris, positions, texcoords); 204 sgTrianglesIndexedNonUniform(gfx, object->count, tris, positions, texcoords);
156} 205}
157 206
158static void RenderModel(swgfx* gfx, const Model* model) { 207static void RenderModel(swgfx* gfx, const sgImage* textures, const Model* model) {
159 assert(gfx); 208 assert(gfx);
209 assert(textures);
160 assert(model); 210 assert(model);
161 switch (model->type) { 211 const ModelObject* objects = modelObjects(model);
162 case ModelTypeIndexed: RenderIndexedModel(gfx, &model->indexed); break; 212 for (size_t i = 0; i < model->numObjects; ++i) {
163 case ModelTypeFlat: /* TODO: Render flat models. */ break; 213 const ModelObject* object = &objects[i];
164 default: assert(false); break; 214 // TODO: This indexing into the textures array assumes that we have loaded a
215 // single model. Generalize later.
216 assert((size_t)object->material < MaxTextures);
217 const sgImage* texture = &textures[object->material];
218 sgTexture(gfx, texture);
219 switch (model->type) {
220 case ModelTypeIndexed: RenderIndexedModel(gfx, &model->indexed, object); break;
221 case ModelTypeFlat: /* TODO: Render flat models. */ break;
222 default: assert(false); break;
223 }
165 } 224 }
166} 225}
167 226
@@ -225,15 +284,19 @@ static bool Render(State* state) {
225 sgModelId(state->gfx); 284 sgModelId(state->gfx);
226 sgView(state->gfx, SgVec3FromMathVec3(cam->spatial.p), SgVec3FromMathVec3(cam->spatial.f)); 285 sgView(state->gfx, SgVec3FromMathVec3(cam->spatial.p), SgVec3FromMathVec3(cam->spatial.f));
227 sgPerspective(state->gfx, cam->fovy, cam->aspect, cam->near, cam->far); 286 sgPerspective(state->gfx, cam->fovy, cam->aspect, cam->near, cam->far);
228 sgTexture(state->gfx, &state->texture); 287 RenderModel(state->gfx, state->textures, state->model);
229 RenderModel(state->gfx, state->model); 288 /*const sgIdx indices[3] = {0, 1, 2};
230 /*sgIdx indices[3] = {0, 1, 2}; 289 const sgVec3 positions[3] = {
231 sgVec3 positions[3] = {
232 (sgVec3){0, 0, 0}, 290 (sgVec3){0, 0, 0},
233 (sgVec3){5, 2, 0}, 291 (sgVec3){5, 2, 0},
234 (sgVec3){8, 8, 0}, 292 (sgVec3){8, 8, 0},
235 }; 293 };
236 sgTrianglesIndexed(state->gfx, 3, indices, positions);*/ 294 const sgVec2 texcoords[3] = {
295 (sgVec2){0, 0},
296 (sgVec2){0.5, 0.5},
297 (sgVec2){1.0, 1.0},
298 };
299 sgTrianglesIndexed(state->gfx, 3, indices, positions, texcoords);*/
237 sgPresent(state->gfx, WindowDims, window_surface->pixels); 300 sgPresent(state->gfx, WindowDims, window_surface->pixels);
238 301
239 if (!SDL_UpdateWindowSurface(state->window)) { 302 if (!SDL_UpdateWindowSurface(state->window)) {
@@ -284,23 +347,28 @@ static bool Initialize(State* state) {
284 return false; 347 return false;
285 } 348 }
286 349
287 const char* model_path = "/home/jeanne/blender/box_textured.mdl"; 350 const char* model_path = "/home/jeanne/blender/boxout.mdl";
288 if (!(state->model = read_file(model_path))) { 351 if (!(state->model = read_file(model_path))) {
289 fprintf(stderr, "Failed to load model: [%s]\n", model_path); 352 fprintf(stderr, "Failed to load model: [%s]\n", model_path);
290 return false; 353 return false;
291 } 354 }
292 if (state->model->material.diffuseTexture[0] != 0) { 355 if ((size_t)state->model->numMaterials > MaxTextures) {
356 fprintf(stderr, "Model material count is larger than max textures, increase limit\n");
357 return false;
358 }
359 const ModelMaterial* materials = modelMaterials(state->model);
360 for (size_t i = 0; i < state->model->numMaterials; ++i) {
361 const ModelMaterial* material = &materials[i];
293 // TODO: When doing lighting, need to gamma-correct here. 362 // TODO: When doing lighting, need to gamma-correct here.
294 sgImage texture = {0}; 363 sgImage* texture = &state->textures[state->numTextures++];
295 int channels = 0; 364 int channels = 0;
296 constexpr int desired_channels = 4; 365 constexpr int desired_channels = 4;
297 texture.pixels = (sgPixel*)stbi_load(state->model->material.diffuseTexture, &texture.width, &texture.height, &channels, desired_channels); 366 texture->pixels = (sgPixel*)stbi_load(material->diffuseTexture, &texture->width, &texture->height, &channels, desired_channels);
298 if (!texture.pixels) { 367 if (!texture->pixels) {
299 fprintf(stderr, "Failed to read texture: [%s]\n", state->model->material.diffuseTexture); 368 fprintf(stderr, "Failed to read texture: [%s]\n", material->diffuseTexture);
300 return false; 369 return false;
301 } 370 }
302 assert(channels == desired_channels); 371 assert(channels == desired_channels);
303 state->texture = texture;
304 } 372 }
305 373
306 Camera* camera = &state->camera; 374 Camera* camera = &state->camera;
@@ -324,16 +392,19 @@ static bool Initialize(State* state) {
324static void Shutdown(State* state) { 392static void Shutdown(State* state) {
325 assert(state); 393 assert(state);
326 394
327 if (state->texture.pixels) { 395 for (size_t i = 0; i < state->numTextures; ++i) {
328 free(state->texture.pixels); 396 sgImage* texture = &state->textures[i];
329 state->texture = (sgImage){0}; 397 if (texture->pixels) {
398 free(texture->pixels);
399 *texture = (sgImage){0};
400 }
330 } 401 }
331 402
332 if (state->model) { 403 if (state->model) {
333 free(state->model); 404 free(state->model);
334 state->model = nullptr; 405 state->model = nullptr;
335 } 406 }
336 407
337 if (state->gfx) { 408 if (state->gfx) {
338 sgDel(&state->gfx); 409 sgDel(&state->gfx);
339 } 410 }
@@ -412,6 +483,22 @@ int main() {
412 case SDLK_D: 483 case SDLK_D:
413 running = false; 484 running = false;
414 break; 485 break;
486 // Save state.
487 case SDLK_S:
488 if (StateSave(&state, StateFile)) {
489 fprintf(stderr, "State saved\n");
490 } else {
491 fprintf(stderr, "Failed to save state\n");
492 }
493 break;
494 // Load state.
495 case SDLK_L:
496 if (StateLoad(StateFile, &state)) {
497 fprintf(stderr, "State loaded\n");
498 } else {
499 fprintf(stderr, "Failed to load state\n");
500 }
501 break;
415 default: 502 default:
416 break; 503 break;
417 } 504 }