writing a mesh abstraction
[vrtris] / src / cmesh.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include "opengl.h"
4 #include "cmesh.h"
5
6
7 struct cmesh_vattrib {
8         int nelem;      /* num elements per attribute [1, 4] */
9         float *data;    /* dynarr */
10         unsigned int vbo;
11         int vbo_valid, data_valid;
12 };
13
14
15 struct cmesh {
16         char *name;
17         unsigned int nverts, nfaces;
18
19         /* current value for each attribute for the immediate mode interface */
20         cgm_vec4 cur_val[CMESH_NUM_ATTR];
21
22         unsigned int buffer_objects[CMESH_NUM_ATTR + 1];
23         struct cmesh_vattrib vattr[CMESH_NUM_ATTR];
24
25         unsigned int *idata;    /* dynarr */
26         unsigned int ibo;
27         int ibo_valid, idata_valid;
28
29         /* index buffer for wireframe rendering (constructed on demand) */
30         unsigned int wire_ibo;
31         int wire_ibo_valid;
32
33         /* axis-aligned bounding box */
34         cgm_vec3 aabb_min, aabb_max;
35         int aabb_valid;
36         /* bounding sphere */
37         cgm_vec3 bsph_center;
38         float bsph_radius;
39         int bsph_valid;
40 };
41
42 static int sdr_loc[CMESH_NUM_ATTR] = {0, 1, 2, 3, 4, 5, 6, 7};
43
44
45 /* global state */
46 void cmesh_set_attrib_sdrloc(int attr, int loc)
47 {
48         sdr_loc[attr] = loc;
49 }
50
51 int cmesh_get_attrib_sdrloc(int attr)
52 {
53         return sdr_loc[attr];
54 }
55
56 void cmesh_clear_attrib_sdrloc(void)
57 {
58         int i;
59         for(i=0; i<CMESH_NUM_ATTR; i++) {
60                 sdr_loc[i] = -1;
61         }
62 }
63
64 /* mesh functions */
65 struct cmesh *cmesh_alloc(void)
66 {
67         struct cmesh *cm;
68
69         if(!(cm = malloc(sizeof *cm))) {
70                 return 0;
71         }
72         if(cmesh_init(cm) == -1) {
73                 free(cm);
74                 return 0;
75         }
76         return cm;
77 }
78
79 void cmesh_free(struct cmesh *cm)
80 {
81         cmesh_destroy(cm);
82         free(cm);
83 }
84
85 int cmesh_init(struct cmesh *cm)
86 {
87         int i;
88         cgm_clear(cm);
89
90         glGenBuffers(CMESH_NUM_ATTR + 1, cm->buffer_objects);
91
92         for(i=0; i<CMESH_NUM_ATTR; i++) {
93                 if(!(cm->vattr[i].data = dynarr_alloc(0, sizeof(float)))) {
94                         cmesh_destroy(cm);
95                         return -1;
96                 }
97                 cm->vattr[i].vbo = buffer_objects[i];
98         }
99
100         cm->ibo = buffer_objects[CMESH_NUM_ATTR];
101         if(!(cm->idata = dynarr_alloc(0, sizeof *cm->idata))) {
102                 cmesh_destroy(cm);
103                 return -1;
104         }
105         return 0;
106 }
107
108 void cmesh_destroy(struct cmesh *cm)
109 {
110         int i;
111
112         for(i=0; i<CMESH_NUM_ATTR; i++) {
113                 dynarr_free(cm->vattr[i].data);
114         }
115         dynarr_free(cm->idata);
116
117         glDeleteBuffers(CMESH_NUM_ATTR + 1, cm->buffer_objects);
118         if(cm->wire_ibo) {
119                 glDeleteBuffers(1, &cm->wire_ibo);
120         }
121 }
122
123 void cmesh_clear(struct cmesh *cm)
124 {
125         memset(cm, 0, sizeof *cm);
126
127         cgm_wcons(cm->cur_val + CMESH_ATTR_COLOR, 1, 1, 1, 1);
128         /* TODO */
129 }
130
131 void cmesh_copy(struct cmesh *cmdest, struct cmesh *cmsrc);
132
133 void cmesh_set_name(struct cmesh *cm, const char *name);
134 const char *cmesh_name(struct cmesh *cm);
135
136 int cmesh_has_attrib(struct cmesh *cm, int attr);
137 int cmesh_indexed(struct cmesh *cm);
138
139 /* vdata can be 0, in which case only memory is allocated
140  * returns pointer to the attribute array
141  */
142 float *cmesh_set_attrib(struct cmesh *cm, int attr, int nelem, unsigned int num,
143                 const float *vdata);
144 float *cmesh_attrib(struct cmesh *cm, int attr);        /* invalidates VBO */
145 const float *cmesh_attrib_ro(struct cmesh *cm, int attr);       /* doesn't invalidate */
146 int cmesh_attrib_count(struct cmesh *cm, int attr);
147
148 /* indices can be 0, in which case only memory is allocated
149  * returns pointer to the index array
150  */
151 unsigned int *cmesh_set_index(struct cmesh *cm, int num, const unsigned int *indices);
152 unsigned int *cmesh_index(struct cmesh *cm);    /* invalidates IBO */
153 const unsigned int *cmesh_index_ro(struct cmesh *cm);   /* doesn't invalidate */
154 int cmesh_index_count(struct cmesh *cm);
155
156 int get_poly_count(struct cmesh *cm);
157
158 /* attr can be -1 to invalidate all attributes */
159 void cmesh_invalidate_attrib(struct cmesh *cm, int attr);
160 void cmesh_invalidate_index(struct cmesh *cm);
161
162 int cmesh_append(struct cmesh *cmdest, struct cmesh *cmsrc);
163
164 /* immediate-mode style mesh construction interface */
165 int cmesh_vertex(struct cmesh *cm, float x, float y, float z);
166 int cmesh_normal(struct cmesh *cm, float nx, float ny, float nz);
167 int cmesh_tangent(struct cmesh *cm, float tx, float ty, float tz);
168 int cmesh_texcoord(struct cmesh *cm, float u, float v, float w);
169 int cmesh_boneweights(struct cmesh *cm, float w1, float w2, float w3, float w4);
170 int cmesh_boneidx(struct cmesh *cm, int idx1, int idx2, int idx3, int idx4);
171
172 /* dir_xform can be null, in which case it's calculated from xform */
173 void cmesh_apply_xform(struct cmesh *cm, float *xform, float *dir_xform);
174
175 void cmesh_flip(struct cmesh *cm);      /* flip faces (winding) and normals */
176 void cmesh_flip_faces(struct cmesh *cm);
177 void cmesh_flip_normals(struct cmesh *cm);
178
179 void cmesh_explode(struct cmesh *cm);   /* undo all vertex sharing */
180
181 /* this is only guaranteed to work on an exploded mesh */
182 void cmesh_calc_face_normals(struct cmesh *cm);
183
184 void cmesh_draw(struct cmesh *cm);
185 void cmesh_draw_wire(struct cmesh *cm, float linesz);
186 void cmesh_draw_vertices(struct cmesh *cm, float ptsz);
187 void cmesh_draw_normals(struct cmesh *cm, float len);
188 void cmesh_draw_tangents(struct cmesh *cm, float len);
189
190 /* get the bounding box in local space. The result will be cached and subsequent
191  * calls will return the same box. The cache gets invalidated by any functions that
192  * can affect the vertex data
193  */
194 void cmesh_aabbox(struct cmesh *cm, cgm_vec3 *vmin, cgm_vec3 *vmax);
195
196 /* get the bounding sphere in local space. The result will be cached ... see above */
197 float cmesh_bsphere(struct cmesh *cm, cgm_vec3 *center, float *rad);
198
199 /* texture coordinate manipulation */
200 void cmesh_texcoord_apply_xform(struct cmesh *cm, float *xform);
201 void cmesh_texcoord_gen_plane(struct cmesh *cm, cgm_vec3 *norm, cgm_vec3 *tang);
202 void cmesh_texcoord_gen_box(struct cmesh *cm);
203 void cmesh_texcoord_gen_cylinder(struct cmesh *cm);
204
205 int cmesh_dump(struct cmesh *cm, const char *fname);
206 int cmesh_dump_file(struct cmesh *cm, FILE *fp);
207 int cmesh_dump_obj(struct cmesh *cm, const char *fname);
208 int cmesh_dump_obj_file(struct cmesh *cm, FILE *fp, int voffs);