bool snapshot () { nosnapshot (); if (! freeze ()) return false; setPixelCoords (true); glGenTextures (1, &snapshotTextureName); int w = winWidth; int h = winHeight; if (! NPOT_textures) { w = getNextPOT(winWidth); h = getNextPOT(winHeight); snapTexW = ((double)winWidth) / w; snapTexH = ((double)winHeight) / h; } glBindTexture(GL_TEXTURE_2D, snapshotTextureName); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); texImage2D (GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, snapshotTextureName); // Render scene glDepthMask (GL_TRUE); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen glDepthMask (GL_FALSE); drawBackDrop (); // Draw the room drawZBuffer(cameraX, cameraY, false); glEnable(GL_DEPTH_TEST); drawPeople (); // Then add any moving characters... glDisable(GL_DEPTH_TEST); viewSpeech (); // ...and anything being said drawStatusBar (); // Copy Our ViewPort To The Texture copyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, viewportOffsetX, viewportOffsetY, winWidth, winHeight, snapshotTextureName); setPixelCoords (false); unfreeze (false); return true; }
// Paste a scaled sprite onto the backdrop void fixScaleSprite (int x, int y, sprite & single, const spritePalette & fontPal, onScreenPerson * thisPerson, int camX, int camY, bool mirror) { float scale = thisPerson-> scale; bool useZB = ! (thisPerson->extra & EXTRA_NOZB); bool light = ! (thisPerson->extra & EXTRA_NOLITE); if (scale <= 0.05) return; float tx1 = (float)(single.tex_x) / fontPal.tex_w[single.texNum]; float ty1 = (float) 1.0/fontPal.tex_h[single.texNum];//0.0; float tx2 = (float)(single.tex_x + single.width) / fontPal.tex_w[single.texNum]; float ty2 = (float)(single.height+1)/fontPal.tex_h[single.texNum]; int diffX = (int)(((float)single.width) * scale); int diffY = (int)(((float)single.height) * scale); int x1; if (single.xhot < 0) x1 = x - (int)((mirror ? (float) (single.width - single.xhot) : (float)(single.xhot+1) ) * scale); else x1 = x - (int)((mirror ? (float) (single.width - (single.xhot+1)) : (float)single.xhot ) * scale); int y1 = y - (int)((single.yhot - thisPerson->floaty) * scale); float spriteWidth = diffX; float spriteHeight = diffY; if (x1 < 0) diffX += x1; if (y1 < 0) diffY += y1; if (x1 + diffX > sceneWidth) diffX = sceneWidth - x1; if (y1 + diffY > sceneHeight) diffY = sceneHeight - y1; if (diffX < 0) return; if (diffY < 0) return; GLfloat z; if (useZB && zBuffer.numPanels) { int i; for (i = 1; i<zBuffer.numPanels; i++) { if (zBuffer.panel[i] >= y + cameraY) { i--; break; } } z = 0.999 - (double) i * (1.0 / 128.0); } else { z = -0.5; } float ltx1, btx1; float ltx2, btx2; float lty1, bty1; float lty2, bty2; if (! NPOT_textures) { ltx1 = lightMap.texW * x1 / sceneWidth; ltx2 = lightMap.texW * (x1+spriteWidth) / sceneWidth; lty1 = lightMap.texH * y1 / sceneHeight; lty2 = lightMap.texH * (y1+spriteHeight) / sceneHeight; btx1 = backdropTexW * x1 / sceneWidth; btx2 = backdropTexW * (x1+spriteWidth) / sceneWidth; bty1 = backdropTexH * y1 / sceneHeight; bty2 = backdropTexH * (y1+spriteHeight) / sceneHeight; } else { btx1 = ltx1 = (float) x1 / sceneWidth; btx2 = ltx2 = (float) (x1+spriteWidth) / sceneWidth; bty1 = lty1 = (float) y1 / sceneHeight; bty2 = lty2 = (float) (y1+spriteHeight) / sceneHeight; } const GLfloat ltexCoords[] = { ltx1, lty1, ltx2, lty1, ltx1, lty2, ltx2, lty2 }; const GLfloat btexCoords[] = { btx1, bty1, btx2, bty1, btx1, bty2, btx2, bty2 }; if (light && lightMap.data) { if (lightMapMode == LIGHTMAPMODE_HOTSPOT) { int lx=x+cameraX; int ly=y+cameraY; if (lx<0 || ly<0 || lx>=sceneWidth || ly>=sceneHeight) { curLight[0] = curLight[1] = curLight[2] = 255; } else { GLubyte *target = lightMap.data + (ly*sceneWidth + lx)*4; curLight[0] = target[0]; curLight[1] = target[1]; curLight[2] = target[2]; } } else if (lightMapMode == LIGHTMAPMODE_PIXEL) { curLight[0] = curLight[1] = curLight[2] = 255; glActiveTexture(GL_TEXTURE1); glBindTexture (GL_TEXTURE_2D, lightMap.name); } } else { curLight[0] = curLight[1] = curLight[2] = 255; } glActiveTexture(GL_TEXTURE2); glBindTexture (GL_TEXTURE_2D, backdropTextureName); glActiveTexture(GL_TEXTURE0); setPixelCoords (true); GLfloat xoffset = 0.0f; while (xoffset < diffX) { int w = (diffX-xoffset < viewportWidth) ? (int) (diffX-xoffset) : viewportWidth; GLfloat yoffset = 0.0f; while (yoffset < diffY) { int h = (diffY-yoffset< viewportHeight) ? (int) (diffY-yoffset) : viewportHeight; // Render the scene - first the old backdrop (so that it'll show through when the z-buffer is active //glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glBindTexture (GL_TEXTURE_2D, backdropTextureName); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); const GLfloat vertices[] = { -x1-xoffset, -y1-yoffset, 0.0f, sceneWidth-x1-xoffset, -y1-yoffset, 0.0f, -x1-xoffset, sceneHeight-y1-yoffset, 0.0f, sceneWidth-x1-xoffset, sceneHeight-y1-yoffset, 0.0f }; const GLfloat texCoords[] = { 0.0f, 0.0f, backdropTexW, 0.0f, 0.0f, backdropTexH, backdropTexW, backdropTexH }; glUseProgram(shader.texture); setPMVMatrix(shader.texture); drawQuad(shader.texture, vertices, 1, texCoords); // The z-buffer if (useZB) { glDepthMask (GL_TRUE); glClear(GL_DEPTH_BUFFER_BIT); drawZBuffer((int) (x1+xoffset+camX), (int) (y1+yoffset+camY), false); glDepthMask (GL_FALSE); glEnable(GL_DEPTH_TEST); } // Then the sprite glUseProgram(shader.paste); GLint uniform = glGetUniformLocation(shader.paste, "useLightTexture"); if (uniform >= 0) glUniform1i(uniform, light && lightMapMode == LIGHTMAPMODE_PIXEL && lightMap.data); setPMVMatrix(shader.paste); setDrawMode (thisPerson); glBindTexture (GL_TEXTURE_2D, fontPal.tex_names[single.texNum]); const GLfloat vertices2[] = { -xoffset, -yoffset, z, spriteWidth-xoffset, -yoffset, z, -xoffset, spriteHeight-yoffset, z, spriteWidth-xoffset, spriteHeight-yoffset, z }; if (! mirror) { GLfloat tx3 = tx1; tx1 = tx2; tx2 = tx3; } const GLfloat texCoords2[] = { tx2, ty1, tx1, ty1, tx2, ty2, tx1, ty2 }; drawQuad(shader.paste, vertices2, 3, texCoords2, ltexCoords, btexCoords); setSecondaryColor(0., 0., 0., 1.); //glDisable(GL_COLOR_SUM); FIXME: replace line? // Copy Our ViewPort To The Texture glUseProgram(0); copyTexSubImage2D(GL_TEXTURE_2D, 0, (int) ((x1<0) ? xoffset: x1+xoffset), (int) ((y1<0) ? yoffset: y1+yoffset), (int) ((x1<0) ?viewportOffsetX-x1:viewportOffsetX), (int) ((y1<0) ?viewportOffsetY-y1:viewportOffsetY), w, h, backdropTextureName); yoffset += viewportHeight; } xoffset += viewportWidth; } setPixelCoords (false); glUseProgram(0); }
void sludgeDisplay () { #if defined(HAVE_GLES2) #ifndef GL_DEPTH24_STENCIL8 #define GL_DEPTH24_STENCIL8 0x88F0 #endif // create an FBO static GLuint fbo = 0; static GLuint fbo_tex = 0; static GLuint fbo_rbo = 0; static float fbo_tex_w, fbo_tex_h; static GLuint fbo_shad, fbo_vert, fbo_frag; if(fbo==0) { // create FBO int width = 1; while (width<realWinWidth) width *= 2; int height = 1; while (height<realWinHeight) height *= 2; glGenFramebuffers(1, &fbo); glGenTextures(1, &fbo_tex); glGenRenderbuffers(1, &fbo_rbo); glBindTexture(GL_TEXTURE_2D, fbo_tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); glBindTexture(GL_TEXTURE_2D, 0); glBindRenderbuffer(GL_RENDERBUFFER, fbo_rbo); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); glBindRenderbuffer(GL_RENDERBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo_tex, 0); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo_rbo); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fbo_rbo); GLenum ret = glCheckFramebufferStatus(GL_FRAMEBUFFER); printf("Screen is %dx%d, FBO(%dx%d) Status = 0x%04X\n", realWinWidth, realWinHeight, width, height, ret); glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, fbo); fbo_tex_w = (float)realWinWidth / width; fbo_tex_h = (float)realWinHeight / height; // create shader for blitting the fbo... const char _blit_vsh[] = " \n\t" \ "attribute highp vec2 aPosition; \n\t" \ "attribute highp vec2 aTexCoord; \n\t" \ "varying mediump vec2 vTexCoord; \n\t" \ "void main(){ \n\t" \ "gl_Position = vec4(aPosition.x, aPosition.y, 0.0, 1.0);\n\t" \ "vTexCoord = aTexCoord; \n\t" \ "} \n\t"; const char _blit_fsh[] = " \n\t" \ "uniform sampler2D uTex; \n\t" \ "varying mediump vec2 vTexCoord; \n\t" \ "void main(){ \n\t" \ "gl_FragColor = texture2D(uTex, vTexCoord); \n\t" \ "} \n\t"; GLint success; fbo_frag = glCreateShader( GL_FRAGMENT_SHADER ); const char* src[1]; src[0] = _blit_fsh; glShaderSource( fbo_frag, 1, src, NULL ); glCompileShader( fbo_frag ); glGetShaderiv( fbo_frag, GL_COMPILE_STATUS, &success ); if (!success) { printf("Failed to produce default fragment shader.\n"); } fbo_vert = glCreateShader( GL_VERTEX_SHADER ); src[0] = _blit_vsh; glShaderSource( fbo_vert, 1, src, NULL ); glCompileShader( fbo_vert ); glGetShaderiv( fbo_vert, GL_COMPILE_STATUS, &success ); if( !success ) { printf( "Failed to produce default vertex shader.\n" ); } fbo_shad = glCreateProgram(); glBindAttribLocation( fbo_shad, 0, "aPosition" ); glBindAttribLocation( fbo_shad, 1, "aTexCoord" ); glAttachShader( fbo_shad, fbo_frag ); glAttachShader( fbo_shad, fbo_vert ); glLinkProgram( fbo_shad ); glGetProgramiv( fbo_shad, GL_LINK_STATUS, &success ); if( !success ) { printf( "Failed to link default program.\n" ); } glUniform1i( glGetUniformLocation( fbo_shad, "uTex" ), 0 ); } #endif glDepthMask (GL_TRUE); // glClearColor(0.5, 0.5, 1.0, 0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen glDepthMask (GL_FALSE); drawBackDrop (); // Draw the room drawZBuffer(cameraX, cameraY, false); glEnable(GL_DEPTH_TEST); drawPeople (); // Then add any moving characters... glDisable(GL_DEPTH_TEST); viewSpeech (); // ...and anything being said drawStatusBar (); displayCursor (); if (brightnessLevel < 255) fixBrightness (); // This is for transitionLevel special effects glFlush(); #if !defined(HAVE_GLES2) SDL_GL_SwapBuffers(); #else if(fbo) { // blit the FBO now glBindFramebuffer(GL_FRAMEBUFFER, 0); GLuint old_prog; glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&old_prog); glUseProgram(fbo_shad); glViewport(0, 0, realWinWidth, realWinHeight); const float vert[] = { -1.0, -1.0, +0.0, +0.0, +1.0, -1.0, fbo_tex_w, +0.0, -1.0, +1.0, +0.0, fbo_tex_h, +1.0, +1.0, fbo_tex_w, fbo_tex_h }; glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, fbo_tex); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (float*)vert); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (float*)vert + 2); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glBindTexture(GL_TEXTURE_2D, 0); glUseProgram(old_prog); glViewport (viewportOffsetX, viewportOffsetY, viewportWidth, viewportHeight); } EGL_SwapBuffers(); if(fbo) { // Rebind FBO now glBindFramebuffer(GL_FRAMEBUFFER, fbo); } #endif }