diff --git a/src/scene.cpp b/src/scene.cpp index c40537a7..db51c0fe 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -55,6 +55,9 @@ private: int ntiles; float angle; + GLuint *bufs; + int nbufs; + static Scene *scene; }; @@ -70,10 +73,16 @@ Scene::Scene(float angle) data->tiles = 0; data->ntiles = 0; data->angle = angle; + + data->bufs = 0; + data->nbufs = 0; } Scene::~Scene() { + /* FIXME: this must be done while the GL context is still active. + * Change the architecture to make sure of that. */ + glDeleteBuffers(data->nbufs, data->bufs); delete data; } @@ -131,13 +140,58 @@ void Scene::Render() // XXX: rename to Blit() glRotatef(8.0f * cosf(f), 0.0f, 0.0f, 1.0f); #endif glTranslatef(-320.0f, -240.0f, 0.0f); + // XXX: end of debug stuff - for (int i = 0; i < data->ntiles; i++) - Tiler::BlitTile(data->tiles[i].code, data->tiles[i].x, - data->tiles[i].y, data->tiles[i].z, data->tiles[i].o); + for (int buf = 0, i = 0, n; i < data->ntiles; i = n, buf += 2) + { + /* Generate new vertex / texture coord buffers if necessary */ + if (buf + 2 > data->nbufs) + { + data->bufs = (GLuint *)realloc(data->bufs, (buf + 2) * sizeof(GLuint)); + glGenBuffers(buf + 2 - data->nbufs, data->bufs + data->nbufs); + data->nbufs = buf + 2; + } + + /* Count how many quads will be needed */ + for (n = i + 1; n < data->ntiles; n++) + if (data->tiles[i].code >> 16 != data->tiles[n].code >> 16) + break; + + /* Create a vertex array object */ + float *vertex = (float *)malloc(6 * 3 * (n - i) * sizeof(float)); + float *texture = (float *)malloc(6 * 2 * (n - i) * sizeof(float)); + + for (int j = i; j < n; j++) + { + Tiler::BlitTile(data->tiles[j].code, data->tiles[j].x, + data->tiles[j].y, data->tiles[j].z, data->tiles[j].o, + vertex + 18 * (j - i), texture + 12 * (j - i)); + } + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + glBindBuffer(GL_ARRAY_BUFFER, data->bufs[buf]); + glBufferData(GL_ARRAY_BUFFER, 6 * 3 * (n - i) * sizeof(float), + vertex, GL_DYNAMIC_DRAW); + glVertexPointer(3, GL_FLOAT, 0, NULL); + + glBindBuffer(GL_ARRAY_BUFFER, data->bufs[buf + 1]); + glBufferData(GL_ARRAY_BUFFER, 6 * 2 * (n - i) * sizeof(float), + texture, GL_DYNAMIC_DRAW); + glTexCoordPointer(2, GL_FLOAT, 0, NULL); + + Tiler::Bind(data->tiles[i].code); + glDrawArrays(GL_TRIANGLES, 0, (n - i) * 6); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + free(vertex); + free(texture); + } glPopMatrix(); - // XXX: end of debug stuff free(data->tiles); data->tiles = 0; diff --git a/src/tiler.cpp b/src/tiler.cpp index f484a547..0359d60b 100644 --- a/src/tiler.cpp +++ b/src/tiler.cpp @@ -93,7 +93,25 @@ int2 Tiler::GetCount(int id) return tileset->GetCount(); } -void Tiler::BlitTile(uint32_t code, int x, int y, int z, int o) +void Tiler::Bind(uint32_t code) +{ + int id = (code >> 16) - 1; /* ID 0 is for the empty tileset */ + + TileSet *tileset = (TileSet *)data->tilesets.GetEntity(id); +#if !FINAL_RELEASE + if (!tileset) + { + if (id != data->lasterror) + fprintf(stderr, "ERROR: binding null tiler #%i\n", id); + data->lasterror = id; + return; + } +#endif + tileset->Bind(); +} + +void Tiler::BlitTile(uint32_t code, int x, int y, int z, int o, + float *vertex, float *texture) { int id = (code >> 16) - 1; /* ID 0 is for the empty tileset */ @@ -107,6 +125,6 @@ void Tiler::BlitTile(uint32_t code, int x, int y, int z, int o) return; } #endif - tileset->BlitTile(code & 0xffff, x, y, z, o); + tileset->BlitTile(code & 0xffff, x, y, z, o, vertex, texture); } diff --git a/src/tiler.h b/src/tiler.h index 0c8d3484..26174ba7 100644 --- a/src/tiler.h +++ b/src/tiler.h @@ -27,7 +27,9 @@ public: static int2 GetSize(int id); static int2 GetCount(int id); - static void BlitTile(uint32_t code, int x, int y, int z, int o); + static void Bind(uint32_t code); + static void BlitTile(uint32_t code, int x, int y, int z, int o, + float *vertex, float *texture); }; #endif // __DH_TILER_H__ diff --git a/src/tileset.cpp b/src/tileset.cpp index b29a52d1..0bd53b16 100644 --- a/src/tileset.cpp +++ b/src/tileset.cpp @@ -167,7 +167,14 @@ int2 TileSet::GetCount() const return data->count; } -void TileSet::BlitTile(uint32_t id, int x, int y, int z, int o) +void TileSet::Bind() +{ + if (!data->img) + glBindTexture(GL_TEXTURE_2D, data->texture); +} + +void TileSet::BlitTile(uint32_t id, int x, int y, int z, int o, + float *vertex, float *texture) { float tx = data->tx * ((id & 0xffff) % data->count.i); float ty = data->ty * ((id & 0xffff) / data->count.i); @@ -179,17 +186,48 @@ void TileSet::BlitTile(uint32_t id, int x, int y, int z, int o) if (!data->img) { - glBindTexture(GL_TEXTURE_2D, data->texture); - glBegin(GL_QUADS); - glTexCoord2f(tx, ty); - glVertex3f(x, dilate * (y + dy), dilate * (z + dz)); - glTexCoord2f(tx + data->tx, ty); - glVertex3f(x + dx, dilate * (y + dy), dilate * (z + dz)); - glTexCoord2f(tx + data->tx, ty + data->ty); - glVertex3f(x + dx, dilate * y, dilate * z); - glTexCoord2f(tx, ty + data->ty); - glVertex3f(x, dilate * y, dilate * z); - glEnd(); + float tmp[10]; + + *vertex++ = tmp[0] = x; + *vertex++ = tmp[1] = dilate * (y + dy); + *vertex++ = tmp[2] = dilate * (z + dz); + *texture++ = tmp[3] = tx; + *texture++ = tmp[4] = ty; + + *vertex++ = x + dx; + *vertex++ = dilate * (y + dy); + *vertex++ = dilate * (z + dz); + *texture++ = tx + data->tx; + *texture++ = ty; + + *vertex++ = tmp[5] = x + dx; + *vertex++ = tmp[6] = dilate * y; + *vertex++ = tmp[7] = dilate * z; + *texture++ = tmp[8] = tx + data->tx; + *texture++ = tmp[9] = ty + data->ty; + + *vertex++ = tmp[0]; + *vertex++ = tmp[1]; + *vertex++ = tmp[2]; + *texture++ = tmp[3]; + *texture++ = tmp[4]; + + *vertex++ = tmp[5]; + *vertex++ = tmp[6]; + *vertex++ = tmp[7]; + *texture++ = tmp[8]; + *texture++ = tmp[9]; + + *vertex++ = x; + *vertex++ = dilate * y; + *vertex++ = dilate * z; + *texture++ = tx; + *texture++ = ty + data->ty; + } + else + { + memset(vertex, 0, 3 * sizeof(float)); + memset(texture, 0, 2 * sizeof(float)); } } diff --git a/src/tileset.h b/src/tileset.h index b7c45f76..e62c07a7 100644 --- a/src/tileset.h +++ b/src/tileset.h @@ -40,7 +40,9 @@ public: /* New methods */ int2 GetSize() const; int2 GetCount() const; - void BlitTile(uint32_t id, int x, int y, int z, int o); + void Bind(); + void BlitTile(uint32_t id, int x, int y, int z, int o, + float *vertex, float *texture); private: TileSetData *data;