#include #include #include #include #include #include #include int dtx::draw() const { int ret = 0; GLenum error; glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texture); if (bpp == bpp_s3tc_dxt5) { glEnable(GL_BLEND); glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA); } glBegin(GL_QUADS); glTexCoord2f(0.0f, 0.0f); glVertex2f(-0.5f, 0.5f); glTexCoord2f(0.0f, 1.0f); glVertex2f(0.5f, 0.5f); glTexCoord2f(1.0f, 1.0f); glVertex2f(0.5f, -0.5f); glTexCoord2f(1.0f, 0.0f); glVertex2f(-0.5f, -0.5f); glEnd(); glFlush(); glDisable(GL_BLEND); glDisable(GL_TEXTURE_2D); while ((error = glGetError()) != GL_NO_ERROR) { ret = -1; fprintf(stderr, "%s:%d: glGetError returned %x\n", __FILE__, __LINE__, error); } return ret; } int dtx::parse(rez::file &f) { uint32_t restype, uversion; if (f.read_le(restype) || f.read_le(uversion)) return -1; const uint32_t exp_type = 0; const int32_t exp_version = -5; int32_t version = uversion; if (restype != exp_type) { std::cerr << f.path() << ": invalid resource type " << restype << ", expected " << exp_type << '\n'; return -1; } else if (version != exp_version) { std::cerr << f.path() << ": invalid or unsupported version " << version << ", expected " << exp_version << '\n'; return -1; } const uint16_t max_mipmaps = 8; uint16_t w, h, n_mipmaps, n_sections, tex_angle; uint32_t iflags, userflags, tex_scale; unsigned char tex_group, n_rtmipmaps, bpp, mipmap_off_nc, mipmap_off, tex_prio; char cmd[128]; if (f.read_le(w) || f.read_le(h) || f.read_le(n_mipmaps) || f.read_le(n_sections)) { std::cerr << f.path() << ": failed to read header\n"; return -1; } else if (!n_mipmaps || n_mipmaps > max_mipmaps) { std::cerr << f.path() << ": invalid number of mipmaps: " << n_mipmaps << '\n'; return -1; } else if (f.read_le(iflags) || f.read_le(userflags)) { std::cerr << f.path() << ": failed to read flags\n"; return -1; } else if (f.read(tex_group) || f.read(n_rtmipmaps) || f.read(bpp) || f.read(mipmap_off_nc) || f.read(mipmap_off) || f.read(tex_prio) || f.read_le(tex_scale) || f.read_le(tex_angle)) { std::cerr << f.path() << ": failed to read extra data\n"; return -1; } else if (bpp != bpp::bpp_32 && bpp != bpp::bpp_s3tc_dxt1 && bpp != bpp::bpp_s3tc_dxt5) { std::cerr << f.path() << ": invalid or unsupported bpp " << std::to_string(bpp) << ", expected " << bpp::bpp_s3tc_dxt1 << ", " << bpp::bpp_32 << " or " << bpp::bpp_s3tc_dxt5 << '\n'; return -1; } else if (f.read(cmd, sizeof cmd)) { std::cerr << f.path() << ": failed to read cmd\n"; return -1; } this->bpp = static_cast(bpp); this->w = w; this->h = h; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); GLint level = 0; for (uint32_t i = 0; i < n_mipmaps; i++) { GLenum format; unsigned long n_pix = (w >> i) * (h >> i); pixdata mipmap; switch (this->bpp) { case bpp_32: format = GL_BGRA; n_pix *= sizeof (uint32_t); break; case bpp_s3tc_dxt1: format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; n_pix >>= 1; break; case bpp_s3tc_dxt5: format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break; default: return -1; } mipmap.reserve(n_pix); while (n_pix) { unsigned char buf[BUFSIZ]; size_t n = n_pix > sizeof buf ? sizeof buf : n_pix; if (f.read(buf, n)) return -1; mipmap.insert(mipmap.end(), buf, &buf[n]); n_pix -= n; } GLenum error; int ret = 0; if (bpp == bpp::bpp_s3tc_dxt1 || bpp == bpp::bpp_s3tc_dxt5) glCompressedTexImage2D(GL_TEXTURE_2D, level++, format, w >> i, h >> i, 0, mipmap.size(), mipmap.data()); else if (bpp == bpp::bpp_32) glTexImage2D(GL_TEXTURE_2D, level++, format, w >> i, h >> i, 0, format, GL_UNSIGNED_BYTE, mipmap.data()); while ((error = glGetError()) != GL_NO_ERROR) { fprintf(stderr, "%s:%d: glGetError returned %x\n", __FILE__, __LINE__, error); ret = -1; } if (ret) return ret; } return 0; } dtx::~dtx() { if (texture) glDeleteTextures(1, &texture); } dtx::dtx() : texture(0) { }