| |
| |
| #include "tgl.h" |
| |
| #include "tconvert.h" |
| #include "tofflinegl.h" |
| #include "trop.h" |
| #include "timage_io.h" |
| #include "tcurves.h" |
| |
| #ifndef __sgi |
| #ifdef _WIN32 |
| #include <cstdlib> |
| #include <GL/glut.h> |
| #elif defined(LINUX) |
| #include <GL/glut.h> |
| #else |
| #include <GLUT/glut.h> |
| #endif |
| #endif |
| |
| #if defined(MACOSX) || defined(LINUX) |
| #include <QGLContext> |
| #endif |
| |
| |
| |
| #undef SCALE_BY_GLU |
| |
| |
| |
| |
| namespace |
| { |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| int computeSlices(double radius, double pixelSize = 1.0) |
| { |
| if (radius < 0) |
| return 2; |
| |
| double thetaStep; |
| double temp = pixelSize * 0.5 / radius; |
| |
| if (fabs(1.0 - temp) <= 1) |
| thetaStep = acos(1.0 - temp); |
| else |
| thetaStep = M_PI_4; |
| |
| assert(thetaStep != 0.0); |
| |
| int numberOfSlices = (int)(M_2PI / thetaStep); |
| |
| return numberOfSlices != 0 ? numberOfSlices : 2; |
| } |
| } |
| |
| |
| |
| double tglGetPixelSize2() |
| { |
| double mat[16]; |
| glMatrixMode(GL_MODELVIEW); |
| glGetDoublev(GL_MODELVIEW_MATRIX, mat); |
| |
| double det = fabs(mat[0] * mat[5] - mat[1] * mat[4]); |
| if (det < TConsts::epsilon) |
| det = TConsts::epsilon; |
| return 1.0 / det; |
| } |
| |
| |
| |
| double tglGetTextWidth(const std::string &s, void *font) |
| { |
| double factor = 0.07; |
| double w = 0; |
| for (int i = 0; i < (int)s.length(); i++) |
| w += glutStrokeWidth(font, s[i]); |
| return w * factor; |
| } |
| |
| |
| |
| void tglDrawText(const TPointD &p, const std::string &s, void *character) |
| { |
| #ifndef __sgi |
| glPushMatrix(); |
| glTranslated(p.x, p.y, 0); |
| double factor = 0.07; |
| glScaled(factor, factor, factor); |
| for (int i = 0; i < (int)s.size(); i++) |
| glutStrokeCharacter(character, s[i]); |
| glPopMatrix(); |
| #else |
| assert("Not Yet Implemented" && 0); |
| std::cout << s << std::endl; |
| #endif |
| } |
| |
| |
| |
| void tglDrawText(const TPointD &p, const std::wstring &s, void *character) |
| { |
| #ifndef __sgi |
| glPushMatrix(); |
| glTranslated(p.x, p.y, 0); |
| double factor = 0.07; |
| glScaled(factor, factor, factor); |
| for (int i = 0; i < (int)s.size(); i++) |
| glutStrokeCharacter(character, s[i]); |
| glPopMatrix(); |
| #else |
| assert("Not Yet Implemented" && 0); |
| std::cout << s << std::endl; |
| #endif |
| } |
| |
| |
| |
| void tglDrawSegment(const TPointD &p1, const TPointD &p2) |
| { |
| glBegin(GL_LINES); |
| tglVertex(p1); |
| tglVertex(p2); |
| glEnd(); |
| } |
| |
| |
| |
| void tglDrawCircle(const TPointD ¢er, double radius) |
| { |
| if (radius <= 0) |
| return; |
| |
| double pixelSize = 1; |
| int slices = 60; |
| |
| if (slices <= 0) |
| slices = computeSlices(radius, pixelSize) >> 1; |
| |
| double step = M_PI / slices; |
| double step2 = 2.0 * step; |
| |
| double |
| cos_t, |
| sin_t, |
| cos_ts, sin_ts, t; |
| |
| glPushMatrix(); |
| glTranslated(center.x, center.y, 0.0); |
| glBegin(GL_LINES); |
| |
| cos_t = radius ; |
| sin_t = 0.0; |
| for (t = 0; t + step < M_PI_2; t += step2) { |
| cos_ts = radius * cos(t + step); |
| sin_ts = radius * sin(t + step); |
| |
| glVertex2f(cos_t, sin_t); |
| glVertex2f(cos_ts, sin_ts); |
| |
| glVertex2f(-cos_t, sin_t); |
| glVertex2f(-cos_ts, sin_ts); |
| |
| glVertex2f(-cos_t, -sin_t); |
| glVertex2f(-cos_ts, -sin_ts); |
| |
| glVertex2f(cos_t, -sin_t); |
| glVertex2f(cos_ts, -sin_ts); |
| |
| cos_t = cos_ts; |
| sin_t = sin_ts; |
| } |
| |
| cos_ts = 0.0; |
| sin_ts = radius ; |
| |
| glVertex2f(cos_t, sin_t); |
| glVertex2f(cos_ts, sin_ts); |
| |
| glVertex2f(-cos_t, sin_t); |
| glVertex2f(-cos_ts, sin_ts); |
| |
| glVertex2f(-cos_t, -sin_t); |
| glVertex2f(-cos_ts, -sin_ts); |
| |
| glVertex2f(cos_t, -sin_t); |
| glVertex2f(cos_ts, -sin_ts); |
| |
| glEnd(); |
| glPopMatrix(); |
| } |
| |
| |
| |
| void tglDrawDisk(const TPointD &c, double r) |
| { |
| if (r <= 0) |
| return; |
| |
| double pixelSize = 1; |
| int slices = 60; |
| |
| if (slices <= 0) |
| slices = computeSlices(r, pixelSize) >> 1; |
| |
| glPushMatrix(); |
| glTranslated(c.x, c.y, 0.0); |
| GLUquadric *quadric = gluNewQuadric(); |
| gluDisk(quadric, 0, r, slices, 1); |
| gluDeleteQuadric(quadric); |
| glPopMatrix(); |
| } |
| |
| |
| |
| void tglDrawRect(const TRectD &rect) |
| { |
| glBegin(GL_LINE_LOOP); |
| tglVertex(rect.getP00()); |
| tglVertex(rect.getP10()); |
| tglVertex(rect.getP11()); |
| tglVertex(rect.getP01()); |
| glEnd(); |
| } |
| |
| |
| |
| void tglFillRect(const TRectD &rect) |
| { |
| glBegin(GL_POLYGON); |
| tglVertex(rect.getP00()); |
| tglVertex(rect.getP10()); |
| tglVertex(rect.getP11()); |
| tglVertex(rect.getP01()); |
| glEnd(); |
| } |
| |
| |
| void tglRgbOnlyColorMask() |
| { |
| tglMultColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); |
| tglEnableBlending(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
| } |
| |
| |
| |
| void tglAlphaOnlyColorMask() |
| { |
| tglMultColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); |
| tglEnableBlending(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); |
| } |
| |
| |
| |
| void tglEnableBlending(GLenum src, GLenum dst) |
| { |
| glEnable(GL_BLEND); |
| glBlendFunc(src, dst); |
| } |
| |
| |
| |
| void tglEnableLineSmooth(bool enable, double lineSize) |
| { |
| if (enable) { |
| glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); |
| glEnable(GL_LINE_SMOOTH); |
| glLineWidth(lineSize); |
| } else |
| glDisable(GL_LINE_SMOOTH); |
| } |
| |
| |
| |
| void tglEnablePointSmooth(double pointSize) |
| { |
| glEnable(GL_BLEND); |
| glPointSize(pointSize); |
| } |
| |
| |
| |
| void tglGetColorMask(GLboolean &red, GLboolean &green, GLboolean &blue, GLboolean &alpha) |
| { |
| GLboolean channels[4]; |
| glGetBooleanv(GL_COLOR_WRITEMASK, &channels[0]); |
| red = channels[0], green = channels[1], blue = channels[2], alpha = channels[3]; |
| } |
| |
| |
| |
| void tglMultColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) |
| { |
| GLboolean channels[4]; |
| glGetBooleanv(GL_COLOR_WRITEMASK, &channels[0]); |
| glColorMask(red && channels[0], |
| green && channels[1], |
| blue && channels[2], |
| alpha && channels[3]); |
| } |
| |
| |
| |
| namespace |
| { |
| |
| |
| class GlFontManager |
| { |
| GlFontManager(); |
| |
| public: |
| ~GlFontManager(); |
| static GlFontManager *instance(); |
| bool setFont(void *font = GLUT_BITMAP_TIMES_ROMAN_10); |
| void drawText( |
| std::wstring wtext |
| ); |
| |
| private: |
| static GlFontManager *m_instance; |
| |
| |
| |
| std::map<void *, double> m_fonts; |
| std::vector<TRectD> m_charsBBox; |
| void *m_currentFont; |
| TRaster32P m_fontTexture; |
| GLuint m_base; |
| }; |
| |
| |
| |
| GlFontManager *GlFontManager::m_instance = 0L; |
| |
| |
| |
| GlFontManager::GlFontManager() |
| : m_currentFont(0L), m_base(0) |
| { |
| m_fonts.insert(std::make_pair(GLUT_BITMAP_8_BY_13, 13.0)); |
| m_fonts.insert(std::make_pair(GLUT_BITMAP_9_BY_15, 15.0)); |
| m_fonts.insert(std::make_pair(GLUT_BITMAP_TIMES_ROMAN_10, 10.0)); |
| m_fonts.insert(std::make_pair(GLUT_BITMAP_TIMES_ROMAN_24, 24.0)); |
| m_fonts.insert(std::make_pair(GLUT_BITMAP_HELVETICA_10, 10.0)); |
| m_fonts.insert(std::make_pair(GLUT_BITMAP_HELVETICA_12, 12.0)); |
| m_fonts.insert(std::make_pair(GLUT_BITMAP_HELVETICA_18, 18.0)); |
| bool ok = setFont(); |
| assert(ok); |
| } |
| |
| |
| |
| GlFontManager::~GlFontManager() |
| { |
| m_instance = 0L; |
| } |
| |
| |
| |
| GlFontManager *GlFontManager::instance() |
| { |
| if (!m_instance) |
| m_instance = new GlFontManager(); |
| |
| return m_instance; |
| } |
| |
| |
| |
| bool GlFontManager::setFont(void *font) |
| { |
| |
| std::map<void *, double>::iterator it = |
| m_fonts.find(font); |
| |
| |
| if (it != m_fonts.end()) { |
| m_currentFont = font; |
| |
| glPushAttrib(GL_ALL_ATTRIB_BITS); |
| glPushMatrix(); |
| m_base = glGenLists(256); |
| glListBase(m_base); |
| int i = 0; |
| for (; i < 256; ++i) { |
| glNewList(m_base + i, GL_COMPILE); |
| glutStrokeCharacter(GLUT_STROKE_ROMAN, i); |
| |
| glEndList(); |
| } |
| glPopAttrib(); |
| glPopMatrix(); |
| return true; |
| } |
| return false; |
| } |
| |
| |
| |
| void GlFontManager::drawText( |
| std::wstring wtext |
| ) |
| { |
| if (!m_currentFont) |
| return; |
| |
| std::string text = ::to_string(wtext); |
| const char *textString = text.c_str(); |
| glListBase(m_base); |
| |
| |
| |
| |
| |
| glCallLists((GLuint)strlen(textString), GL_BYTE, textString); |
| |
| } |
| |
| |
| |
| } |
| |
| |
| |
| void tglDraw(const TCubic &cubic, int precision, GLenum pointOrLine) |
| { |
| CHECK_ERRORS_BY_GL; |
| assert(pointOrLine == GL_POINT || pointOrLine == GL_LINE); |
| float ctrlPts[4][3]; |
| |
| ctrlPts[0][0] = cubic.getP0().x; |
| ctrlPts[0][1] = cubic.getP0().y; |
| ctrlPts[0][2] = 0.0; |
| |
| ctrlPts[1][0] = cubic.getP1().x; |
| ctrlPts[1][1] = cubic.getP1().y; |
| ctrlPts[1][2] = 0.0; |
| |
| ctrlPts[2][0] = cubic.getP2().x; |
| ctrlPts[2][1] = cubic.getP2().y; |
| ctrlPts[2][2] = 0.0; |
| |
| ctrlPts[3][0] = cubic.getP3().x; |
| ctrlPts[3][1] = cubic.getP3().y; |
| ctrlPts[3][2] = 0.0; |
| |
| CHECK_ERRORS_BY_GL; |
| glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, &ctrlPts[0][0]); |
| CHECK_ERRORS_BY_GL; |
| glEnable(GL_MAP1_VERTEX_3); |
| CHECK_ERRORS_BY_GL; |
| glMapGrid1f(precision, 0.0, 1.0); |
| CHECK_ERRORS_BY_GL; |
| glEvalMesh1(pointOrLine, 0, precision); |
| CHECK_ERRORS_BY_GL; |
| } |
| |
| |
| |
| void tglDraw(const TRectD &rect, |
| const std::vector<TRaster32P> &textures, |
| bool blending) |
| { |
| double pixelSize2 = tglGetPixelSize2(); |
| |
| unsigned int level = 1; |
| while (pixelSize2 * level * level <= 1.0) |
| level <<= 1; |
| |
| unsigned int texturesCount = (int)textures.size(); |
| if (level > texturesCount) |
| level = texturesCount; |
| |
| level = texturesCount - level; |
| |
| tglDraw(rect, textures[level], blending); |
| } |
| |
| |
| |
| void tglDraw(const TRectD &rect, const TRaster32P &tex, bool blending) |
| { |
| CHECK_ERRORS_BY_GL; |
| glPushAttrib(GL_ALL_ATTRIB_BITS); |
| if (blending) { |
| glEnable(GL_BLEND); |
| glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
| } |
| |
| unsigned int texWidth = 1; |
| unsigned int texHeight = 1; |
| |
| while (texWidth < (unsigned int)tex->getLx()) |
| texWidth = texWidth << 1; |
| |
| while (texHeight < (unsigned int)tex->getLy()) |
| texHeight = texHeight << 1; |
| |
| double lwTex = 1.0; |
| double lhTex = 1.0; |
| |
| TRaster32P texture; |
| unsigned int texLx = (unsigned int)tex->getLx(); |
| unsigned int texLy = (unsigned int)tex->getLy(); |
| |
| if (texWidth != texLx || |
| texHeight != texLy) { |
| texture = TRaster32P(texWidth, texHeight); |
| texture->fill(TPixel32(0, 0, 0, 0)); |
| texture->copy(tex); |
| lwTex = (texLx) / (double)(texWidth); |
| lhTex = (texLy) / (double)(texHeight); |
| if (lwTex > 1.0) |
| lwTex = 1.0; |
| if (lhTex > 1.0) |
| lhTex = 1.0; |
| } else |
| texture = tex; |
| GLenum fmt = |
| #ifdef TNZ_MACHINE_CHANNEL_ORDER_BGRM |
| GL_BGRA_EXT; |
| #elif TNZ_MACHINE_CHANNEL_ORDER_MBGR |
| GL_ABGR_EXT; |
| #elif TNZ_MACHINE_CHANNEL_ORDER_RGBM |
| GL_RGBA; |
| #elif TNZ_MACHINE_CHANNEL_ORDER_MRGB |
| GL_BGRA; |
| #else |
| |
| #error "unknown channel order!" |
| #endif |
| |
| |
| GLuint texId; |
| glGenTextures(1, &texId); |
| |
| glBindTexture(GL_TEXTURE_2D, texId); |
| |
| glPixelStorei(GL_UNPACK_ROW_LENGTH, texture->getWrap()); |
| |
| texture->lock(); |
| glTexImage2D(GL_TEXTURE_2D, |
| 0, |
| 4, |
| texWidth, |
| texHeight, |
| 0, |
| fmt, |
| #ifdef TNZ_MACHINE_CHANNEL_ORDER_MRGB |
| GL_UNSIGNED_INT_8_8_8_8_REV, |
| #else |
| GL_UNSIGNED_BYTE, |
| #endif |
| texture->getRawData()); |
| |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); |
| |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| |
| glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); |
| glEnable(GL_TEXTURE_2D); |
| |
| glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); |
| |
| double rectLx = rect.getLx(); |
| double rectLy = rect.getLy(); |
| |
| tglColor(TPixel32(0, 0, 0, 0)); |
| |
| glPushMatrix(); |
| |
| glTranslated(rect.x0, rect.y0, 0.0); |
| glBegin(GL_POLYGON); |
| |
| glTexCoord2d(0, 0); |
| tglVertex(TPointD(0.0, 0.0)); |
| |
| glTexCoord2d(lwTex, 0); |
| tglVertex(TPointD(rectLx, 0.0)); |
| |
| glTexCoord2d(lwTex, lhTex); |
| tglVertex(TPointD(rectLx, rectLy)); |
| |
| glTexCoord2d(0, lhTex); |
| tglVertex(TPointD(0.0, rectLy)); |
| |
| glEnd(); |
| glDisable(GL_TEXTURE_2D); |
| |
| glPopMatrix(); |
| glPopAttrib(); |
| |
| |
| glDeleteTextures(1, &texId); |
| |
| texture->unlock(); |
| } |
| |
| |
| |
| void tglBuildMipmaps(std::vector<TRaster32P> &rasters, |
| const TFilePath &filepath) |
| { |
| assert(rasters.size() > 0); |
| TRop::ResampleFilterType resampleFilter = TRop::ClosestPixel; |
| TRasterP ras; |
| TImageReader::load(filepath, ras); |
| int rasLx = ras->getLx(); |
| int rasLy = ras->getLy(); |
| |
| int lx = 1; |
| while (lx < rasLx) |
| lx <<= 1; |
| |
| int ly = 1; |
| while (ly < rasLy) |
| ly <<= 1; |
| |
| TRaster32P ras2(lx, ly); |
| double sx = (double)lx / (double)ras->getLx(); |
| double sy = (double)ly / (double)ras->getLy(); |
| #ifndef SCALE_BY_GLU |
| TRop::resample(ras2, ras, TScale(sx, sy), resampleFilter); |
| #else |
| ras->lock(); |
| gluScaleImage(GL_RGBA, ras->getLx(), ras->getLy(), GL_UNSIGNED_BYTE, ras->getRawData(), |
| lx, ly, GL_UNSIGNED_BYTE, ras2->getRawData()); |
| ras->unlock(); |
| #endif |
| |
| rasters[0] = ras2; |
| int ras2Lx = ras2->getLx(); |
| int ras2Ly = ras2->getLy(); |
| for (int i = 1; i < (int)rasters.size(); ++i) { |
| lx >>= 1; |
| ly >>= 1; |
| if (lx < 1) |
| lx = 1; |
| if (ly < 1) |
| ly = 1; |
| rasters[i] = TRaster32P(lx, ly); |
| sx = (double)lx / (double)ras2Lx; |
| sy = (double)ly / (double)ras2Ly; |
| rasters[i] = TRaster32P(lx, ly); |
| #ifndef SCALE_BY_GLU |
| TRop::resample(rasters[i], ras2, TScale(sx, sy), resampleFilter); |
| #else |
| ras2->lock(); |
| gluScaleImage(GL_RGBA, ras->getLx(), ras->getLy(), GL_UNSIGNED_BYTE, ras2->getRawData(), |
| lx, ly, GL_UNSIGNED_BYTE, rasters[i]->getRawData()); |
| ras2->unlock(); |
| #endif |
| } |
| } |
| |
| |
| |
| #if defined(_WIN32) |
| |
| TGlContext tglGetCurrentContext() |
| { |
| return std::make_pair(wglGetCurrentDC(), wglGetCurrentContext()); |
| } |
| |
| void tglMakeCurrent(TGlContext context) |
| { |
| wglMakeCurrent(context.first, context.second); |
| } |
| |
| void tglDoneCurrent(TGlContext) |
| { |
| wglMakeCurrent(NULL, NULL); |
| } |
| |
| #elif defined(LINUX) || defined(__sgi) || defined(MACOSX) |
| |
| TGlContext tglGetCurrentContext() |
| { |
| return reinterpret_cast<TGlContext>( |
| const_cast<QGLContext *>(QGLContext::currentContext())); |
| |
| |
| |
| } |
| |
| void tglMakeCurrent(TGlContext context) |
| { |
| if (context) |
| reinterpret_cast<QGLContext *>(context)->makeCurrent(); |
| else |
| tglDoneCurrent(tglGetCurrentContext()); |
| } |
| |
| void tglDoneCurrent(TGlContext context) |
| { |
| if (context) |
| reinterpret_cast<QGLContext *>(context)->doneCurrent(); |
| } |
| |
| #else |
| #error "unknown platform!" |
| #endif |
| |
| |
| |
| |
| |