initial commit, eq circuit emulator
[eqemu] / src / mesh.cc
1 /*
2 eqemu - electronic queue system emulator
3 Copyright (C) 2014  John Tsiombikas <nuclear@member.fsf.org>,
4                     Eleni-Maria Stea <eleni@mutantstargoat.com>
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 #include <stdio.h>
20 #include <string.h>
21 #include <math.h>
22 #include <GL/glew.h>
23 #include "mesh.h"
24
25 #define ALL_VALID       0xffffffff
26
27 Mesh::Mesh()
28 {
29         buf_valid = ALL_VALID;
30         bsph_valid = false;
31
32         for(int i=0; i<NUM_MESH_ATTRIBS; i++) {
33                 attr[i] = 0;
34                 attr_size[i] = 0;
35                 buf_valid &= ~(1 << i);
36         }
37         vcount = 0;
38         glGenBuffers(NUM_MESH_ATTRIBS, vbo);
39 }
40
41 Mesh::~Mesh()
42 {
43         for(int i=0; i<NUM_MESH_ATTRIBS; i++) {
44                 delete [] attr[i];
45         }
46         glDeleteBuffers(NUM_MESH_ATTRIBS, vbo);
47 }
48
49 float *Mesh::set_attrib(int aidx, int count, int elemsz, float *data)
50 {
51         delete [] attr[aidx];
52         attr[aidx] = new float[count * elemsz];
53         memcpy(attr[aidx], data, count * elemsz * sizeof *data);
54         vcount = count;
55         attr_size[aidx] = elemsz;
56         buf_valid &= ~(1 << aidx);
57
58         if(aidx == MESH_ATTR_VERTEX) {
59                 bsph_valid = false;
60         }
61
62         return attr[aidx];
63 }
64
65 float *Mesh::get_attrib(int aidx)
66 {
67         buf_valid &= ~(1 << aidx);
68         if(aidx == MESH_ATTR_VERTEX) {
69                 bsph_valid = false;
70         }
71         return attr[aidx];
72 }
73
74 const float *Mesh::get_attrib(int aidx) const
75 {
76         return attr[aidx];
77 }
78
79 void Mesh::draw() const
80 {
81         if(!vcount) return;
82
83         update_buffers();
84
85         if(!vbo[MESH_ATTR_VERTEX]) {
86                 fprintf(stderr, "trying to render without a vertex buffer\n");
87                 return;
88         }
89
90         glBindBuffer(GL_ARRAY_BUFFER, vbo[MESH_ATTR_VERTEX]);
91         glEnableClientState(GL_VERTEX_ARRAY);
92         glVertexPointer(attr_size[MESH_ATTR_VERTEX], GL_FLOAT, 0, 0);
93
94         if(vbo[MESH_ATTR_NORMAL]) {
95                 glBindBuffer(GL_ARRAY_BUFFER, vbo[MESH_ATTR_NORMAL]);
96                 glEnableClientState(GL_NORMAL_ARRAY);
97                 glNormalPointer(GL_FLOAT, 0, 0);
98         }
99         if(vbo[MESH_ATTR_TEXCOORD]) {
100                 glBindBuffer(GL_ARRAY_BUFFER, vbo[MESH_ATTR_TEXCOORD]);
101                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
102                 glTexCoordPointer(attr_size[MESH_ATTR_TEXCOORD], GL_FLOAT, 0, 0);
103         }
104         glBindBuffer(GL_ARRAY_BUFFER, 0);
105
106         glDrawArrays(GL_TRIANGLES, 0, vcount);
107
108         glDisableClientState(GL_VERTEX_ARRAY);
109         if(vbo[MESH_ATTR_NORMAL]) {
110                 glDisableClientState(GL_NORMAL_ARRAY);
111         }
112         if(vbo[MESH_ATTR_TEXCOORD]) {
113                 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
114         }
115 }
116
117 BSphere &Mesh::get_bounds()
118 {
119         calc_bsph();
120         return bsph;
121 }
122
123 const BSphere &Mesh::get_bounds() const
124 {
125         calc_bsph();
126         return bsph;
127 }
128
129 void Mesh::update_buffers() const
130 {
131         if(buf_valid == ALL_VALID) {
132                 return;
133         }
134
135         for(int i=0; i<NUM_MESH_ATTRIBS; i++) {
136                 if((buf_valid & (1 << i)) == 0) {
137                         glBindBuffer(GL_ARRAY_BUFFER, vbo[i]);
138                         glBufferData(GL_ARRAY_BUFFER, vcount * attr_size[i] * sizeof(float),
139                                         attr[i], GL_STATIC_DRAW);
140                         buf_valid |= 1 << i;
141                 }
142         }
143 }
144
145 void Mesh::calc_bsph() const
146 {
147         if(bsph_valid || !vcount) {
148                 return;
149         }
150
151         Vector3 center;
152
153         float *vptr = attr[MESH_ATTR_VERTEX];
154         for(int i=0; i<vcount; i++) {
155                 center = center + Vector3(vptr[0], vptr[1], vptr[2]);
156                 vptr += 3;
157         }
158         center = center * (1.0f / (float)vcount);
159
160         float max_lensq = 0.0f;
161         vptr = attr[MESH_ATTR_VERTEX];
162         for(int i=0; i<vcount; i++) {
163                 Vector3 v = Vector3(vptr[0], vptr[1], vptr[2]) - center;
164                 float lensq = dot(v, v);
165                 if(lensq > max_lensq) {
166                         max_lensq = lensq;
167                 }
168         }
169
170         bsph.set_center(center);
171         bsph.set_radius(sqrt(max_lensq));
172
173         bsph_valid = true;
174 }