diff options
Diffstat (limited to 'layoutgl/widget.cpp')
-rw-r--r-- | layoutgl/widget.cpp | 389 |
1 files changed, 389 insertions, 0 deletions
diff --git a/layoutgl/widget.cpp b/layoutgl/widget.cpp new file mode 100644 index 0000000..0758e88 --- /dev/null +++ b/layoutgl/widget.cpp @@ -0,0 +1,389 @@ +#include "widget.h" + +LGLWidget::LGLWidget(QWidget *parent) : + QGLWidget(parent), m_layout(0) { +} + + +void LGLWidget::setLayout(LYTLayout *layout) { + // TODO: cleanup stuff for previous layout + + m_layout = layout; + setFixedSize(layout->width, layout->height); +} + + +void LGLWidget::initializeGL() { + qDebug() << "initialising GL"; + glClearColor(0.0, 0.0, 0.0, 0.0); + glEnable(GL_TEXTURE_2D); + + // this makes texture transparency work + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + // makes glColor value blend with textures + glEnable(GL_COLOR_MATERIAL); + + m_texMgr.setup(this, m_layout); +} + + +void LGLWidget::resizeGL(int w, int h) { + glViewport(0, 0, (GLint)w, (GLint)h); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(-304, 304, -228, 228, -100, 100); + glMatrixMode(GL_MODELVIEW); +} + + +void LGLWidget::paintGL() { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + if (m_layout == 0) + return; + + glLoadIdentity(); + + renderPane(m_layout->rootPane); +} + +void LGLWidget::renderPane(const LYTPane *pane) { + glPushMatrix(); + + glScalef(pane->xScale, pane->yScale, 1.0f); + glRotatef(pane->xRot, 1.0f, 0.0f, 0.0f); + glRotatef(pane->yRot, 0.0f, 1.0f, 0.0f); + glRotatef(pane->zRot, 0.0f, 0.0f, 1.0f); + glTranslatef(pane->xTrans, pane->yTrans, pane->zTrans); + //qDebug() << "Translating by" << pane->xTrans << pane->yTrans << pane->zTrans; + + switch (pane->type()) { + case LYTPane::PictureType: + drawPicture((LYTPicture*)pane); + break; + case LYTPane::WindowType: + drawWindow((LYTWindow*)pane); + break; + } + + foreach (const LYTPane *childPane, pane->children) + renderPane(childPane); + + //qDebug() << "Popping"; + glPopMatrix(); +} + +void LGLWidget::drawPicture(const LYTPicture *pic) { + float dX = pic->drawnVertexX(); + float dY = pic->drawnVertexY(); + //qDebug() << "Drawing" << dX << dY << pic->width << pic->height; + + useMaterial(pic->materialName); + + drawQuad(dX, dY, pic->width, pic->height, pic->texCoords, pic->vtxColours, pic->alpha); + + glColor3ub(255, 255, 255); + renderText(dX, (dY-pic->height)+10, 0, pic->name); +} + +struct TexFlipBit { + quint8 bits[8]; + quint8 one, two; +}; + +static const TexFlipBit TextureFlipInfo[6] = { + {{0,0,1,0,0,1,1,1},0,1}, + {{1,0,0,0,1,1,0,1},0,1}, + {{0,1,1,1,0,0,1,0},0,1}, + {{0,1,0,0,1,1,1,0},1,0}, + {{1,1,0,1,1,0,0,0},0,1}, + {{1,0,1,1,0,0,0,1},1,0} +}; + +void LGLWidget::dealWithWindowFrame(LYTTexCoords &coords, const QString &materialName, + int flipType, float pieceWidth, float pieceHeight, + int rep1, int rep2, int rep3, int rep4) { + // What are you DOING Nintendo.. the code for this is a mess! + // I seriously don't get it. + // I am also using a terrible hack here. + const TexFlipBit &info = TextureFlipInfo[flipType]; + + qreal *hack = (qreal*)(&coords.coord[0]); + + float assign1 = info.bits[rep1 + info.one]; + hack[rep1 + info.one] = assign1; + hack[rep3 + info.one] = assign1; + + float assign2 = info.bits[rep1 + info.two]; + hack[rep1 + info.two] = assign2; + hack[rep2 + info.two] = assign2; + + float texSize[2]; + getTextureSize(materialName, &texSize[0], &texSize[1]); + + float assign3 = info.bits[rep1 + info.one] + (pieceWidth / ((info.bits[rep2 + info.one] - info.bits[rep1 + info.one]) * texSize[info.one])); + hack[rep2 + info.one] = assign3; + hack[rep4 + info.one] = assign3; + + float assign4 = info.bits[rep1 + info.two] + (pieceHeight / ((info.bits[rep3 + info.two] - info.bits[rep1 + info.two]) * texSize[info.two])); + hack[rep3 + info.two] = assign4; + hack[rep4 + info.two] = assign4; +} + +void LGLWidget::drawWindow(const LYTWindow *wnd) { + float dX = wnd->drawnVertexX(); + float dY = wnd->drawnVertexY(); + + // get the frame size + float frameLeft, frameTop, frameRight, frameBottom; + + switch (wnd->frames.count()) { + case 1: + float oneW, oneH; + getTextureSize(wnd->frames.at(0)->materialName, &oneW, &oneH); + frameLeft = frameRight = oneW; + frameTop = frameBottom = oneH; + break; + case 4: case 8: + getTextureSize(wnd->frames.at(0)->materialName, &frameLeft, &frameTop); + getTextureSize(wnd->frames.at(3)->materialName, &frameRight, &frameBottom); + break; + } + + // draw the content + useMaterial(wnd->contentMaterialName); + qDebug() << "content material:" << wnd->contentMaterialName; + drawQuad( + dX + frameLeft - wnd->contentOverflowLeft, + dY - frameTop + wnd->contentOverflowTop, + ((wnd->contentOverflowLeft + (wnd->width - frameLeft)) - frameRight) + wnd->contentOverflowRight, + ((wnd->contentOverflowTop + (wnd->height - frameTop)) - frameBottom) + wnd->contentOverflowBottom, + wnd->contentTexCoords, wnd->contentVtxColours, wnd->alpha); + + // deal with the frame + LYTTexCoords texCoords; + + switch (wnd->frames.count()) { + case 1: + { + const LYTWindowFrame &frame = *wnd->frames.first(); + const LYTMaterial &mat = getMaterial(frame.materialName); + + if (!mat.texMaps.empty()) { + useMaterial(mat); + + // top left + float pieceWidth = wnd->width - frameRight; + float pieceHeight = frameTop; + + dealWithWindowFrame(texCoords, frame.materialName, 0, pieceWidth, pieceHeight, 0, 2, 4, 6); + drawQuad(dX, dY, pieceWidth, pieceHeight, 1, &texCoords, 0, wnd->alpha); + + // top right + pieceWidth = frameRight; + pieceHeight = wnd->height - frameBottom; + + dealWithWindowFrame(texCoords, frame.materialName, 1, pieceWidth, pieceHeight, 2, 0, 6, 4); + + drawQuad(dX + wnd->width - frameRight, dY, pieceWidth, pieceHeight, + 1, &texCoords, 0, wnd->alpha); + + // bottom left + pieceWidth = frameLeft; + pieceHeight = wnd->height - frameTop; + + dealWithWindowFrame(texCoords, frame.materialName, 2, pieceWidth, pieceHeight, 4, 6, 0, 2); + + drawQuad(dX, dY - frameTop, pieceWidth, pieceHeight, + 1, &texCoords, 0, wnd->alpha); + + // bottom right + pieceWidth = wnd->width - frameLeft; + pieceHeight = frameBottom; + + dealWithWindowFrame(texCoords, frame.materialName, 4, pieceWidth, pieceHeight, 6, 4, 2, 0); + + drawQuad(dX + frameLeft, dY - wnd->height + frameBottom, pieceWidth, pieceHeight, + 1, &texCoords, 0, wnd->alpha); + } + } + break; + case 4: + { + // top left + const LYTWindowFrame &fTL = *wnd->frames.at(0); + const LYTMaterial &mTL = getMaterial(fTL.materialName); + + if (!mTL.texMaps.empty()) { + useMaterial(mTL); + + float pieceWidth = wnd->width - frameRight; + float pieceHeight = frameTop; + + dealWithWindowFrame(texCoords, fTL.materialName, fTL.type, pieceWidth, pieceHeight, 0, 2, 4, 6); + drawQuad(dX, dY, pieceWidth, pieceHeight, 1, &texCoords, 0, wnd->alpha); + } + + // top right + const LYTWindowFrame &fTR = *wnd->frames.at(1); + const LYTMaterial &mTR = getMaterial(fTR.materialName); + + if (!mTR.texMaps.empty()) { + useMaterial(mTR); + + float pieceWidth = frameRight; + float pieceHeight = wnd->height - frameBottom; + + dealWithWindowFrame(texCoords, fTR.materialName, fTR.type, pieceWidth, pieceHeight, 2, 0, 6, 4); + + drawQuad(dX + wnd->width - frameRight, dY, pieceWidth, pieceHeight, + 1, &texCoords, 0, wnd->alpha); + } + + // bottom left + const LYTWindowFrame &fBL = *wnd->frames.at(2); + const LYTMaterial &mBL = getMaterial(fBL.materialName); + + if (!mBL.texMaps.empty()) { + useMaterial(mBL); + + float pieceWidth = frameLeft; + float pieceHeight = wnd->height - frameTop; + + dealWithWindowFrame(texCoords, fBL.materialName, fBL.type, pieceWidth, pieceHeight, 4, 6, 0, 2); + + drawQuad(dX, dY - frameTop, pieceWidth, pieceHeight, + 1, &texCoords, 0, wnd->alpha); + } + + const LYTWindowFrame &fBR = *wnd->frames.at(3); + const LYTMaterial &mBR = getMaterial(fBR.materialName); + + // bottom right + if (!mBR.texMaps.empty()) { + useMaterial(mBR); + + float pieceWidth = frameRight; + float pieceHeight = wnd->height - frameBottom; + + dealWithWindowFrame(texCoords, fBR.materialName, fBR.type, pieceWidth, pieceHeight, 6, 4, 0, 2); + + drawQuad(dX + frameLeft, dY - wnd->height + frameBottom, pieceWidth, pieceHeight, + 1, &texCoords, 0, wnd->alpha); + } + } + break; + default: + qDebug() << "unhandled window frame count" << wnd->frames.count(); + } +} + +static GLint GLWrapModes[] = { + GL_CLAMP_TO_EDGE, // Clamp + GL_REPEAT, // Repeat + GL_MIRRORED_REPEAT, // Mirror +}; + +void LGLWidget::useMaterial(const QString &materialName) { + const LYTMaterial *mat = m_layout->materials.getMaterialByName(materialName); + + useMaterial(*mat); +} + +void LGLWidget::useMaterial(const LYTMaterial &mat) { + int cutAt = mat.texMaps.count(); + + for (int i = 0; i < cutAt; i++) { + const LYTTexMap &texMap = mat.texMaps.at(i); + + const QString &texName = texMap.textureName; + GLuint texID = m_texMgr.glTextureForName(texName); + + glActiveTexture(GL_TEXTURE0 + i); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, texID); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GLWrapModes[texMap.wrap_s]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GLWrapModes[texMap.wrap_t]); + + // is there a matching TexSRT? + // TODO: fix this + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + + if (mat.texSRTs.count() > i) { + const LYTTexSRT &srt = mat.texSRTs.at(i); + + glScalef(srt.xScale, srt.yScale, 1.0f); + // rotate? + glTranslatef(srt.xTrans, -srt.yTrans, 0.0f); + } + + glMatrixMode(GL_MODELVIEW); + } + + for (int i = cutAt; i < 8; i++) { + glActiveTexture(GL_TEXTURE0 + i); + glDisable(GL_TEXTURE_2D); + } + + glActiveTexture(GL_TEXTURE0); +} + +void LGLWidget::drawQuad(float x, float y, float w, float h, const QVector<LYTTexCoords> &texCoords, const QColor *colours, uchar alpha) { + drawQuad(x, y, w, h, texCoords.count(), texCoords.constData(), colours, alpha); +} + +void LGLWidget::drawQuad(float x, float y, float w, float h, int texCoordCount, const LYTTexCoords *texCoords, const QColor *colours, uchar alpha) { + if (!colours) + glColor4ub(255, 255, 255, 255); + + glBegin(GL_QUADS); + + for (int i = 0; i < texCoordCount; i++) + glMultiTexCoord2f(GL_TEXTURE0_ARB+i, texCoords[i].coord[0].x(), 1.0f-texCoords[i].coord[0].y()); + + if (colours) + qglColor(colours[0]); + glVertex2f(x, y); + + for (int i = 0; i < texCoordCount; i++) + glMultiTexCoord2f(GL_TEXTURE0_ARB+i, texCoords[i].coord[1].x(), 1.0f-texCoords[i].coord[1].y()); + + if (colours) + qglColor(colours[1]); + glVertex2f(x + w, y); + + for (int i = 0; i < texCoordCount; i++) + glMultiTexCoord2f(GL_TEXTURE0_ARB+i, texCoords[i].coord[3].x(), 1.0f-texCoords[i].coord[3].y()); + + if (colours) + qglColor(colours[2]); + glVertex2f(x + w, y - h); + + for (int i = 0; i < texCoordCount; i++) + glMultiTexCoord2f(GL_TEXTURE0_ARB+i, texCoords[i].coord[2].x(), 1.0f-texCoords[i].coord[2].y()); + + if (colours) + qglColor(colours[3]); + glVertex2f(x, y - h); + + glEnd(); +} + + +void LGLWidget::getTextureSize(const QString &materialName, float *w, float *h) { + const LYTMaterial *mat = m_layout->materials.getMaterialByName(materialName); + + if (mat->texMaps.count() == 0) { + *w = 0.0f; + *h = 0.0f; + } else { + const LYTTexMap &tm = mat->texMaps.first(); + + QImage img = m_texMgr.imageForName(tm.textureName); + *w = img.width(); + *h = img.height(); + } +} + |