Showing posts with label code. Show all posts
Showing posts with label code. Show all posts

February 6, 2018

0.0 ~ 1.0 to RGB (Red - Yellow - Green - Cyan - Blue)

float val;        // input 0.0 ~ 1.0
unsigned char R, G, B;    // output 0 ~ 255
R = (unsigned char)(( val > 0.5f ? 0.0f : ( val < 0.25f ? 1.0f : (2.0f - 4.0f*val)) ) * 255.0f );
G = (unsigned char)(( val < 0.25f ? 4.0f*val : ( val > 0.75f ? (4.0f - 4.0f*val) : 1.0f ) ) * 255.0f );
B = (unsigned char)(( val < 0.5f ? 0.0f : ( val > 0.75f ? 1.0f : (4.0f*val - 2.0f) )) * 255.0f );

June 23, 2015

FBO on Android

private void initFBO(int width, int height) {
  hFBOTex = new int[1];
  GLES20.glGenTextures(1,hFBOTex,0);
  GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, hFBOTex[0]);
  GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D,0,GLES20.GL_RGBA,width,height,0,GLES20.GL_RGBA,GLES20.GL_UNSIGNED_BYTE,null);
  GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
  GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
  GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
  GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);

  hFBO = new int[1];
  GLES20.glGenFramebuffers(1,hFBO,0);
  GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER,hFBO[0]);
  GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER,GLES20.GL_COLOR_ATTACHMENT0,GLES20.GL_TEXTURE_2D,hFBOTex[0],0);

  int[] depth;
  depth = new int[1];
  GLES20.glGenRenderbuffers(1,depth,0);
  GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER,depth[0]);
  GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER,GLES20.GL_DEPTH_COMPONENT16,width,height);
  GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER,GLES20.GL_DEPTH_ATTACHMENT,GLES20.GL_RENDERBUFFER,depth[0]);

  if ( GLES20.glGetError() != GLES20.GL_NO_ERROR) Log.i("mr","initFBO - rbo");

  if(GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER) != GLES20.GL_FRAMEBUFFER_COMPLETE)
    Log.e("mr","initFBO");
}

public void onDrawFrame ( GL10 unused ) {
  GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER,hFBO[0]);
  // draw somethings to FBO

  GLES20.glFlush();
  // read a block of pixels from back buffer in double-buffered configurations
  ByteBuffer buf = ByteBuffer.allocateDirect(width*height*4);
  GLES20.glReadPixels(0, 0, width, height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, buf);

  GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER,0);
  // draw somethings to frame(back) buffer
  // you can use hFBOTex[0] as a texture
}

March 23, 2015

Render camera preview using OpenGL ES 2.0 on Android API 21 or higher

I referred to the Android Samples for android.hardware.camera2 (samples\android-21\media\Camera2Basic).

In the code, I fixed the resolution of camera preview to the device resolution, and tested on the NEXUS 9.

// AndroidManifest.xml
...
< uses-feature android:glEsVersion="0x00020000" android:required="true"/>
< uses-feature android:name="android.hardware.camera2"/>
< uses-permission android:name="android.permission.CAMERA"/>
...
< activity android:name=".MainActivity" android:screenOrientation="landscape">
...


// MainActivity.java
package ...
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;

public class MainActivity extends Activity {
    private MainView mView;

    @Override
    public void onCreate ( Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        int ui = getWindow().getDecorView().getSystemUiVisibility();
        ui = ui | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
        getWindow().getDecorView().setSystemUiVisibility(ui);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        mView = new MainView(this);
        setContentView ( mView );
    }

    @Override
    protected void onResume() {
        super.onResume();
        mView.onResume();
    }

    @Override
    protected void onPause() {
        mView.onPause();
        super.onPause();
    }
}


// MainView.java
package ...
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.view.SurfaceHolder;

public class MainView extends GLSurfaceView {
    MainRenderer mRenderer;

    MainView ( Context context ) {
        super ( context );
        mRenderer = new MainRenderer(this);
        setEGLContextClientVersion ( 2 );
        setRenderer ( mRenderer );
        setRenderMode ( GLSurfaceView.RENDERMODE_WHEN_DIRTY );
    }

    public void surfaceCreated ( SurfaceHolder holder ) {
        super.surfaceCreated ( holder );
    }

    public void surfaceDestroyed ( SurfaceHolder holder ) {
        super.surfaceDestroyed ( holder );
    }

    public void surfaceChanged ( SurfaceHolder holder, int format, int w, int h ) {
        super.surfaceChanged ( holder, format, w, h );
    }

    @Override
    public void onResume() {
        super.onResume();
        mRenderer.onResume();
    }

    @Override
    public void onPause() {
        mRenderer.onPause();
        super.onPause();
    }
}


// MainRenderer.java
package ...
import android.content.Context;
import android.graphics.Point;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.opengl.GLES11Ext;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.util.Size;
import android.view.Surface;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.Arrays;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

public class MainRenderer implements GLSurfaceView.Renderer, SurfaceTexture.OnFrameAvailableListener {
    private final String vss_default = "" +
            "attribute vec2 vPosition;\n" +
            "attribute vec2 vTexCoord;\n" +
            "varying vec2 texCoord;\n" +
            "void main() {\n" +
            "  texCoord = vTexCoord;\n" +
            "  gl_Position = vec4 ( vPosition.x, vPosition.y, 0.0, 1.0 );\n" +
            "}";

    private final String fss_default = "" +
            "#extension GL_OES_EGL_image_external : require\n" +
            "precision mediump float;\n" +
            "uniform samplerExternalOES sTexture;\n" +
            "varying vec2 texCoord;\n" +
            "void main() {\n" +
            "  gl_FragColor = texture2D(sTexture,texCoord);\n" +
            "}";

    private int[] hTex;
    private FloatBuffer pVertex;
    private FloatBuffer pTexCoord;
    private int hProgram;

    private SurfaceTexture mSTexture;

    private boolean mGLInit = false;
    private boolean mUpdateST = false;

    private MainView mView;

    private CameraDevice mCameraDevice;
    private CameraCaptureSession mCaptureSession;
    private CaptureRequest.Builder mPreviewRequestBuilder;
    private String mCameraID;
    private Size mPreviewSize = new Size ( 1920, 1080 );

    private HandlerThread mBackgroundThread;
    private Handler mBackgroundHandler;
    private Semaphore mCameraOpenCloseLock = new Semaphore(1);

    MainRenderer ( MainView view ) {
        mView = view;
        float[] vtmp = { 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f };
        float[] ttmp = { 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f };
        pVertex = ByteBuffer.allocateDirect(8 * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
        pVertex.put ( vtmp );
        pVertex.position(0);
        pTexCoord = ByteBuffer.allocateDirect(8*4).order(ByteOrder.nativeOrder()).asFloatBuffer();
        pTexCoord.put ( ttmp );
        pTexCoord.position(0);
    }

    public void onResume() {
        startBackgroundThread();
    }

    public void onPause() {
        mGLInit = false;
        mUpdateST = false;
        closeCamera();
        stopBackgroundThread();
    }

    public void onSurfaceCreated ( GL10 unused, EGLConfig config ) {
        initTex();
        mSTexture = new SurfaceTexture ( hTex[0] );
        mSTexture.setOnFrameAvailableListener(this);

        GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);

        hProgram = loadShader ( vss_default, fss_default );

        Point ss = new Point();
        mView.getDisplay().getRealSize(ss);

        cacPreviewSize(ss.x, ss.y);
        openCamera();

        mGLInit = true;
    }

    public void onDrawFrame ( GL10 unused ) {
        if ( !mGLInit ) return;
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

        synchronized(this) {
            if ( mUpdateST ) {
                mSTexture.updateTexImage();
                mUpdateST = false;
            }
        }

        GLES20.glUseProgram(hProgram);

        int ph = GLES20.glGetAttribLocation(hProgram, "vPosition");
        int tch = GLES20.glGetAttribLocation ( hProgram, "vTexCoord" );

        GLES20.glVertexAttribPointer(ph, 2, GLES20.GL_FLOAT, false, 4*2, pVertex);
        GLES20.glVertexAttribPointer(tch, 2, GLES20.GL_FLOAT, false, 4*2, pTexCoord );
        GLES20.glEnableVertexAttribArray(ph);
        GLES20.glEnableVertexAttribArray(tch);

        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, hTex[0]);
        GLES20.glUniform1i(GLES20.glGetUniformLocation ( hProgram, "sTexture" ), 0);

        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
        GLES20.glFlush();
    }

    public void onSurfaceChanged ( GL10 unused, int width, int height ) {
        GLES20.glViewport(0, 0, width, height);
    }

    private void initTex() {
        hTex = new int[1];
        GLES20.glGenTextures ( 1, hTex, 0 );
        GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, hTex[0]);
        GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
        GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
        GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
        GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
    }

    public synchronized void onFrameAvailable ( SurfaceTexture st ) {
        mUpdateST = true;
        mView.requestRender();
    }

    private static int loadShader ( String vss, String fss ) {
        int vshader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
        GLES20.glShaderSource(vshader, vss);
        GLES20.glCompileShader(vshader);
        int[] compiled = new int[1];
        GLES20.glGetShaderiv(vshader, GLES20.GL_COMPILE_STATUS, compiled, 0);
        if (compiled[0] == 0) {
            Log.e("Shader", "Could not compile vshader");
            Log.v("Shader", "Could not compile vshader:"+GLES20.glGetShaderInfoLog(vshader));
            GLES20.glDeleteShader(vshader);
            vshader = 0;
        }

        int fshader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
        GLES20.glShaderSource(fshader, fss);
        GLES20.glCompileShader(fshader);
        GLES20.glGetShaderiv(fshader, GLES20.GL_COMPILE_STATUS, compiled, 0);
        if (compiled[0] == 0) {
            Log.e("Shader", "Could not compile fshader");
            Log.v("Shader", "Could not compile fshader:"+GLES20.glGetShaderInfoLog(fshader));
            GLES20.glDeleteShader(fshader);
            fshader = 0;
        }

        int program = GLES20.glCreateProgram();
        GLES20.glAttachShader(program, vshader);
        GLES20.glAttachShader(program, fshader);
        GLES20.glLinkProgram(program);

        return program;
    }

    void cacPreviewSize( final int width, final int height ) {
        CameraManager manager = (CameraManager)mView.getContext().getSystemService(Context.CAMERA_SERVICE);
        try {
            for (String cameraID : manager.getCameraIdList()) {
                CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraID);
                if (characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT)
                    continue;

                mCameraID = cameraID;
                StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
                for ( Size psize : map.getOutputSizes(SurfaceTexture.class)) {
                    if ( width == psize.getWidth() && height == psize.getHeight() ) {
                        mPreviewSize = psize;
                        break;
                    }
                }
                break;
            }
        } catch ( CameraAccessException e ) {
            Log.e("mr", "cacPreviewSize - Camera Access Exception");
        } catch ( IllegalArgumentException e ) {
            Log.e("mr", "cacPreviewSize - Illegal Argument Exception");
        } catch ( SecurityException e ) {
            Log.e("mr", "cacPreviewSize - Security Exception");
        }
    }

    void openCamera() {
        CameraManager manager = (CameraManager)mView.getContext().getSystemService(Context.CAMERA_SERVICE);
        try {
            CameraCharacteristics characteristics = manager.getCameraCharacteristics(mCameraID);
            if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
                throw new RuntimeException("Time out waiting to lock camera opening.");
            }
            manager.openCamera(mCameraID,mStateCallback,mBackgroundHandler);
        } catch ( CameraAccessException e ) {
            Log.e("mr", "OpenCamera - Camera Access Exception");
        } catch ( IllegalArgumentException e ) {
            Log.e("mr", "OpenCamera - Illegal Argument Exception");
        } catch ( SecurityException e ) {
            Log.e("mr", "OpenCamera - Security Exception");
        } catch ( InterruptedException e ) {
            Log.e("mr", "OpenCamera - Interrupted Exception");
        }
    }

    private void closeCamera() {
        try {
            mCameraOpenCloseLock.acquire();
            if (null != mCaptureSession) {
                mCaptureSession.close();
                mCaptureSession = null;
            }
            if (null != mCameraDevice) {
                mCameraDevice.close();
                mCameraDevice = null;
            }
        } catch (InterruptedException e) {
            throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
        } finally {
            mCameraOpenCloseLock.release();
        }
    }

    private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {

        @Override
        public void onOpened(CameraDevice cameraDevice) {
            mCameraOpenCloseLock.release();
            mCameraDevice = cameraDevice;
            createCameraPreviewSession();
        }

        @Override
        public void onDisconnected(CameraDevice cameraDevice) {
            mCameraOpenCloseLock.release();
            cameraDevice.close();
            mCameraDevice = null;
        }

        @Override
        public void onError(CameraDevice cameraDevice, int error) {
            mCameraOpenCloseLock.release();
            cameraDevice.close();
            mCameraDevice = null;
        }

    };

    private void createCameraPreviewSession() {
        try {
            mSTexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());

            Surface surface = new Surface(mSTexture);

            mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            mPreviewRequestBuilder.addTarget(surface);

            mCameraDevice.createCaptureSession(Arrays.asList(surface),
                    new CameraCaptureSession.StateCallback() {
                        @Override
                        public void onConfigured(CameraCaptureSession cameraCaptureSession) {
                            if (null == mCameraDevice)
                                return;

                            mCaptureSession = cameraCaptureSession;
                            try {
                                mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
                                mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);

                                mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), null, mBackgroundHandler);
                            } catch (CameraAccessException e) {
                                Log.e("mr", "createCaptureSession");
                            }
                        }
                        @Override
                        public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
                        }
                    }, null
            );
        } catch (CameraAccessException e) {
            Log.e("mr", "createCameraPreviewSession");
        }
    }

    private void startBackgroundThread() {
        mBackgroundThread = new HandlerThread("CameraBackground");
        mBackgroundThread.start();
        mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
    }

    private void stopBackgroundThread() {
        mBackgroundThread.quitSafely();
        try {
            mBackgroundThread.join();
            mBackgroundThread = null;
            mBackgroundHandler = null;
        } catch (InterruptedException e) {
            Log.e("mr", "stopBackgroundThread");
        }
    }
}

December 26, 2014

Render the captured image from real camera matrix using OpenGL

// intrinsic parameter: fx, fy, cx, cy, skew
// image size: width, hegiht
// view frustum: nearp, farp
// extrinsic parameter: r00, r01, r02, r10, r11, r12, r20, r21, r22, tx, ty, tz

// projection matrix
float pm[16] = { 0.0f };
pm[0]  = 2.0f*fx/width;
pm[4]  = -2.0f*skew/width;
pm[8]  = 1.0f - 2.0f*cx/width;
pm[12] = 0.0f;
pm[1]  = 0.0f;
pm[5]  = -2.0f*fy/height;
pm[9]  = 1.0f - 2.0f*cy/height;
pm[13] = 0.0f;
pm[2]  = 0.0f;
pm[6]  = 0.0f;
pm[10] = -(farp+nearp)/(farp-nearp);
pm[14] = -2.0f*farp*nearp/(farp-nearp);
pm[3]  = 0.0f;
pm[7]  = 0.0f;
pm[11] = -1.0f;
pm[15] = 0.0f;

glViewport ( 0, 0, width, height);
glMatrixMode ( GL_PROJECTION );

glLoadMatrixf ( pm );

glMatrixMode ( GL_MODELVIEW );
glLoadIdentity();

// -z direction
float rm[16] = { 0.0f };
rm[0]  = 1.0f;
rm[5]  = 1.0f;
rm[10] = -1.0f;
rm[15] = 1.0f;

glMultMatrixf ( rm );

rm[0]  = r00;
rm[4]  = r01;
rm[8]  = r02;
rm[1]  = r10;
rm[5]  = r11;
rm[9]  = r12;
rm[2]  = r20;
rm[6]  = r21;
rm[10] = r22;
rm[15] = 1.0f;

// inverse rotation and translation

glMultTransposeMatrixf ( rm );
glTranslatef ( -tx, -ty, -tz );

September 24, 2012

Render camera preview using OpenGL ES 2.0 on Android

Please refer -> updated version for Lollipop

// in Manifest
< uses-feature android:glEsVersion="0x00020000" android:required="true"/>
< uses-feature android:name="android.hardware.camera"/>
< uses-permission android:name="android.permission.CAMERA"/>
< uses-permission android:name="android.permission.WAKE_LOCK"/>
... android:screenOrientation="landscape" ... // activity property


// Activity
public class MainActivity extends Activity {
  private MainView mView;
  private WakeLock mWL;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // full screen & full brightness
    requestWindowFeature ( Window.FEATURE_NO_TITLE);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    mWL = ((PowerManager)getSystemService ( Context.POWER_SERVICE )).newWakeLock(PowerManager.FULL_WAKE_LOCK, "WakeLock");
    mWL.acquire();
    mView = new MainView(this);
    setContentView ( mView );
  }
  
  @Override
  protected void onPause() {
    if ( mWL.isHeld() )
      mWL.release();
    mView.onPause();
    super.onPause();
  }
    
  @Override
  protected void onResume() {
    super.onResume();
    mView.onResume();
    if(!mWL.isHeld()) mWL.acquire();
  }
}


// View
class MainView extends GLSurfaceView {
  MainRenderer mRenderer;
 
  MainView ( Context context ) {
    super ( context );
    mRenderer = new MainRenderer(this);
    setEGLContextClientVersion ( 2 );
    setRenderer ( mRenderer );
    setRenderMode ( GLSurfaceView.RENDERMODE_WHEN_DIRTY );
  }
 
  public void surfaceCreated ( SurfaceHolder holder ) {
    super.surfaceCreated ( holder );
  }
 
  public void surfaceDestroyed ( SurfaceHolder holder ) {
    mRenderer.close();
    super.surfaceDestroyed ( holder );
  }
 
  public void surfaceChanged ( SurfaceHolder holder, int format, int w, int h ) {
    super.surfaceChanged ( holder, format, w, h );
  }
}


// Renderer
public class MainRenderer implements GLSurfaceView.Renderer, SurfaceTexture.OnFrameAvailableListener {
  private final String vss =
      "attribute vec2 vPosition;\n" +
      "attribute vec2 vTexCoord;\n" +
      "varying vec2 texCoord;\n" +
      "void main() {\n" +
      "  texCoord = vTexCoord;\n" +
      "  gl_Position = vec4 ( vPosition.x, vPosition.y, 0.0, 1.0 );\n" +
      "}";
 
  private final String fss =
      "#extension GL_OES_EGL_image_external : require\n" +
      "precision mediump float;\n" +
      "uniform samplerExternalOES sTexture;\n" +
      "varying vec2 texCoord;\n" +
      "void main() {\n" +
      "  gl_FragColor = texture2D(sTexture,texCoord);\n" +
      "}";

  private int[] hTex;
  private FloatBuffer pVertex;
  private FloatBuffer pTexCoord;
  private int hProgram;
 
  private Camera mCamera;
  private SurfaceTexture mSTexture;
 
  private boolean mUpdateST = false;
 
  private MainView mView;
 
  MainRenderer ( MainView view ) {
    mView = view;
    float[] vtmp = { 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f };
    float[] ttmp = { 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f };
    pVertex = ByteBuffer.allocateDirect(8*4).order(ByteOrder.nativeOrder()).asFloatBuffer();
    pVertex.put ( vtmp );
    pVertex.position(0);
    pTexCoord = ByteBuffer.allocateDirect(8*4).order(ByteOrder.nativeOrder()).asFloatBuffer();
    pTexCoord.put ( ttmp );
    pTexCoord.position(0);
  }
 
  public void close()
  {
    mUpdateST = false;
    mSTexture.release();
    mCamera.stopPreview();
    mCamera.release();
    mCamera = null;
    deleteTex();
  }
 
  public void onSurfaceCreated ( GL10 unused, EGLConfig config ) {
    //String extensions = GLES20.glGetString(GLES20.GL_EXTENSIONS);
    //Log.i("mr", "Gl extensions: " + extensions);
    //Assert.assertTrue(extensions.contains("OES_EGL_image_external"));
        
    initTex();
    mSTexture = new SurfaceTexture ( hTex[0] );
    mSTexture.setOnFrameAvailableListener(this);

    mCamera = Camera.open();
    try {
      mCamera.setPreviewTexture(mSTexture);
    } catch ( IOException ioe ) {
    }

    GLES20.glClearColor ( 1.0f, 1.0f, 0.0f, 1.0f );
  
    hProgram = loadShader ( vss, fss );
  }
 
  public void onDrawFrame ( GL10 unused ) {
    GLES20.glClear( GLES20.GL_COLOR_BUFFER_BIT );
  
    synchronized(this) {
      if ( mUpdateST ) {
        mSTexture.updateTexImage();
        mUpdateST = false;
      }
    }

    GLES20.glUseProgram(hProgram);

    int ph = GLES20.glGetAttribLocation(hProgram, "vPosition");
    int tch = GLES20.glGetAttribLocation ( hProgram, "vTexCoord" );
    int th = GLES20.glGetUniformLocation ( hProgram, "sTexture" );
  
    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
    GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, hTex[0]);
    GLES20.glUniform1i(th, 0);
  
    GLES20.glVertexAttribPointer(ph, 2, GLES20.GL_FLOAT, false, 4*2, pVertex);
    GLES20.glVertexAttribPointer(tch, 2, GLES20.GL_FLOAT, false, 4*2, pTexCoord );
    GLES20.glEnableVertexAttribArray(ph);
    GLES20.glEnableVertexAttribArray(tch);
  
    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
    GLES20.glFlush();
  }
 
  public void onSurfaceChanged ( GL10 unused, int width, int height ) {
    GLES20.glViewport( 0, 0, width, height );
    Camera.Parameters param = mCamera.getParameters();
    List psize = param.getSupportedPreviewSizes();
    if ( psize.size() > 0 ) {
      int i;
      for ( i = 0; i < psize.size(); i++ ) {
        if ( psize.get(i).width < width || psize.get(i).height < height )
          break;
      }
      if ( i > 0 )
        i--;
      param.setPreviewSize(psize.get(i).width, psize.get(i).height);
      //Log.i("mr","ssize: "+psize.get(i).width+", "+psize.get(i).height);
    }
    param.set("orientation", "landscape");
    mCamera.setParameters ( param );
    mCamera.startPreview();
  }
 
  private void initTex() {
    hTex = new int[1];
    GLES20.glGenTextures ( 1, hTex, 0 );
    GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, hTex[0]);
    GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
    GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
    GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
    GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
  }
 
  private void deleteTex() {
    GLES20.glDeleteTextures ( 1, hTex, 0 );
  }
 
  public synchronized void onFrameAvailable ( SurfaceTexture st ) {
    mUpdateST = true;
    mView.requestRender();
  }
 
  private static int loadShader ( String vss, String fss ) {
    int vshader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
    GLES20.glShaderSource(vshader, vss);
    GLES20.glCompileShader(vshader);
    int[] compiled = new int[1];
    GLES20.glGetShaderiv(vshader, GLES20.GL_COMPILE_STATUS, compiled, 0);
    if (compiled[0] == 0) {
      Log.e("Shader", "Could not compile vshader");
      Log.v("Shader", "Could not compile vshader:"+GLES20.glGetShaderInfoLog(vshader));
      GLES20.glDeleteShader(vshader);
      vshader = 0;
    }
  
    int fshader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
    GLES20.glShaderSource(fshader, fss);
    GLES20.glCompileShader(fshader);
    GLES20.glGetShaderiv(fshader, GLES20.GL_COMPILE_STATUS, compiled, 0);
    if (compiled[0] == 0) {
      Log.e("Shader", "Could not compile fshader");
      Log.v("Shader", "Could not compile fshader:"+GLES20.glGetShaderInfoLog(fshader));
      GLES20.glDeleteShader(fshader);
      fshader = 0;
    }

    int program = GLES20.glCreateProgram();
    GLES20.glAttachShader(program, vshader);
    GLES20.glAttachShader(program, fshader);
    GLES20.glLinkProgram(program);
        
    return program;
  }
}

January 17, 2012

Creating OpenGL shaders

include : glut.h, glew.h
library : glut32.lib, glew32.lib
bin : glut32.dll, glew32.dll

// initialize glew in the begging of application
glewInit();


// compile and link shader program from string
GLhandleARB InstallShaders ( const char *_vsSource, const char *_fsSource )
{
 GLuint program;
 GLuint vs, fs;
 GLint vertCompiled;
 GLint fragCompiled;
 GLint linked;

 vs = glCreateShader ( GL_VERTEX_SHADER );
 if ( vs )
 {
  glShaderSource ( vs, 1, &_vsSource, NULL );
  glCompileShader ( vs );
  glGetShaderiv ( vs, GL_COMPILE_STATUS, &vertCompiled );
  if ( !vertCompiled )
  {
   GLint infologLength = 0;
   glGetShaderiv ( vs, GL_INFO_LOG_LENGTH, &infologLength );

   if ( infologLength > 0 )
   {
    char *infoLog = (char*)malloc ( infologLength );
    glGetShaderInfoLog ( vs, infologLength, NULL, infoLog );
    int dsize = MultiByteToWideChar ( CP_ACP, 0, (char*)infoLog, -1, NULL, NULL );
    WCHAR *des = new WCHAR[dsize];
    MultiByteToWideChar ( CP_ACP, 0, (char*)infoLog, dsize, des, dsize );
    MessageBox ( g_hMain, des, L"Vertex Shader Compile Error", MB_ICONERROR );
    delete[] des;
    free ( infoLog );
   }
   glDeleteShader ( vs );
   vs = 0;
   return 0;
  }
 }

 fs = glCreateShader ( GL_FRAGMENT_SHADER );
 if ( fs )
 {
  glShaderSource ( fs, 1, &_fsSource, NULL );
  glCompileShader ( fs );
  glGetShaderiv ( fs, GL_COMPILE_STATUS, &fragCompiled );
  if ( !fragCompiled )
  {
   int infologLength = 0;
   glGetShaderiv ( fs, GL_INFO_LOG_LENGTH, &infologLength );

   if ( infologLength > 0 )
   {
    char *infoLog = (char*)malloc ( infologLength );
    glGetShaderInfoLog ( fs, infologLength, NULL, infoLog );
    int dsize = MultiByteToWideChar ( CP_ACP, 0, (char*)infoLog, -1, NULL, NULL );
    WCHAR *des = new WCHAR[dsize];
    MultiByteToWideChar ( CP_ACP, 0, (char*)infoLog, dsize, des, dsize );
    MessageBox ( g_hMain, des, L"Fragment Shader Compile Error", MB_ICONERROR );
    delete[] des;
    free ( infoLog );
   }
   glDeleteShader ( fs );
   fs = 0;
   return 0;
  }
 }

 if ( vs > 0 && fs > 0 )
 {
  program = glCreateProgram();
  if ( program )
  {
   glAttachShader ( program, vs );
   glAttachShader ( program, fs );

   glDeleteShader ( vs );
   glDeleteShader ( fs );

   glLinkProgram ( program );
   glGetProgramiv ( program, GL_LINK_STATUS, &linked );
   if ( !linked )
   {
    int infologLength = 0;
    glGetProgramiv ( program, GL_INFO_LOG_LENGTH, &infologLength);

    if ( infologLength > 0 )
    {
     char *infoLog = (char*)malloc ( infologLength );
     glGetProgramInfoLog ( program, infologLength, NULL, infoLog );
     int dsize = MultiByteToWideChar ( CP_ACP, 0, (char*)infoLog, -1, NULL, NULL );
     WCHAR *des = new WCHAR[dsize];
     MultiByteToWideChar ( CP_ACP, 0, (char*)infoLog, dsize, des, dsize );
     MessageBox ( g_hMain, des, L"Shader Link Error", MB_ICONERROR );
     delete[] des;
     free ( infoLog );
    }
    glDeleteProgram ( program );
    program = 0;
    return 0;
   }

   return program;
  }
  return 0;
 }
 return 0;
}


// clean up shader
GLint CleanUpShaders ( GLuint *_program )
{
 glDeleteProgram ( *_program );
 _program = 0;
 return 1;
}

Trace in visual studio

include : windows.h, stdio.h, stdarg.h
void Trace ( char *_format, ... )
{
 va_list args;
 va_start ( args, _format );
 int len = _vscprintf ( _format, args ) + 1;
 char *str = new char[len];
 vsprintf_s ( str, len, _format, args );
 va_end ( args );
 int dsize = MultiByteToWideChar ( CP_ACP, 0, str, -1, NULL, NULL );
 WCHAR *des = new WCHAR[dsize];
 MultiByteToWideChar ( CP_ACP, 0, str, dsize, des, dsize );
 OutputDebugString ( des );
 delete[] des;
 delete[] str;
}

January 12, 2012

Save BMP file using win32 API

include : windows.h
int SaveBMP ( const unsigned char *_buf, const char *_name, const int _width, const int _height )
{
 int i, j;
 BITMAPFILEHEADER bmfh;
 memset ( &bmfh, 0, sizeof ( BITMAPFILEHEADER ) );
 bmfh.bfType = 0x4d42;
 bmfh.bfSize = sizeof ( BITMAPFILEHEADER ) + sizeof ( BITMAPINFOHEADER ) + _width * _height * 3 + ( _width % 4 ) * _height + 2;
 bmfh.bfReserved1 = 0;
 bmfh.bfReserved2 = 0;
 bmfh.bfOffBits = sizeof ( BITMAPFILEHEADER ) + sizeof ( BITMAPINFOHEADER );

 BITMAPINFOHEADER bmih;
 memset ( &bmih, 0, sizeof ( BITMAPINFOHEADER ) );
 bmih.biSize = sizeof ( BITMAPINFOHEADER );
 bmih.biWidth = _width;
 bmih.biHeight = _height;
 bmih.biPlanes = 1;
 bmih.biBitCount = 24;
 bmih.biCompression = BI_RGB;
 bmih.biSizeImage = 0;
 bmih.biXPelsPerMeter = 0;
 bmih.biYPelsPerMeter = 0;
 bmih.biClrUsed = 0;
 bmih.biClrImportant = 0;

 FILE *bmf = NULL;
 if ( fopen_s ( &bmf, _name, "wcb" ) != 0 ) return -1;

 fwrite ( &bmfh, sizeof ( BITMAPFILEHEADER ), 1, bmf );
 fwrite ( &bmih, sizeof ( BITMAPINFOHEADER ), 1, bmf );

 unsigned char c = 0;
 int index;

 for ( i = _height-1; i >= 0; i-- )
 {
  for ( j = 0; j < _width; j++ )
  {
   index = i*_width+j;
   c = _buf[index*4+2];
   fwrite ( &c, sizeof ( unsigned char ), 1, bmf );
   c = _buf[index*4+1];
   fwrite ( &c, sizeof ( unsigned char ), 1, bmf );
   c = _buf[index*4+0];
   fwrite ( &c, sizeof ( unsigned char ), 1, bmf );
  }

  c = 0;
  switch ( _width % 4 )
  {
  case 3:
   fwrite ( &c, sizeof ( unsigned char ), 1, bmf );
  case 2:
   fwrite ( &c, sizeof ( unsigned char ), 1, bmf );
  case 1:
   fwrite ( &c, sizeof ( unsigned char ), 1, bmf );
  case 0:
   break;
  }
 }

 c = 0;
 fwrite ( &c, sizeof ( unsigned char ), 1, bmf );
 fwrite ( &c, sizeof ( unsigned char ), 1, bmf );

 fflush ( bmf );
 fclose ( bmf );
 bmf = NULL;

 return 1;
}

Read image from file in win32 using gdiplus

include : gdiplus.h
library : gdiplus.lib

// initialize in the begging of application
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR hgdiplusToken;
Gdiplus::GdiplusStartup ( &hgdiplusToken, &gdiplusStartupInput, NULL );


// read image from file
Gdiplus::Bitmap *bitmap = new Gdiplus::Bitmap ( L"filename.png" );
int width = bitmap->GetWidth();
int height = bitmap->GetHeight();
Gdiplus::Rect rt ( 0, 0, width, height );
unsigned char *image = new unsigned char[width*height*4];
Gdiplus::BitmapData data;
bitmap->LockBits ( &rt, Gdiplus::ImageLockModeRead, PixelFormat32bppARGB, &data );
memcpy ( image, data.Scan0, sizeof ( unsigned char ) * width * height * 4 );
bitmap->UnlockBits ( &data );
delete bitmap;
bitmap = NULL;


// release in the end of application
delete[] image;
Gdiplus::GdiplusShutdown ( hgdiplusToken );