mirror of
https://github.com/luksamuk/engine-psx.git
synced 2025-04-28 13:28:02 +03:00
Load common object table and object placement data
This commit is contained in:
parent
5812d18f13
commit
d296245b32
11 changed files with 423 additions and 24 deletions
|
@ -4,6 +4,8 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <psxgpu.h>
|
#include <psxgpu.h>
|
||||||
|
|
||||||
|
#include "object_state.h"
|
||||||
|
|
||||||
#define LEVEL_MAX_X_CHUNKS 255
|
#define LEVEL_MAX_X_CHUNKS 255
|
||||||
#define LEVEL_MAX_Y_CHUNKS 31
|
#define LEVEL_MAX_Y_CHUNKS 31
|
||||||
#define LEVEL_ARENA_SIZE 131072
|
#define LEVEL_ARENA_SIZE 131072
|
||||||
|
@ -51,10 +53,18 @@ typedef struct {
|
||||||
uint16_t *tiles;
|
uint16_t *tiles;
|
||||||
} LevelLayerData;
|
} LevelLayerData;
|
||||||
|
|
||||||
|
#define MAX_OBJECTS_PER_CHUNK 15
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t num_objects;
|
||||||
|
ObjectState objects[MAX_OBJECTS_PER_CHUNK];
|
||||||
|
} ChunkObjectData;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t num_layers;
|
uint8_t num_layers;
|
||||||
uint8_t _unused0;
|
uint8_t _unused0;
|
||||||
LevelLayerData *layers;
|
LevelLayerData *layers;
|
||||||
|
ChunkObjectData **objects;
|
||||||
|
|
||||||
uint16_t crectx, crecty;
|
uint16_t crectx, crecty;
|
||||||
uint16_t prectx, precty;
|
uint16_t prectx, precty;
|
||||||
|
@ -75,4 +85,7 @@ void render_lvl(
|
||||||
int32_t cam_x, int32_t cam_y);
|
int32_t cam_x, int32_t cam_y);
|
||||||
|
|
||||||
|
|
||||||
|
// Object-related. These are defined in object_state.c
|
||||||
|
void load_object_placement(const char *filename, LevelData *lvl);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -2,22 +2,23 @@
|
||||||
#define MEMALLOC_H
|
#define MEMALLOC_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t start;
|
uintptr_t start;
|
||||||
uint32_t ptr;
|
uintptr_t ptr;
|
||||||
uint32_t size;
|
size_t size;
|
||||||
} ArenaAllocator;
|
} ArenaAllocator;
|
||||||
|
|
||||||
void alloc_arena_init(ArenaAllocator *arena, void *start, uint32_t size);
|
void alloc_arena_init(ArenaAllocator *arena, void *start, uintptr_t size);
|
||||||
void alloc_arena_free(ArenaAllocator *arena);
|
void alloc_arena_free(ArenaAllocator *arena);
|
||||||
void *alloc_arena_malloc(ArenaAllocator *arena, uint32_t size);
|
void *alloc_arena_malloc(ArenaAllocator *arena, size_t size);
|
||||||
|
|
||||||
uint32_t alloc_arena_bytes_used(ArenaAllocator *arena);
|
uint32_t alloc_arena_bytes_used(ArenaAllocator *arena);
|
||||||
uint32_t alloc_arena_bytes_free(ArenaAllocator *arena);
|
uint32_t alloc_arena_bytes_free(ArenaAllocator *arena);
|
||||||
|
|
||||||
void fastalloc_init();
|
void fastalloc_init();
|
||||||
void fastalloc_free();
|
void fastalloc_free();
|
||||||
void *fastalloc_malloc(uint32_t size);
|
void *fastalloc_malloc(size_t size);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef OBJECT_H
|
#ifndef MODEL_H
|
||||||
#define OBJECT_H
|
#define MODEL_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <psxgpu.h>
|
#include <psxgpu.h>
|
||||||
|
|
89
include/object.h
Normal file
89
include/object.h
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
#ifndef OBJECT_H
|
||||||
|
#define OBJECT_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "level.h"
|
||||||
|
|
||||||
|
/* ======================== */
|
||||||
|
/* OBJECT PROPERTY DATA */
|
||||||
|
/* ======================== */
|
||||||
|
|
||||||
|
typedef enum int8_t {
|
||||||
|
// Dummy objects
|
||||||
|
OBJ_DUMMY_RINGS_3V = -2,
|
||||||
|
OBJ_DUMMY_RINGS_3H = -1,
|
||||||
|
|
||||||
|
// Actual objects
|
||||||
|
OBJ_RING = 0x00,
|
||||||
|
OBJ_MONITOR = 0x01,
|
||||||
|
OBJ_SPIKES = 0x02,
|
||||||
|
OBJ_CHECKPOINT = 0x03,
|
||||||
|
OBJ_SPRING_YELLOW = 0x04,
|
||||||
|
OBJ_SPRING_RED = 0x05,
|
||||||
|
OBJ_SPRING_YELLOW_DIAGONAL = 0x06,
|
||||||
|
OBJ_SPRING_RED_DIAGONAL = 0x07,
|
||||||
|
OBJ_GOAL_SIGN = 0x08,
|
||||||
|
OBJ_SWITCH = 0x09,
|
||||||
|
} ObjectType;
|
||||||
|
|
||||||
|
#define MASK_FLIP_FLIPX 0x1 // Flip on X axis
|
||||||
|
#define MASK_FLIP_FLIPY 0x2 // Flip on Y axis
|
||||||
|
#define MASK_FLIP_ROTCW 0x4 // Rotated clockwise
|
||||||
|
#define MASK_FLIP_ROTCT 0x8 // Rotated counterclockwise
|
||||||
|
|
||||||
|
typedef enum uint8_t {
|
||||||
|
MONITOR_KIND_NONE = 0,
|
||||||
|
MONITOR_KIND_RING = 1,
|
||||||
|
MONITOR_KIND_SPEEDSHOES = 2,
|
||||||
|
MONITOR_KIND_SHIELD = 3,
|
||||||
|
MONITOR_KIND_INVINCIBILITY = 4,
|
||||||
|
MONITOR_KIND_1UP = 5,
|
||||||
|
MONITOR_KIND_SUPER = 6,
|
||||||
|
} ObjectMonitorKind;
|
||||||
|
|
||||||
|
|
||||||
|
/* ======================== */
|
||||||
|
/* OBJECT TABLE STRUCTURE */
|
||||||
|
/* ======================== */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t u0, v0;
|
||||||
|
uint8_t w, h;
|
||||||
|
uint8_t flipmask;
|
||||||
|
} ObjectAnimFrame;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ObjectAnimFrame *frames;
|
||||||
|
uint16_t num_frames;
|
||||||
|
int8_t loopback;
|
||||||
|
// TODO: number of animation frames?
|
||||||
|
} ObjectAnim;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int16_t offsetx, offsety;
|
||||||
|
ObjectAnim *animations;
|
||||||
|
uint16_t num_animations;
|
||||||
|
} ObjectFrag;
|
||||||
|
|
||||||
|
// TODO: ObjectAnimState
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ObjectAnim *animations;
|
||||||
|
ObjectFrag *fragment;
|
||||||
|
// TODO: Global animation state here, could be NULL
|
||||||
|
uint16_t num_animations;
|
||||||
|
} ObjectTableEntry;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t is_level_specific;
|
||||||
|
uint16_t num_entries;
|
||||||
|
ObjectTableEntry *entries;
|
||||||
|
} ObjectTable;
|
||||||
|
|
||||||
|
|
||||||
|
void load_object_table(const char *filename, ObjectTable *tbl);
|
||||||
|
void unload_object_table(ObjectTable *tbl);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
22
include/object_state.h
Normal file
22
include/object_state.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef OBJECT_STATE_H
|
||||||
|
#define OBJECT_STATE_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* ======================== */
|
||||||
|
/* OBJECT STATE STRUCTURE */
|
||||||
|
/* ======================== */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t kind;
|
||||||
|
} MonitorExtra;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t id;
|
||||||
|
uint8_t flipmask;
|
||||||
|
uint8_t props;
|
||||||
|
int16_t rx, ry; // Positions relative to chunk top-left corner
|
||||||
|
void *extra;
|
||||||
|
} ObjectState;
|
||||||
|
|
||||||
|
#endif
|
14
src/level.c
14
src/level.c
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
#define MAX_TILES 1400
|
#define MAX_TILES 1400
|
||||||
|
|
||||||
static ArenaAllocator _level_arena = { 0 };
|
ArenaAllocator _level_arena = { 0 };
|
||||||
static uint8_t _arena_mem[LEVEL_ARENA_SIZE];
|
static uint8_t _arena_mem[LEVEL_ARENA_SIZE];
|
||||||
|
|
||||||
extern int debug_mode;
|
extern int debug_mode;
|
||||||
|
@ -174,18 +174,23 @@ load_lvl(LevelData *lvl, const char *filename)
|
||||||
lvl->num_layers = get_byte(bytes, &b);
|
lvl->num_layers = get_byte(bytes, &b);
|
||||||
lvl->_unused0 = 0; b += 1;
|
lvl->_unused0 = 0; b += 1;
|
||||||
|
|
||||||
|
uint16_t max_tiles = 0;
|
||||||
|
|
||||||
lvl->layers = alloc_arena_malloc(&_level_arena, lvl->num_layers * sizeof(LevelLayerData));
|
lvl->layers = alloc_arena_malloc(&_level_arena, lvl->num_layers * sizeof(LevelLayerData));
|
||||||
for(uint8_t n_layer = 0; n_layer < lvl->num_layers; n_layer++) {
|
for(uint8_t n_layer = 0; n_layer < lvl->num_layers; n_layer++) {
|
||||||
LevelLayerData *layer = &lvl->layers[n_layer];
|
LevelLayerData *layer = &lvl->layers[n_layer];
|
||||||
layer->width = get_byte(bytes, &b);
|
layer->width = get_byte(bytes, &b);
|
||||||
layer->height = get_byte(bytes, &b);
|
layer->height = get_byte(bytes, &b);
|
||||||
uint16_t num_tiles = (uint16_t)layer->width * (uint16_t)layer->height;
|
uint16_t num_tiles = (uint16_t)layer->width * (uint16_t)layer->height;
|
||||||
|
if(num_tiles > max_tiles) max_tiles = num_tiles;
|
||||||
layer->tiles = alloc_arena_malloc(&_level_arena, num_tiles * sizeof(uint16_t));
|
layer->tiles = alloc_arena_malloc(&_level_arena, num_tiles * sizeof(uint16_t));
|
||||||
for(uint16_t i = 0; i < num_tiles; i++) {
|
for(uint16_t i = 0; i < num_tiles; i++) {
|
||||||
layer->tiles[i] = get_short_be(bytes, &b);
|
layer->tiles[i] = get_short_be(bytes, &b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(bytes);
|
||||||
|
|
||||||
// These values are static because we're always using the same
|
// These values are static because we're always using the same
|
||||||
// coordinates for tpage and clut info. For some reason they're
|
// coordinates for tpage and clut info. For some reason they're
|
||||||
// not loading correctly, but we don't really need them
|
// not loading correctly, but we don't really need them
|
||||||
|
@ -196,7 +201,12 @@ load_lvl(LevelData *lvl, const char *filename)
|
||||||
//lvl->clutmode = 0; // NOTE: This was set to tim->mode previously.
|
//lvl->clutmode = 0; // NOTE: This was set to tim->mode previously.
|
||||||
lvl->_unused1 = 0;
|
lvl->_unused1 = 0;
|
||||||
|
|
||||||
free(bytes);
|
// Initialize object state array within level map
|
||||||
|
printf("Allocating object array\n");
|
||||||
|
lvl->objects = alloc_arena_malloc(&_level_arena, max_tiles * sizeof(ChunkObjectData *));
|
||||||
|
for(uint16_t i = 0; i < max_tiles; i++) {
|
||||||
|
lvl->objects[i] = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Level sprite buffer.
|
// Level sprite buffer.
|
||||||
|
|
|
@ -7,11 +7,12 @@ ArenaAllocator scratchpad_arena;
|
||||||
#define SCRATCHPAD_SIZE 1024
|
#define SCRATCHPAD_SIZE 1024
|
||||||
|
|
||||||
void
|
void
|
||||||
alloc_arena_init(ArenaAllocator *arena, void *start, uint32_t size)
|
alloc_arena_init(ArenaAllocator *arena, void *start, size_t size)
|
||||||
{
|
{
|
||||||
arena->start = (uint32_t)start;
|
uintptr_t st = (uintptr_t)start;
|
||||||
|
arena->start = st;
|
||||||
arena->ptr = arena->start;
|
arena->ptr = arena->start;
|
||||||
arena->size = (uint32_t)size;
|
arena->size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -21,12 +22,19 @@ alloc_arena_free(ArenaAllocator *arena)
|
||||||
}
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
alloc_arena_malloc(ArenaAllocator *arena, uint32_t size)
|
alloc_arena_malloc(ArenaAllocator *arena, size_t size)
|
||||||
{
|
{
|
||||||
void *p = (void *)arena->ptr;
|
// Align size so we don't get unaligned memory access
|
||||||
assert(arena->ptr + size < arena->start + arena->size);
|
size += 8 - (size % 8);
|
||||||
arena->ptr += size;
|
|
||||||
return p;
|
uintptr_t p = (uintptr_t)arena->ptr;
|
||||||
|
uintptr_t align_diff = p % 8;
|
||||||
|
/* printf("Alotted size so far: %d / %d, requested: %lu\n", */
|
||||||
|
/* alloc_arena_bytes_used(arena), alloc_arena_bytes_free(arena), */
|
||||||
|
/* size); */
|
||||||
|
assert((arena->ptr + size) < (arena->start + arena->size));
|
||||||
|
arena->ptr += size + align_diff;
|
||||||
|
return (void *)p;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t
|
uint32_t
|
||||||
|
@ -54,7 +62,7 @@ fastalloc_free()
|
||||||
}
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
fastalloc_malloc(uint32_t size)
|
fastalloc_malloc(size_t size)
|
||||||
{
|
{
|
||||||
return alloc_arena_malloc(&scratchpad_arena, size);
|
return alloc_arena_malloc(&scratchpad_arena, size);
|
||||||
}
|
}
|
||||||
|
|
134
src/object.c
Normal file
134
src/object.c
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "object.h"
|
||||||
|
#include "memalloc.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
extern ArenaAllocator _level_arena;
|
||||||
|
|
||||||
|
void
|
||||||
|
_load_animation(ObjectAnim *animation, uint8_t *bytes, uint32_t *b)
|
||||||
|
{
|
||||||
|
animation->frames = NULL;
|
||||||
|
animation->num_frames = get_short_be(bytes, b);
|
||||||
|
animation->loopback = get_byte(bytes, b);
|
||||||
|
if(animation->num_frames > 0) {
|
||||||
|
animation->frames = alloc_arena_malloc(
|
||||||
|
&_level_arena,
|
||||||
|
sizeof(ObjectAnimFrame) * animation->num_frames);
|
||||||
|
|
||||||
|
for(uint16_t i = 0; i < animation->num_frames; i++) {
|
||||||
|
ObjectAnimFrame *frame = &animation->frames[i];
|
||||||
|
frame->u0 = get_byte(bytes, b);
|
||||||
|
frame->v0 = get_byte(bytes, b);
|
||||||
|
frame->w = get_byte(bytes, b);
|
||||||
|
frame->h = get_byte(bytes, b);
|
||||||
|
frame->flipmask = get_byte(bytes, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
load_object_table(const char *filename, ObjectTable *tbl)
|
||||||
|
{
|
||||||
|
uint8_t *bytes;
|
||||||
|
uint32_t b, length;
|
||||||
|
|
||||||
|
bytes = file_read(filename, &length);
|
||||||
|
if(bytes == NULL) {
|
||||||
|
printf("Error reading OTD file %s from the CD.\n", filename);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
b = 0;
|
||||||
|
|
||||||
|
tbl->is_level_specific = get_byte(bytes, &b);
|
||||||
|
tbl->num_entries = get_short_be(bytes, &b);
|
||||||
|
|
||||||
|
if(tbl->num_entries == 0) goto end;
|
||||||
|
|
||||||
|
tbl->entries = alloc_arena_malloc(
|
||||||
|
&_level_arena,
|
||||||
|
sizeof(ObjectTableEntry) * tbl->num_entries);
|
||||||
|
|
||||||
|
printf("Entries at %p\n", tbl->entries);
|
||||||
|
|
||||||
|
|
||||||
|
for(uint16_t i = 0; i < tbl->num_entries; i++) {
|
||||||
|
printf("Reading entry %d.\n", i);
|
||||||
|
ObjectTableEntry *entry = &tbl->entries[i];
|
||||||
|
printf("Init animations and fragment\n");
|
||||||
|
entry->animations = NULL;
|
||||||
|
entry->fragment = NULL;
|
||||||
|
printf("OK\n");
|
||||||
|
|
||||||
|
uint8_t _id = get_byte(bytes, &b); // Entry ID, always sequential; discarded
|
||||||
|
printf("Registered id: %d\n", _id);
|
||||||
|
uint8_t has_fragment = get_byte(bytes, &b);
|
||||||
|
entry->num_animations = get_short_be(bytes, &b);
|
||||||
|
|
||||||
|
if(entry->num_animations > 0) {
|
||||||
|
printf("Start reading animations...\n");
|
||||||
|
entry->animations = alloc_arena_malloc(
|
||||||
|
&_level_arena,
|
||||||
|
sizeof(ObjectAnim) * entry->num_animations);
|
||||||
|
|
||||||
|
for(uint16_t j = 0; j < entry->num_animations; j++) {
|
||||||
|
printf("Reading animation %d.\n", j);
|
||||||
|
ObjectAnim *animation = &entry->animations[j];
|
||||||
|
_load_animation(animation, bytes, &b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(has_fragment) {
|
||||||
|
printf("Start reading fragment...\n");
|
||||||
|
ObjectFrag *fragment = alloc_arena_malloc(
|
||||||
|
&_level_arena,
|
||||||
|
sizeof(ObjectFrag));
|
||||||
|
entry->fragment = fragment;
|
||||||
|
|
||||||
|
fragment->offsetx = get_short_be(bytes, &b);
|
||||||
|
fragment->offsety = get_short_be(bytes, &b);
|
||||||
|
fragment->num_animations = get_short_be(bytes, &b);
|
||||||
|
fragment->animations = alloc_arena_malloc(
|
||||||
|
&_level_arena,
|
||||||
|
sizeof(ObjectAnim) * fragment->num_animations);
|
||||||
|
|
||||||
|
for(uint16_t j = 0; j < fragment->num_animations; j++) {
|
||||||
|
printf("Reading fragment animation %d.\n", j);
|
||||||
|
ObjectAnim *animation = &fragment->animations[j];
|
||||||
|
_load_animation(animation, bytes, &b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
free(bytes);
|
||||||
|
printf("Loaded %d object types.\n", tbl->num_entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
unload_object_table(ObjectTable *tbl)
|
||||||
|
{
|
||||||
|
// Since the object table has to be heap-allocated, we need to unload it
|
||||||
|
for(uint16_t i = 0; i < tbl->num_entries; i++) {
|
||||||
|
ObjectTableEntry *entry = &tbl->entries[i];
|
||||||
|
for(uint16_t j = 0; j < entry->num_animations; j++) {
|
||||||
|
ObjectAnim *animation = &entry->animations[j];
|
||||||
|
free(animation->frames);
|
||||||
|
}
|
||||||
|
if(entry->num_animations > 0) free(entry->animations);
|
||||||
|
|
||||||
|
if(entry->fragment) {
|
||||||
|
for(uint16_t j = 0; j < entry->fragment->num_animations; j++) {
|
||||||
|
ObjectAnim *animation = &entry->fragment->animations[j];
|
||||||
|
free(animation->frames);
|
||||||
|
}
|
||||||
|
if(entry->fragment->num_animations > 0)
|
||||||
|
free(entry->fragment->animations);
|
||||||
|
free(entry->fragment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(tbl->entries);
|
||||||
|
}
|
100
src/object_state.c
Normal file
100
src/object_state.c
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "object.h"
|
||||||
|
#include "object_state.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "memalloc.h"
|
||||||
|
|
||||||
|
extern ArenaAllocator _level_arena;
|
||||||
|
|
||||||
|
void
|
||||||
|
_emplace_object(
|
||||||
|
ChunkObjectData *data,
|
||||||
|
uint8_t is_level_specific,
|
||||||
|
int8_t type, uint8_t flipmask, int32_t vx, int32_t vy, void *extra)
|
||||||
|
{
|
||||||
|
ObjectState *state = &data->objects[data->num_objects++];
|
||||||
|
assert(data->num_objects < MAX_OBJECTS_PER_CHUNK);
|
||||||
|
|
||||||
|
state->id = type + (is_level_specific ? 100 : 0);
|
||||||
|
state->flipmask = flipmask;
|
||||||
|
state->rx = vx & 0x7f;
|
||||||
|
state->ry = vy & 0x7f;
|
||||||
|
state->extra = extra;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
load_object_placement(const char *filename, LevelData *lvl)
|
||||||
|
{
|
||||||
|
uint8_t *bytes;
|
||||||
|
uint32_t b, length;
|
||||||
|
|
||||||
|
bytes = file_read(filename, &length);
|
||||||
|
if(bytes == NULL) {
|
||||||
|
printf("Error reading OTD file %s from the CD.\n", filename);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
b = 0;
|
||||||
|
|
||||||
|
uint16_t created_objects = 0;
|
||||||
|
uint16_t num_objects = get_short_be(bytes, &b);
|
||||||
|
for(uint16_t i = 0; i < num_objects; i++) {
|
||||||
|
uint8_t is_level_specific = get_byte(bytes, &b);
|
||||||
|
int8_t type = get_byte(bytes, &b);
|
||||||
|
uint8_t flipmask = get_byte(bytes, &b);
|
||||||
|
int32_t vx = get_long_be(bytes, &b);
|
||||||
|
int32_t vy = get_long_be(bytes, &b);
|
||||||
|
void *extra = NULL;
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
default: break;
|
||||||
|
case OBJ_MONITOR:
|
||||||
|
extra = alloc_arena_malloc(&_level_arena, sizeof(MonitorExtra));
|
||||||
|
((MonitorExtra *)extra)->kind = get_byte(bytes, &b);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get chunk at position
|
||||||
|
int32_t cx = vx >> 7;
|
||||||
|
int32_t cy = vy >> 7;
|
||||||
|
int32_t chunk_pos;
|
||||||
|
if((cx < 0) || (cx >= lvl->layers[0].width)) chunk_pos = -1;
|
||||||
|
else if((cy < 0) || (cy >= lvl->layers[0].height)) chunk_pos = -1;
|
||||||
|
else chunk_pos = (cy * lvl->layers[0].width) + cx;
|
||||||
|
|
||||||
|
ChunkObjectData *data = lvl->objects[chunk_pos];
|
||||||
|
if(!data) {
|
||||||
|
data = alloc_arena_malloc(&_level_arena, sizeof(ChunkObjectData));
|
||||||
|
lvl->objects[chunk_pos] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(type < 0) {
|
||||||
|
// This is a dummy object, so create others in its place.
|
||||||
|
switch(type) {
|
||||||
|
case OBJ_DUMMY_RINGS_3V:
|
||||||
|
_emplace_object(data, 0, OBJ_RING, 0, vx, vy - 24, NULL);
|
||||||
|
_emplace_object(data, 0, OBJ_RING, 0, vx, vy, NULL);
|
||||||
|
_emplace_object(data, 0, OBJ_RING, 0, vx, vy + 24, NULL);
|
||||||
|
created_objects += 3;
|
||||||
|
break;
|
||||||
|
case OBJ_DUMMY_RINGS_3H:
|
||||||
|
_emplace_object(data, 0, OBJ_RING, 0, vx - 24, vy, NULL);
|
||||||
|
_emplace_object(data, 0, OBJ_RING, 0, vx, vy, NULL);
|
||||||
|
_emplace_object(data, 0, OBJ_RING, 0, vx + 24, vy, NULL);
|
||||||
|
created_objects += 3;
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_emplace_object(data, is_level_specific, type, flipmask, vx, vy, extra);
|
||||||
|
created_objects++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Loaded %d objects.\n", created_objects);
|
||||||
|
|
||||||
|
free(bytes);
|
||||||
|
}
|
|
@ -23,7 +23,7 @@ void
|
||||||
screen_disclaimer_load()
|
screen_disclaimer_load()
|
||||||
{
|
{
|
||||||
screen_disclaimer_data *data = screen_alloc(sizeof(screen_disclaimer_data));
|
screen_disclaimer_data *data = screen_alloc(sizeof(screen_disclaimer_data));
|
||||||
uint32_t length;
|
uint32_t length; // 153624 B
|
||||||
data->disclaimer_bg = file_read("\\MISC\\DISK.TIM;1", &length);
|
data->disclaimer_bg = file_read("\\MISC\\DISK.TIM;1", &length);
|
||||||
data->disclaimer_timer = 0;
|
data->disclaimer_timer = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "level.h"
|
#include "level.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include "model.h"
|
#include "model.h"
|
||||||
|
#include "object.h"
|
||||||
|
|
||||||
extern int debug_mode;
|
extern int debug_mode;
|
||||||
|
|
||||||
|
@ -24,10 +25,11 @@ static uint8_t music_channel = 0;
|
||||||
|
|
||||||
static Player player;
|
static Player player;
|
||||||
|
|
||||||
TileMap16 map16;
|
TileMap16 map16;
|
||||||
TileMap128 map128;
|
TileMap128 map128;
|
||||||
LevelData leveldata;
|
LevelData leveldata;
|
||||||
Camera camera;
|
Camera camera;
|
||||||
|
ObjectTable obj_table_common;
|
||||||
|
|
||||||
#define CHANNELS_PER_BGM 3
|
#define CHANNELS_PER_BGM 3
|
||||||
static uint32_t bgm_loop_sectors[] = {
|
static uint32_t bgm_loop_sectors[] = {
|
||||||
|
@ -73,6 +75,7 @@ static uint32_t bgm_loop_sectors[] = {
|
||||||
// Forward function declarations
|
// Forward function declarations
|
||||||
static void level_load_player();
|
static void level_load_player();
|
||||||
static void level_load_level();
|
static void level_load_level();
|
||||||
|
static void level_unload_level();
|
||||||
|
|
||||||
// TODO!!!
|
// TODO!!!
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -99,6 +102,7 @@ screen_level_unload(void *)
|
||||||
{
|
{
|
||||||
sound_stop_xa();
|
sound_stop_xa();
|
||||||
level_reset();
|
level_reset();
|
||||||
|
level_unload_level();
|
||||||
sound_reset_mem();
|
sound_reset_mem();
|
||||||
screen_free();
|
screen_free();
|
||||||
}
|
}
|
||||||
|
@ -356,6 +360,17 @@ level_load_level()
|
||||||
printf("Loading %s...\n", filename0);
|
printf("Loading %s...\n", filename0);
|
||||||
load_lvl(&leveldata, filename0);
|
load_lvl(&leveldata, filename0);
|
||||||
|
|
||||||
|
// Load common objects
|
||||||
|
printf("Loading common object table...\n");
|
||||||
|
load_object_table("\\LEVELS\\COMMON\\OBJ.OTD", &obj_table_common);
|
||||||
|
|
||||||
|
// Load level objects
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
// Load object positioning on level
|
||||||
|
snprintf(filename0, 255, "%s\\Z%1u.OMP;1", basepath, (level & 0x01) + 1);
|
||||||
|
load_object_placement(filename0, &leveldata);
|
||||||
|
|
||||||
|
|
||||||
// Pre-allocate and initialize level primitive buffer
|
// Pre-allocate and initialize level primitive buffer
|
||||||
prepare_renderer(&leveldata);
|
prepare_renderer(&leveldata);
|
||||||
|
@ -376,3 +391,10 @@ level_load_level()
|
||||||
|
|
||||||
sound_play_xa(filename0, 0, music_channel, bgm_loop_sectors[level]);
|
sound_play_xa(filename0, 0, music_channel, bgm_loop_sectors[level]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
level_unload_level()
|
||||||
|
{
|
||||||
|
// Object tables are heap-allocated
|
||||||
|
//unload_object_table(&obj_table_common);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue