summaryrefslogtreecommitdiff
path: root/include/model.h
blob: 10c9cdf3f3bfd524d40d3655b90772656f6fd7c8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#pragma once

#include <assert.h>
#include <stddef.h>
#include <stdint.h>

constexpr size_t ModelPathLen      = 256;
constexpr size_t ModelNameLen      = 64;
constexpr size_t ModelMaxObjects   = 256; // uint8_t
constexpr size_t ModelMaxMaterials = 256; // uint8_t
constexpr size_t ModelMaxVerts     = 4294967296; // uint32_t
constexpr size_t ModelMaxFaces     = 4294967296; // uint32_t

typedef uint16_t mdIdx;
typedef struct mdVert { mdIdx position, texcoord, normal; } mdVert;
typedef struct mdTri  { mdVert v0, v1, v2; } mdTri;
typedef struct mdVec2 { float x, y;        } mdVec2;
typedef struct mdVec3 { float x, y, z;     } mdVec3;

typedef struct ModelObject {
  uint32_t offset;   // FlatModel: offset into indices. IndexedModel: offset into tris.
  uint32_t count;    // FloatModel: number of indices.  IndexedModel: number of tris.
  uint8_t  material; // Material index.
  uint8_t  pad[3];
  char     name[ModelNameLen];
} ModelObject;

typedef struct ModelMaterial {
  char name[ModelNameLen];
  char diffuseTexture[ModelPathLen];
} ModelMaterial;

// Every three indices form a triangle, and each index indexes all attribute
// arrays simultaneously. This is best for a fast, linear-scan rendering.
// This is what you would render with glDrawElements().
typedef struct FlatModel {
  // Counts.
  uint32_t numIdxs;
  uint32_t numVerts;
  // Offsets.
  uint32_t offsetIdxs;
  uint32_t offsetPositions;
  uint32_t offsetTexcoords;
  uint32_t offsetNormals;
  /*
  [objects]   -- numObjects   Object
  [materials] -- numMaterials Material
  [indices]   -- numIdxs  mdIdx
  [positions] -- numVerts mdVec3
  [texcoords] -- numVerts mdVec2
  [normals]   -- numVerts mdVec3
  */
  uint8_t data[];
} FlatModel;

// Every triangle is made up of three vertices, and each vertex holds one index
// for each of the attribute arrays. This allows for a smaller representation of
// some models by virtue of being able to re-use attributes across vertices.
// This is the sort of format that OBJ follows, where the indices to each array
// given by a face may be non-uniform.
typedef struct IndexedModel {
  // Counts.
  uint32_t numTris;
  uint32_t numPositions;
  uint32_t numTexcoords;
  uint32_t numNormals;
  // Offsets.
  uint32_t offsetTris;
  uint32_t offsetPositions;
  uint32_t offsetTexcoords;
  uint32_t offsetNormals;
  /*
  [objects]   -- numObjects   Object
  [materials] -- numMaterials Material
  [triangles] -- numTris      mdTri
  [positions] -- numPositions mdVec3
  [texcoords] -- numTexcoords mdVec2
  [normals]   -- numNormals   mdVec3
  */
  uint8_t data[];
} IndexedModel;

typedef enum ModelType {
  ModelTypeFlat,
  ModelTypeIndexed
} ModelType;

typedef struct Model {
  uint32_t type;
  // Counts.
  uint8_t  numObjects;
  uint8_t  numMaterials;
  uint8_t  pad[2];
  // Offsets.
  uint32_t offsetObjects;
  uint32_t offsetMaterials;
  // Model details.
  union {
    FlatModel    flat;
    IndexedModel indexed;
  };
} Model;

static inline const ModelObject* modelObjects(const Model* model) {
  assert(model);
  switch (model->type) {
  case ModelTypeIndexed:
    return (const ModelObject*)(model->indexed.data + model->offsetObjects);
  case ModelTypeFlat:
    return (const ModelObject*)(model->flat.data    + model->offsetObjects);
  default:
    assert(false);
    break;
  }
}

static inline const ModelMaterial* modelMaterials(const Model* model) {
  assert(model);
  switch (model->type) {
  case ModelTypeIndexed:
    return (const ModelMaterial*)(model->indexed.data + model->offsetMaterials);
  case ModelTypeFlat:
    return (const ModelMaterial*)(model->flat.data    + model->offsetMaterials);
  default:
    assert(false);
    break;
  }
}