title: OpenGL- Render to texture- a specific area of screen
body: <p>I implemented FBO on my OpenGL Game. and Im rendering what is rendered to screen to a texture, the problem is that rendering to texture starts from lower left corner. look:</p>
  
  <p>what is rendered to Default Frame Buffer:</p>
  
  <p><a href="https://i.stack.imgur.com/YvN25.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/YvN25.jpg" alt="enter image description here"></a></p>
  
  <p>what is rendered to texture attached to FBO:</p>
  
  <p><a href="https://i.stack.imgur.com/r7LnJ.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/r7LnJ.jpg" alt="enter image description here"></a></p>
  
  <p>But Where i want to be Rendered to Texture is:</p>
  
  <p><a href="https://i.stack.imgur.com/d8TRv.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/d8TRv.jpg" alt="enter image description here"></a></p>
  
  <p>how can i do this? here is the renderer Calass (the FBO operation is done in <code>onDrawFrame</code> function):</p>
  
  <pre><code>public class CurlRenderer implements GLSurfaceView.Renderer {
  
  // Constant for requesting right page rect.
  public static final int PAGE = 1;
  // Set to true for checking quickly how perspective projection looks.
  private static final boolean USE_PERSPECTIVE_PROJECTION = false;
  // Background fill color.
  private int mBackgroundColor;
  // Curl meshes used for static and dynamic rendering.
  private CurlMesh mCurlMesh;
  private RectF mMargins = new RectF();
  private CurlRenderer.Observer mObserver;
  // Page rectangles.
  private RectF mPageRect;
  // View mode.
  // Screen size.
  private int mViewportWidth, mViewportHeight;
  // Rect for render area.
  private RectF mViewRect = new RectF();
  private boolean first = true;
  int[] fb, renderTex; 
  int texW = 300; 
  int texH = 256; 
  IntBuffer texBuffer;
  int[] buf = new int[texW * texH];
  GL11ExtensionPack gl11ep ;
  /**
   * Basic constructor.
   */
  public CurlRenderer(CurlRenderer.Observer observer) {
      mObserver = observer;
      mCurlMesh = new CurlMesh(0);
      mPageRect = new RectF();
  }
  
  /**
   * Adds CurlMesh to this renderer.
   */
  public synchronized void addCurlMesh(CurlMesh mesh) {
      mCurlMesh = mesh;
  }
  
  /**
   * Returns rect reserved for left or right page. Value page should be
   * PAGE_LEFT or PAGE_RIGHT.
   */
  public RectF getPageRect(int page) {
          if (page == PAGE) {
          return mPageRect;
      }
      return null;
  }
  public void setup(GL10 gl){
      fb = new int[1];
      renderTex = new int[1];
      // generate
      ((GL11ExtensionPack)gl).glGenFramebuffersOES(1, fb, 0); 
      gl.glEnable(GL10.GL_TEXTURE_2D);
      gl.glGenTextures(1, renderTex, 0);// generate texture
      gl.glBindTexture(GL10.GL_TEXTURE_2D, renderTex[0]);
      gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
      gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
      gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
      gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);
     // texBuffer = ByteBuffer.allocateDirect(buf.length*4).order(ByteOrder.nativeOrder()).asIntBuffer();
     // gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE,GL10.GL_MODULATE);
      gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGBA, texW, texH, 0, GL10.GL_RGBA, GL10.GL_UNSIGNED_SHORT_4_4_4_4, null);
      gl.glDisable(GL10.GL_TEXTURE_2D);
  }
  boolean RenderStart(GL10 gl){
      // Bind the framebuffer
      ((GL11ExtensionPack)gl).glBindFramebufferOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES, fb[0]);
  
      // specify texture as color attachment
      ((GL11ExtensionPack)gl).glFramebufferTexture2DOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES, GL11ExtensionPack.GL_COLOR_ATTACHMENT0_OES, GL10.GL_TEXTURE_2D, renderTex[0], 0);
  
  
      int error = gl.glGetError();
      if (error != GL10.GL_NO_ERROR) {
          Log.d("err", "Background Load GLError: " + error+"      ");
      }
      int status = ((GL11ExtensionPack)gl).glCheckFramebufferStatusOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES);
      if (status != GL11ExtensionPack.GL_FRAMEBUFFER_COMPLETE_OES)
      {
          Log.d("err", "Background Load GLError: " + status+"      ");;
          return true;
      }
      gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
      return true;
  }
  void RenderEnd(GL10 gl){
      ((GL11ExtensionPack)gl).glBindFramebufferOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES, 0);
  
      gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
  
      gl.glEnable(GL10.GL_TEXTURE_2D);
      gl.glBindTexture(GL10.GL_TEXTURE_2D, renderTex[0]);
      gl.glColor4f(1,1,1,1);
      gl.glDisable(GL10.GL_TEXTURE_2D);
  }
  
  @Override
  public synchronized void onDrawFrame(GL10 gl) {
      if(first){
      int h = GLES20.glGetError();
      this.setup(gl);
      if(h!=0){
          Log.d("ERROR", "ERROR Happend"+h+"");
      }
      first = false;
      }
      mObserver.onDrawFrame();
      //glClearColor miad rangi ke maa entekhaab kardim ro tooye carde Graphic register mikone
      gl.glClearColor(Color.red(mBackgroundColor) / 255f,
              Color.green(mBackgroundColor) / 255f,
              Color.blue(mBackgroundColor) / 255f,
              Color.alpha(mBackgroundColor) / 255f);
      //glClear miad oon rangi ke bala register karde boodim ro dige az buffer paak mikone
      gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
  
      //miad matris ro be MabdaEsh barmigardoone, ke bAd baraye glRotate va glTranslate moshkeli ijaad nashe
      //chon maa asle jaabejaa kardan hamoon baraye safhe, baste be makaane avalieye
      // kaaghazemoon hast, na oon makani ke dar haale hazer gharaar dare
      gl.glLoadIdentity();
  
      if (USE_PERSPECTIVE_PROJECTION) {
          gl.glTranslatef(0, 0, -6f);
      }
  
  
      RenderStart(gl);
      mCurlMesh.onDrawFrame(gl);
      RenderEnd(gl);
      mCurlMesh.onDrawFrame(gl);
  
  }
  
  @Override
  public void onSurfaceChanged(GL10 gl, int width, int height) {
      gl.glViewport(0, 0, width, height);
      mViewportWidth = width;
      mViewportHeight = height;
  
      float ratio = (float) width / height;
      mViewRect.top = 1.0f;
      mViewRect.bottom = -1.0f;
      mViewRect.left = -ratio;
      mViewRect.right = ratio;
      updatePageRects();
  
      gl.glMatrixMode(GL10.GL_PROJECTION);
      gl.glLoadIdentity();
      if (USE_PERSPECTIVE_PROJECTION) {
          GLU.gluPerspective(gl, 20f, (float) width / height, .1f, 100f);
      } else {
          GLU.gluOrtho2D(gl, mViewRect.left, mViewRect.right,
                  mViewRect.bottom, mViewRect.top);
      }
  
      gl.glMatrixMode(GL10.GL_MODELVIEW);
      gl.glLoadIdentity();
  }
  
  @Override
  public void onSurfaceCreated(GL10 gl, EGLConfig config) {
  //  mCurlMesh.setup(gl);
      gl.glClearColor(0f, 0f, 0f, 1f);
      gl.glShadeModel(GL10.GL_SMOOTH);
      gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
      gl.glHint(GL10.GL_LINE_SMOOTH_HINT, GL10.GL_NICEST);
      //gl.glHint(GL10.GL_POLYGON_SMOOTH_HINT, GL10.GL_NICEST);
      gl.glEnable(GL10.GL_LINE_SMOOTH);
      gl.glDisable(GL10.GL_DEPTH_TEST);
      gl.glDisable(GL10.GL_CULL_FACE);
  }
  
  
  /**
   * Change background/clear color.
   */
  public void setBackgroundColor(int color) {
      mBackgroundColor = color;
  }
  
  /**
   * Set margins or padding. Note: margins are proportional. Meaning a value
   * of .1f will produce a 10% margin.
   */
  public synchronized void setMargins(float left, float top, float right,
          float bottom) {
      mMargins.left = left;
      mMargins.top = top;
      mMargins.right = right;
      mMargins.bottom = bottom;
      updatePageRects();
  }
  /**
   * Translates screen coordinates into view coordinates.
   * mokhtassate ye noghte (masalan pointer Position) roye safhe ro, be moAdele mokhtasaatesh
   * rooye CurlView Tabdil mikene
   */
  public void translate(PointF pt) {
      pt.x = mViewRect.left + (mViewRect.width() * pt.x / mViewportWidth);
      pt.y = mViewRect.top - (-mViewRect.height() * pt.y / mViewportHeight);
  }
  
  /**
   * Recalculates page rectangles.
   */
  private void updatePageRects() {
      if (mViewRect.width() == 0 || mViewRect.height() == 0) {
          return;
      }
      /**
       * @ TODO inja daghighan hamnoon kaari ke mikham, yAni size dadan be Page ro anjaam mide
       * mpageRect... khode meshe  va mViewRect view E layout
       */
          mPageRect.set(mViewRect);
          mPageRect.left += mViewRect.width() * mMargins.left;
          mPageRect.right -= mViewRect.width() * mMargins.right;
          mPageRect.top += mViewRect.height() * mMargins.top;
          mPageRect.bottom -= mViewRect.height() * mMargins.bottom;
  
          int bitmapW = (int) ((mPageRect.width() * mViewportWidth) / mViewRect.width());
          int bitmapH = (int) ((mPageRect.height() * mViewportHeight) / mViewRect.height());
          mObserver.onPageSizeChanged(bitmapW, bitmapH);
  
  }
  
  /**
   * Observer for waiting render engine/state updates.
   */
  public interface Observer {
      /**
       * Called from onDrawFrame called before rendering is started. This is
       * intended to be used for animation purposes.
       */
      public void onDrawFrame();
  
      /**
       * Called once page size is changed. Width and height tell the page size
       * in pixels making it possible to update textures accordingly.
       */
      public void onPageSizeChanged(int width, int height);
  
       }
  } 
  </code></pre>