#include "Tesselator.h" #include #include #include Tesselator Tesselator::instance(sizeof(GLfloat) * MAX_FLOATS); // max size in bytes const int VertexSizeBytes = sizeof(VERTEX); Tesselator::Tesselator( int size ) : size(size), vertices(0), u(0), v(0), _color(0), hasColor(false), hasTexture(false), hasNormal(false), p(0), count(0), _noColor(false), mode(0), xo(0), yo(0), zo(0), _normal(0), _sx(1), _sy(1), tesselating(false), vboId(-1), vboCounts(128), totalSize(0), accessMode(ACCESS_STATIC), maxVertices(size / sizeof(VERTEX)), _voidBeginEnd(false) { vboIds = new GLuint[vboCounts]; _varray = new VERTEX[maxVertices]; char* a = (char*)&_varray[0]; char* b = (char*)&_varray[1]; LOGI("Vsize: %lu, %d\n", sizeof(VERTEX), (b-a)); } Tesselator::~Tesselator() { delete[] vboIds; delete[] _varray; } void Tesselator::init() { #ifndef STANDALONE_SERVER glGenBuffers2(vboCounts, vboIds); #endif } void Tesselator::clear() { accessMode = ACCESS_STATIC; vertices = 0; count = 0; p = 0; _voidBeginEnd = false; } int Tesselator::getVboCount() { return vboCounts; } RenderChunk Tesselator::end( bool useMine, int bufferId ) { #ifndef STANDALONE_SERVER //if (!tesselating) throw /*new*/ IllegalStateException("Not tesselating!"); if (!tesselating) LOGI("not tesselating!\n"); if (!tesselating || _voidBeginEnd) return RenderChunk(); tesselating = false; const int o_vertices = vertices; if (vertices > 0) { if (p <= 0 || p > maxVertices) { clear(); return RenderChunk(); } int bytes = p * sizeof(VERTEX); if (bytes <= 0) return RenderChunk(); if (++vboId >= vboCounts) vboId = 0; #ifdef USE_VBO // Using VBO, use default buffer id only if we don't send in any if (!useMine) { bufferId = vboIds[vboId]; } #else // Not using VBO - always use the next buffer object bufferId = vboIds[vboId]; #endif int access = GL_STATIC_DRAW;//(accessMode==ACCESS_DYNAMIC) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW; glBindBuffer2(GL_ARRAY_BUFFER, bufferId); glBufferData2(GL_ARRAY_BUFFER, bytes, _varray, access); // GL_STREAM_DRAW totalSize += bytes; #ifndef USE_VBO // 0 1 2 3 4 5 6 7 // x y z u v c if (hasTexture) { glTexCoordPointer2(2, GL_FLOAT, VertexSizeBytes, (GLvoid*) (3 * 4)); glEnableClientState2(GL_TEXTURE_COORD_ARRAY); } if (hasColor) { glColorPointer2(4, GL_UNSIGNED_BYTE, VertexSizeBytes, (GLvoid*) (5 * 4)); glEnableClientState2(GL_COLOR_ARRAY); } if (hasNormal) { glNormalPointer(GL_BYTE, VertexSizeBytes, (GLvoid*) (6 * 4)); glEnableClientState2(GL_NORMAL_ARRAY); } glVertexPointer2(3, GL_FLOAT, VertexSizeBytes, 0); glEnableClientState2(GL_VERTEX_ARRAY); if (mode == GL_QUADS) { glDrawArrays2(GL_TRIANGLES, 0, vertices); } else { glDrawArrays2(mode, 0, vertices); } //printf("drawing %d tris, size %d (%d,%d,%d)\n", vertices, p, hasTexture, hasColor, hasNormal); glDisableClientState2(GL_VERTEX_ARRAY); if (hasTexture) glDisableClientState2(GL_TEXTURE_COORD_ARRAY); if (hasColor) glDisableClientState2(GL_COLOR_ARRAY); if (hasNormal) glDisableClientState2(GL_NORMAL_ARRAY); #endif /*!USE_VBO*/ } clear(); RenderChunk out(bufferId, o_vertices); //map.insert( std::make_pair(bufferId, out.id) ); return out; #else return RenderChunk(); #endif } void Tesselator::begin( int mode ) { if (tesselating || _voidBeginEnd) { if (tesselating && !_voidBeginEnd) LOGI("already tesselating!\n"); return; } //if (tesselating) { // throw /*new*/ IllegalStateException("Already tesselating!"); //} tesselating = true; clear(); this->mode = mode; hasNormal = false; hasColor = false; hasTexture = false; _noColor = false; } void Tesselator::begin() { begin(GL_QUADS); } void Tesselator::tex( float u, float v ) { hasTexture = true; this->u = u; this->v = v; } int Tesselator::getColor() { return _color; } void Tesselator::color( float r, float g, float b ) { color((int) (r * 255), (int) (g * 255), (int) (b * 255)); } void Tesselator::color( float r, float g, float b, float a ) { color((int) (r * 255), (int) (g * 255), (int) (b * 255), (int) (a * 255)); } void Tesselator::color( int r, int g, int b ) { color(r, g, b, 255); } void Tesselator::color( int r, int g, int b, int a ) { if (_noColor) return; if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255; if (a > 255) a = 255; if (r < 0) r = 0; if (g < 0) g = 0; if (b < 0) b = 0; if (a < 0) a = 0; hasColor = true; //if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) { if (true) { _color = (a << 24) | (b << 16) | (g << 8) | (r); } else { _color = (r << 24) | (g << 16) | (b << 8) | (a); } } void Tesselator::color( char r, char g, char b ) { color(r & 0xff, g & 0xff, b & 0xff); } void Tesselator::color( int c ) { int r = ((c >> 16) & 255); int g = ((c >> 8) & 255); int b = ((c) & 255); color(r, g, b); } //@note: doesn't care about endianess void Tesselator::colorABGR( int c ) { if (_noColor) return; hasColor = true; _color = c; } void Tesselator::color( int c, int alpha ) { int r = ((c >> 16) & 255); int g = ((c >> 8) & 255); int b = ((c) & 255); color(r, g, b, alpha); } void Tesselator::vertexUV( float x, float y, float z, float u, float v ) { tex(u, v); vertex(x, y, z); } void Tesselator::scale2d(float sx, float sy) { _sx *= sx; _sy *= sy; } void Tesselator::resetScale() { _sx = _sy = 1; } void Tesselator::vertex( float x, float y, float z ) { #ifndef STANDALONE_SERVER count++; if (mode == GL_QUADS && (count & 3) == 0) { for (int i = 0; i < 2; i++) { const int offs = 3 - i; if (p - offs < 0 || p >= maxVertices) { clear(); return; } VERTEX& src = _varray[p - offs]; VERTEX& dst = _varray[p]; if (hasTexture) { dst.u = src.u; dst.v = src.v; } if (hasColor) { dst.color = src.color; } //if (hasNormal) { // dst.normal = src.normal; //} dst.x = src.x; dst.y = src.y; dst.z = src.z; ++vertices; ++p; } } if (p < 0 || p >= maxVertices) { clear(); return; } VERTEX& vertex = _varray[p]; if (hasTexture) { vertex.u = u; vertex.v = v; } if (hasColor) { vertex.color = _color; } //if (hasNormal) { // vertex.normal = _normal; //} vertex.x = _sx * (x + xo); vertex.y = _sy * (y + yo); vertex.z = z + zo; ++p; ++vertices; if ((vertices & 3) == 0 && p >= maxVertices-1) { for (int i = 0; i < 3; ++i) printf("Overwriting the vertex buffer! This chunk/entity won't show up\n"); clear(); } #endif } void Tesselator::noColor() { _noColor = true; } void Tesselator::setAccessMode(int mode) { accessMode = mode; } void Tesselator::normal( float x, float y, float z ) { static int _warn_t = 0; if ((++_warn_t & 32767) == 1) LOGI("WARNING: Can't use normals (Tesselator::normal)\n"); return; if (!tesselating) printf("But.."); hasNormal = true; char xx = (char) (x * 128); char yy = (char) (y * 127); char zz = (char) (z * 127); _normal = xx | (yy << 8) | (zz << 16); } void Tesselator::offset( float xo, float yo, float zo ) { this->xo = xo; this->yo = yo; this->zo = zo; } void Tesselator::addOffset( float x, float y, float z ) { xo += x; yo += y; zo += z; } void Tesselator::offset( const Vec3& v ) { xo = v.x; yo = v.y; zo = v.z; } void Tesselator::addOffset( const Vec3& v ) { xo += v.x; yo += v.y; zo += v.z; } void Tesselator::draw() { #ifndef STANDALONE_SERVER if (!tesselating) LOGI("not (draw) tesselating!\n"); if (!tesselating || _voidBeginEnd) return; tesselating = false; if (vertices > 0) { if (p <= 0 || p > maxVertices) { clear(); return; } int bytes = p * sizeof(VERTEX); if (bytes <= 0) { clear(); return; } if (++vboId >= vboCounts) vboId = 0; int bufferId = vboIds[vboId]; int access = GL_DYNAMIC_DRAW;//(accessMode==ACCESS_DYNAMIC) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW; glBindBuffer2(GL_ARRAY_BUFFER, bufferId); glBufferData2(GL_ARRAY_BUFFER, bytes, _varray, access); // GL_STREAM_DRAW if (hasTexture) { glTexCoordPointer2(2, GL_FLOAT, VertexSizeBytes, (GLvoid*) (3 * 4)); //glTexCoordPointer2(2, GL_FLOAT, VertexSizeBytes, (GLvoid*) &_varray->u); glEnableClientState2(GL_TEXTURE_COORD_ARRAY); } if (hasColor) { glColorPointer2(4, GL_UNSIGNED_BYTE, VertexSizeBytes, (GLvoid*) (5 * 4)); //glColorPointer2(4, GL_UNSIGNED_BYTE, VertexSizeBytes, (GLvoid*) &_varray->color); glEnableClientState2(GL_COLOR_ARRAY); } //if (hasNormal) { // glNormalPointer(GL_BYTE, VertexSizeBytes, (GLvoid*) (6 * 4)); // glEnableClientState2(GL_NORMAL_ARRAY); //} //glVertexPointer2(3, GL_FLOAT, VertexSizeBytes, (GLvoid*)&_varray); glVertexPointer2(3, GL_FLOAT, VertexSizeBytes, 0); glEnableClientState2(GL_VERTEX_ARRAY); if (mode == GL_QUADS) { glDrawArrays2(GL_TRIANGLES, 0, vertices); } else { glDrawArrays2(mode, 0, vertices); } glDisableClientState2(GL_VERTEX_ARRAY); if (hasTexture) glDisableClientState2(GL_TEXTURE_COORD_ARRAY); if (hasColor) glDisableClientState2(GL_COLOR_ARRAY); //if (hasNormal) glDisableClientState2(GL_NORMAL_ARRAY); } clear(); #endif } void Tesselator::voidBeginAndEndCalls(bool doVoid) { _voidBeginEnd = doVoid; } void Tesselator::enableColor() { _noColor = false; }