1 /*
2     Copyright (c) 2011 Andrew Caudwell (acaudwell@gmail.com)
3     All rights reserved.
4 
5     Redistribution and use in source and binary forms, with or without
6     modification, are permitted provided that the following conditions
7     are met:
8     1. Redistributions of source code must retain the above copyright
9        notice, this list of conditions and the following disclaimer.
10     2. Redistributions in binary form must reproduce the above copyright
11        notice, this list of conditions and the following disclaimer in the
12        documentation and/or other materials provided with the distribution.
13     3. The name of the author may not be used to endorse or promote products
14        derived from this software without specific prior written permission.
15 
16     THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17     IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19     IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25     THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 
28 #include "vbo.h"
29 
30 //quadbuf
31 
quadbuf(int vertex_capacity)32 quadbuf::quadbuf(int vertex_capacity) : vertex_capacity(vertex_capacity) {
33     vertex_count = 0;
34 
35     data = vertex_capacity > 0 ? new quadbuf_vertex[vertex_capacity] : 0;
36 
37     //fprintf(stderr, "size of quadbuf_vertex = %d\n", sizeof(quadbuf_vertex));
38 }
39 
~quadbuf()40 quadbuf::~quadbuf() {
41     if(data!=0) delete[] data;
42 }
43 
unload()44 void quadbuf::unload() {
45     buf.unload();
46 }
47 
resize(int new_size)48 void quadbuf::resize(int new_size) {
49 
50     quadbuf_vertex* _data = data;
51 
52     data = new quadbuf_vertex[new_size];
53 
54     for(int i=0;i<vertex_capacity;i++) {
55         data[i] = _data[i];
56     }
57 
58     vertex_capacity = new_size;
59 
60     if(_data != 0) delete[] _data;
61 }
62 
reset()63 void quadbuf::reset() {
64     textures.resize(0);
65     vertex_count = 0;
66 }
67 
vertices()68 size_t quadbuf::vertices() {
69     return vertex_count;
70 }
71 
capacity()72 size_t quadbuf::capacity() {
73     return vertex_capacity;
74 }
75 
texture_changes()76 size_t quadbuf::texture_changes() {
77     return textures.size();
78 }
79 
80 vec4 quadbuf_default_texcoord(0.0f, 0.0f, 1.0f, 1.0f);
81 
add(GLuint textureid,const vec2 & pos,const vec2 & dims,const vec4 & colour)82 void quadbuf::add(GLuint textureid, const vec2& pos, const vec2& dims, const vec4& colour) {
83     add(textureid, pos, dims, colour, quadbuf_default_texcoord);
84 }
85 
add(GLuint textureid,const vec2 & pos,const vec2 & dims,const vec4 & colour,const vec4 & texcoord)86 void quadbuf::add(GLuint textureid, const vec2& pos, const vec2& dims, const vec4& colour, const vec4& texcoord) {
87     //debugLog("%d: %.2f, %.2f, %.2f, %.2f\n", i, pos.x, pos.y, dims.x, dims.y);
88 
89     quadbuf_vertex v1(pos,                       colour, vec2(texcoord.x, texcoord.y));
90     quadbuf_vertex v2(pos + vec2(dims.x, 0.0f), colour, vec2(texcoord.z, texcoord.y));
91     quadbuf_vertex v3(pos + dims,                colour, vec2(texcoord.z, texcoord.w));
92     quadbuf_vertex v4(pos + vec2(0.0f, dims.y), colour, vec2(texcoord.x, texcoord.w));
93 
94     int i = vertex_count;
95 
96     vertex_count += 4;
97 
98     if(vertex_count > vertex_capacity) {
99         resize(vertex_count*2);
100     }
101 
102     data[i]   = v1;
103     data[i+1] = v2;
104     data[i+2] = v3;
105     data[i+3] = v4;
106 
107     if(textureid>0 && (textures.empty() || textures.back().textureid != textureid)) {
108         textures.push_back(quadbuf_tex(i, textureid));
109     }
110 }
111 
add(GLuint textureid,const quadbuf_vertex & v1,const quadbuf_vertex & v2,const quadbuf_vertex & v3,const quadbuf_vertex & v4)112 void quadbuf::add(GLuint textureid, const quadbuf_vertex& v1, const quadbuf_vertex& v2, const quadbuf_vertex& v3, const quadbuf_vertex& v4) {
113 
114     int i = vertex_count;
115 
116     vertex_count += 4;
117 
118     if(vertex_count > vertex_capacity) {
119         resize(vertex_count*2);
120     }
121 
122     data[i]   = v1;
123     data[i+1] = v2;
124     data[i+2] = v3;
125     data[i+3] = v4;
126 
127     if(textureid>0 && (textures.empty() || textures.back().textureid != textureid)) {
128         textures.push_back(quadbuf_tex(i, textureid));
129     }
130 }
131 
update()132 void quadbuf::update() {
133     if(vertex_count==0) return;
134 
135     //recreate buffer if less than the vertex_count
136     buf.buffer( vertex_count, sizeof(quadbuf_vertex), vertex_capacity, &(data[0].pos.x), GL_DYNAMIC_DRAW );
137 }
138 
draw()139 void quadbuf::draw() {
140     if(vertex_count==0) return;
141 
142     buf.bind();
143 
144     glEnableClientState(GL_VERTEX_ARRAY);
145     glEnableClientState(GL_COLOR_ARRAY);
146     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
147 
148     glVertexPointer(2,   GL_FLOAT, sizeof(quadbuf_vertex), 0);
149     glColorPointer(4,    GL_FLOAT, sizeof(quadbuf_vertex), (GLvoid*)8);  // offset pos (2x4 bytes)
150     glTexCoordPointer(2, GL_FLOAT, sizeof(quadbuf_vertex), (GLvoid*)24); // offset pos + colour (2x4 + 4x4 bytes)
151 
152     int last_index = vertex_count-1;
153 
154     if(textures.empty()) {
155 
156          glDrawArrays(GL_QUADS, 0, vertex_count);
157 
158     } else {
159         for(std::vector<quadbuf_tex>::iterator it = textures.begin(); it != textures.end();) {
160             quadbuf_tex* tex = &(*it);
161 
162             int end_index;
163 
164             it++;
165 
166             if(it == textures.end()) {
167                 end_index = last_index;
168             } else {
169                 end_index = (*it).start_index;
170             }
171 
172             glBindTexture(GL_TEXTURE_2D, tex->textureid);
173             glDrawArrays(GL_QUADS, tex->start_index, end_index - tex->start_index + 1);
174 
175             if(end_index==last_index) break;
176         }
177     }
178 
179     glDisableClientState(GL_VERTEX_ARRAY);
180     glDisableClientState(GL_COLOR_ARRAY);
181     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
182 
183     buf.unbind();
184 }
185