rb.app.GLObject.java Source code

Java tutorial

Introduction

Here is the source code for rb.app.GLObject.java

Source

//    rbAPPmit: An Android front-end for the Certified Reduced Basis Method
//    Copyright (C) 2010 David J. Knezevic and Phuong Huynh
//
//    This file is part of rbAPPmit
//
//    rbAPPmit is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    rbAPPmit is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with rbAPPmit.  If not, see <http://www.gnu.org/licenses/>. 

package rb.app;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import android.content.Context;
import android.util.Log;

public class GLObject extends Object {

    private int reg_num; // number of subdomains
    private int[] node_reg; // tell us which subdomain our vertices belong to
    private int[] face_dom; // tell us which subdomain our faces belong to

    // the bounding box (xyz range) of the model
    public float[] nminmax = { 1e9f, 1e9f, 1e9f, -1e9f, -1e9f, -1e9f };
    public int node_num; // number of vertices
    public int face_num; // number of faces
    public float[] node = null; // vertex data
    public float[] normal; // vertex normal data
    public float[] fnormal; // face normal data
    public float[] ref_node; // the original vertex data
    public short[] face; // face data
    public short[] face_wf; // edge data
    public float[][] ucolor; // color data
    public float boxsize; // bounding box size
    public int[] frame_num; // number of animation frame for solution field
    public float[][] sol; // field solution data
    public int field_num = 1; // number of solution field

    boolean is2D = true; // is our model 2D?
    boolean isconstant = false; // is the field solution constant?

    public boolean isgeoani = false;
    public int vframe_num = 1; // number of animation frame for vertices
    public float[][][] vLTfunc = null;
    public float[] vnode = null; // animation node data    

    public ShortBuffer _shortBuffer;
    public FloatBuffer _floatBuffer;

    private Context context;

    public void allocateBuffer() {
        int SHORT_MAX = 250000;
        int FLOAT_MAX = 1000000;

        Log.d("GLRenderer", "Allocate (short):" + SHORT_MAX * 2 + " bytes");
        ByteBuffer vbb = ByteBuffer.allocateDirect(SHORT_MAX * 2);
        vbb.order(ByteOrder.nativeOrder());
        _shortBuffer = vbb.asShortBuffer();
        _shortBuffer.position(0);

        Log.d("GLRenderer", "Allocate (float):" + FLOAT_MAX * 4 + " bytes");
        ByteBuffer fbb = ByteBuffer.allocateDirect(FLOAT_MAX * 4);
        fbb.order(ByteOrder.nativeOrder());
        _floatBuffer = fbb.asFloatBuffer();
        _floatBuffer.position(0);
    }

    public GLObject() {
        // void constructor
    }

    public GLObject(Context _context) {
        context = _context;
    }

    // get the bounding box data
    public float[] get_minmax() {
        return nminmax;
    }

    // calculate the color data (red green blue alpha) from the solution field
    public void cal_color_data() {
        float calphaval = 0.8f; // default alpha value, use 1.0f for nonblend rendering

        ucolor = null;
        // all field must have the same length (for now)
        ucolor = new float[field_num][sol[0].length * 4];

        isconstant = true;
        for (int ifn = 0; ifn < field_num; ifn++) {
            // range of the current solution field
            float val_min = sol[ifn][0];
            float val_max = sol[ifn][0];
            for (int i = 0; i < sol[ifn].length; i++) {
                val_min = (val_min > sol[ifn][i]) ? sol[ifn][i] : val_min;
                val_max = (val_max < sol[ifn][i]) ? sol[ifn][i] : val_max;
            }
            if (Math.abs(val_max - val_min) > 1e-8) {
                isconstant = false;

                // calculate color data
                for (int i = 0; i < sol[0].length; i++) {
                    float tmpvar = (sol[ifn][i] - val_min) / (val_max - val_min);
                    if (tmpvar <= 0.125f) {
                        ucolor[ifn][i * 4 + 0] = 0.0f;
                        ucolor[ifn][i * 4 + 1] = 0.0f;
                        ucolor[ifn][i * 4 + 2] = 0.5f + tmpvar / 0.25f;
                        ucolor[ifn][i * 4 + 3] = calphaval;
                    }
                    if ((tmpvar > 0.125f) && (tmpvar <= 0.375f)) {
                        ucolor[ifn][i * 4 + 0] = 0.0f;
                        ucolor[ifn][i * 4 + 1] = 0.0f + (tmpvar - 0.125f) / 0.25f;
                        ucolor[ifn][i * 4 + 2] = 1.0f;
                        ucolor[ifn][i * 4 + 3] = calphaval;
                    }
                    if ((tmpvar > 0.375f) && (tmpvar <= 0.625f)) {
                        ucolor[ifn][i * 4 + 0] = 0.0f + (tmpvar - 0.375f) / 0.25f;
                        ucolor[ifn][i * 4 + 1] = 1.0f;
                        ucolor[ifn][i * 4 + 2] = 1.0f - (tmpvar - 0.375f) / 0.25f;
                        ucolor[ifn][i * 4 + 3] = calphaval;
                    }
                    if ((tmpvar > 0.625f) && (tmpvar <= 0.875f)) {
                        ucolor[ifn][i * 4 + 0] = 1.0f;
                        ucolor[ifn][i * 4 + 1] = 1.0f - (tmpvar - 0.625f) / 0.25f;
                        ucolor[ifn][i * 4 + 2] = 0.0f;
                        ucolor[ifn][i * 4 + 3] = calphaval;
                    }
                    if (tmpvar > 0.875f) {
                        ucolor[ifn][i * 4 + 0] = 1.0f - (tmpvar - 0.875f) / 0.25f;
                        ucolor[ifn][i * 4 + 1] = 0.0f;
                        ucolor[ifn][i * 4 + 2] = 0.0f;
                        ucolor[ifn][i * 4 + 3] = calphaval;
                    }
                }
            } else {
                for (int i = 0; i < sol[0].length; i++) {
                    ucolor[ifn][i * 4 + 0] = 0.0f;
                    ucolor[ifn][i * 4 + 1] = 0.0f;
                    ucolor[ifn][i * 4 + 2] = 1.0f;
                    ucolor[ifn][i * 4 + 3] = calphaval;
                }
            }

        }
    }

    // calculate normal data for the current model
    public void cal_normal_data() {
        normal = new float[node_num * 3];
        fnormal = new float[face_num * 3];
        float[] vecAB = new float[3];
        float[] vecAC = new float[3];
        int i, j, k;
        float length;
        // Initialize normal data and contribution flag
        int[] icount = new int[node_num];
        for (i = 0; i < node_num; i++) {
            normal[i * 3 + 0] = 0.0f;
            normal[i * 3 + 1] = 0.0f;
            normal[i * 3 + 2] = 0.0f;
            icount[i] = 0;
        }
        // calculate local face normal
        for (i = 0; i < face_num; i++) {
            for (j = 0; j < 3; j++) {
                vecAB[j] = node[face[i * 3 + 1] * 3 + j] - node[face[i * 3 + 0] * 3 + j];
                vecAC[j] = node[face[i * 3 + 2] * 3 + j] - node[face[i * 3 + 0] * 3 + j];
            }
            // normal of the face is the cross product of AB and AC
            fnormal[i * 3 + 0] = vecAB[1] * vecAC[2] - vecAB[2] * vecAC[1];
            fnormal[i * 3 + 1] = vecAB[2] * vecAC[0] - vecAB[0] * vecAC[2];
            fnormal[i * 3 + 2] = vecAB[0] * vecAC[1] - vecAB[1] * vecAC[0];
            // normalize
            length = (float) Math.sqrt((fnormal[i * 3 + 0] * fnormal[i * 3 + 0]
                    + fnormal[i * 3 + 1] * fnormal[i * 3 + 1] + fnormal[i * 3 + 2] * fnormal[i * 3 + 2]));
            for (j = 0; j < 3; j++)
                fnormal[i * 3 + j] = fnormal[i * 3 + j] / length;
            // add in contribution to all three vertices 
            for (j = 0; j < 3; j++) {
                icount[face[i * 3 + j]]++;
                for (k = 0; k < 3; k++)
                    normal[face[i * 3 + j] * 3 + k] += fnormal[i * 3 + k];
            }
        }
        // average and normalize all normal vectors
        for (i = 0; i < node_num; i++) {
            for (j = 0; j < 3; j++)
                normal[i * 3 + j] = normal[i * 3 + j] / icount[i];
            length = (float) Math.sqrt((normal[i * 3 + 0] * normal[i * 3 + 0]
                    + normal[i * 3 + 1] * normal[i * 3 + 1] + normal[i * 3 + 2] * normal[i * 3 + 2]));
            for (j = 0; j < 3; j++)
                normal[i * 3 + j] = normal[i * 3 + j] / length;
        }
    }

    // move the model center to (0,0,0)
    public void model_centerize() {
        cal_boxsize();
        float xcen = 0.5f * (nminmax[0] + nminmax[3]);
        float ycen = 0.5f * (nminmax[1] + nminmax[4]);
        float zcen = 0.5f * (nminmax[2] + nminmax[5]);
        for (int i = 0; i < node_num; i++) {
            node[i * 3 + 0] -= xcen;
            node[i * 3 + 1] -= ycen;
            node[i * 3 + 2] -= zcen;
        }
        // recalculating minmax box
        nminmax[0] -= xcen;
        nminmax[3] += xcen;
        nminmax[1] -= ycen;
        nminmax[4] += ycen;
        nminmax[2] -= zcen;
        nminmax[5] += zcen;
    }

    // calculate bounding box data
    public void cal_boxsize() {
        nminmax[0] = 1e9f;
        nminmax[1] = 1e9f;
        nminmax[2] = 1e9f;
        nminmax[3] = -1e9f;
        nminmax[4] = -1e9f;
        nminmax[5] = -1e9f;
        for (int i = 0; i < node_num; i++) {
            for (int j = 0; j < 3; j++) {
                nminmax[0 + j] = (nminmax[0 + j] > node[i * 3 + j]) ? node[i * 3 + j] : nminmax[0 + j];
                nminmax[3 + j] = (nminmax[3 + j] < node[i * 3 + j]) ? node[i * 3 + j] : nminmax[3 + j];
            }
        }
        is2D = false;
        if (Math.abs(nminmax[5] - nminmax[2]) < 1e-8)
            is2D = true;

        boxsize = 0.0f;
        boxsize = (nminmax[3] - nminmax[0]) > boxsize ? (nminmax[3] - nminmax[0]) : boxsize;
        boxsize = (nminmax[4] - nminmax[1]) > boxsize ? (nminmax[4] - nminmax[1]) : boxsize;
        boxsize = (nminmax[5] - nminmax[2]) > boxsize ? (nminmax[5] - nminmax[2]) : boxsize;
    }

    // read geometry data
    public void read_offline_data(String directory_name, boolean isAssetFile) throws IOException {

        HttpClient client = new DefaultHttpClient();
        int buffer_size = 8192;

        // Read in output data
        InputStreamReader isr;
        String dataString = directory_name + "/geometry.dat";

        if (!isAssetFile) {
            HttpGet request = new HttpGet(dataString);
            HttpResponse response = client.execute(request);
            isr = new InputStreamReader(response.getEntity().getContent());
        } else { // Read from assets
            isr = new InputStreamReader(context.getAssets().open(dataString));
        }
        BufferedReader reader = new BufferedReader(isr, buffer_size);

        String line = reader.readLine();
        String[] tokens = line.split(" ");

        node_num = Integer.parseInt(tokens[0]);
        int count = 1;
        ref_node = new float[node_num * 3];
        node = new float[node_num * 3];
        sol = new float[field_num][node_num];
        ucolor = new float[field_num][node_num * 4];
        for (int i = 0; i < node_num; i++) {
            ref_node[i * 3 + 0] = Float.parseFloat(tokens[count]);
            ref_node[i * 3 + 1] = Float.parseFloat(tokens[count + 1]);
            ref_node[i * 3 + 2] = Float.parseFloat(tokens[count + 2]);
            count += 3;
            node[i * 3 + 0] = ref_node[i * 3 + 0];
            node[i * 3 + 1] = ref_node[i * 3 + 1];
            node[i * 3 + 2] = ref_node[i * 3 + 2];
        }
        cal_boxsize();

        reg_num = Integer.parseInt(tokens[count]);
        face_num = Integer.parseInt(tokens[count + 1]);
        count += 2;
        face = new short[face_num * 3];
        for (int i = 0; i < face_num; i++) {
            face[i * 3 + 0] = Short.parseShort(tokens[count]);
            face[i * 3 + 1] = Short.parseShort(tokens[count + 1]);
            face[i * 3 + 2] = Short.parseShort(tokens[count + 2]);
            count += 3;
        }
        node_reg = new int[node_num];
        for (int i = 0; i < node_num; i++) {
            node_reg[i] = Integer.parseInt(tokens[count]);
            count++;
        }
        face_dom = new int[face_num];
        for (int i = 0; i < face_num; i++) {
            face_dom[i] = Integer.parseInt(tokens[count]);
            count++;
        }
        isr.close();

        // Create a wireframe list (edge data)
        face_wf = new short[face_num * 3 * 2];
        for (int i = 0; i < face_num; i++) {
            face_wf[i * 6 + 0 * 2 + 0] = face[i * 3 + 0];
            face_wf[i * 6 + 0 * 2 + 1] = face[i * 3 + 1];
            face_wf[i * 6 + 1 * 2 + 0] = face[i * 3 + 1];
            face_wf[i * 6 + 1 * 2 + 1] = face[i * 3 + 2];
            face_wf[i * 6 + 2 * 2 + 0] = face[i * 3 + 2];
            face_wf[i * 6 + 2 * 2 + 1] = face[i * 3 + 0];
        }

        if (!is2D())
            cal_normal_data();
    }

    // Affine transformation
    // LTfunc is of size [number of subdomain, 12]
    // a row of LTfunc is the rowwise flatten of the [3,3] transformation matrix and the [3,1] translation vector
    public void nodal_transform(float[][] LTfunc) {
        float[] old_node = new float[3];
        for (int i = 0; i < node_num; i++) {
            old_node[0] = ref_node[i * 3 + 0];
            old_node[1] = ref_node[i * 3 + 1];
            old_node[2] = ref_node[i * 3 + 2];
            node[i * 3 + 0] = LTfunc[node_reg[i]][0] * old_node[0] + LTfunc[node_reg[i]][1] * old_node[1]
                    + LTfunc[node_reg[i]][2] * old_node[2] + LTfunc[node_reg[i]][9];
            node[i * 3 + 1] = LTfunc[node_reg[i]][3] * old_node[0] + LTfunc[node_reg[i]][4] * old_node[1]
                    + LTfunc[node_reg[i]][5] * old_node[2] + LTfunc[node_reg[i]][10];
            node[i * 3 + 2] = LTfunc[node_reg[i]][6] * old_node[0] + LTfunc[node_reg[i]][7] * old_node[1]
                    + LTfunc[node_reg[i]][8] * old_node[2] + LTfunc[node_reg[i]][11];
        }
        cal_boxsize();
        model_centerize();
    }

    // assign 1 field solution
    public void set_field_data(float[] _val) {
        sol = null;
        field_num = 1;
        sol = new float[1][_val.length];
        sol[0] = _val;
        frame_num = new int[1];
        frame_num[0] = sol[0].length / node_num;
        cal_color_data();
    }

    public void set_field_data(float[] _val1, float[] _val2) {
        set_field_data(_val1, _val2, true);
    }

    // assign 2 field solutions
    public void set_field_data(float[] _val1, float[] _val2, boolean isDeformed) {
        if (isDeformed) {
            sol = null;
            // the solution field is the displacement field
            // merge displacement field into current vertex data
            field_num = 1;
            float val_min = _val1[0];
            float val_max = _val1[0];
            for (int i = 0; i < _val1.length; i++) {
                val_min = (val_min > _val1[i]) ? _val1[i] : val_min;
                val_max = (val_max < _val1[i]) ? _val1[i] : val_max;
            }
            for (int i = 0; i < _val2.length; i++) {
                val_min = (val_min > _val2[i]) ? _val2[i] : val_min;
                val_max = (val_max < _val2[i]) ? _val2[i] : val_max;
            }
            float sval = (val_max - val_min) / boxsize * 5;
            if ((_val1.length / node_num == 1) && (_val2.length / node_num == 1)) {
                sol = new float[1][node_num];
                for (int i = 0; i < node_num; i++) {
                    node[i * 3 + 0] = node[i * 3 + 0] + _val1[i] / sval;
                    node[i * 3 + 1] = node[i * 3 + 1] + _val2[i] / sval;
                    node[i * 3 + 2] = node[i * 3 + 2];
                    sol[0][i] = 0.0f;
                }
                frame_num = new int[1];
                frame_num[0] = 1;
            } else {
                int _vframe_num = (_val1.length / node_num);
                sol = new float[1][node_num * _vframe_num];
                for (int i = 0; i < node_num; i++)
                    for (int j = 0; j < _vframe_num; j++) {
                        vnode[j * node_num * 3 + i * 3 + 0] = vnode[j * node_num * 3 + i * 3 + 0]
                                + _val1[j * node_num + i] / sval;
                        vnode[j * node_num * 3 + i * 3 + 1] = vnode[j * node_num * 3 + i * 3 + 1]
                                + _val2[j * node_num + i] / sval;
                        vnode[j * node_num * 3 + i * 3 + 2] = vnode[j * node_num * 3 + i * 3 + 2];
                        sol[0][j * node_num + i] = 0.0f;
                    }
                frame_num = new int[1];
                frame_num[0] = _vframe_num;
            }

        } else {
            sol = null;
            field_num = 2;
            if ((_val1.length / node_num == 1) && (_val2.length / node_num == 1)) {
                sol = new float[2][node_num];
                for (int i = 0; i < node_num; i++) {
                    sol[0][i] = _val1[i];
                    sol[1][i] = _val2[i];
                }
                frame_num = new int[2];
                frame_num[0] = 1;
                frame_num[1] = 1;
            } else {
                int _vframe_num = (_val1.length / node_num);
                sol = new float[2][node_num * _vframe_num];
                for (int i = 0; i < node_num; i++)
                    for (int j = 0; j < _vframe_num; j++) {
                        sol[0][j * node_num + i] = _val1[j * node_num + i];
                        sol[1][j * node_num + i] = _val2[j * node_num + i];
                    }
                frame_num = new int[2];
                frame_num[0] = _vframe_num;
                frame_num[1] = _vframe_num;
            }

        }

        cal_color_data();
    }

    public void set_field_data(float[] _val1, float[] _val2, float[] _val3) {
        set_field_data(_val1, _val2, _val3, true);
    }

    // assign 3 field solutions
    public void set_field_data(float[] _val1, float[] _val2, float[] _val3, boolean isDeformed) {
        if (isDeformed) {
            sol = null;
            // the solution field is the displacement field
            // merge displacement field into current vertex data
            field_num = 1;
            float val_min = _val1[0];
            float val_max = _val1[0];
            for (int i = 0; i < _val1.length; i++) {
                val_min = (val_min > _val1[i]) ? _val1[i] : val_min;
                val_max = (val_max < _val1[i]) ? _val1[i] : val_max;
            }
            for (int i = 0; i < _val2.length; i++) {
                val_min = (val_min > _val2[i]) ? _val2[i] : val_min;
                val_max = (val_max < _val2[i]) ? _val2[i] : val_max;
            }
            for (int i = 0; i < _val3.length; i++) {
                val_min = (val_min > _val3[i]) ? _val3[i] : val_min;
                val_max = (val_max < _val3[i]) ? _val3[i] : val_max;
            }
            float sval = (val_max - val_min) / boxsize * 5;
            if ((_val1.length / node_num == 1) && (_val2.length / node_num == 1)
                    && (_val3.length / node_num == 1)) {
                sol = new float[1][node_num];
                for (int i = 0; i < node_num; i++) {
                    node[i * 3 + 0] = node[i * 3 + 0] + _val1[i] / sval;
                    node[i * 3 + 1] = node[i * 3 + 1] + _val2[i] / sval;
                    node[i * 3 + 2] = node[i * 3 + 2] + _val3[i] / sval;
                    ;
                    sol[0][i] = 0.0f;
                    frame_num = new int[1];
                    frame_num[0] = 1;
                }
            } else {
                int _vframe_num = (_val1.length / node_num);
                sol = new float[1][node_num * _vframe_num];
                for (int i = 0; i < node_num; i++)
                    for (int j = 0; j < _vframe_num; j++) {
                        vnode[j * node_num * 3 + i * 3 + 0] = vnode[j * node_num * 3 + i * 3 + 0]
                                + _val1[j * node_num + i] / sval;
                        vnode[j * node_num * 3 + i * 3 + 1] = vnode[j * node_num * 3 + i * 3 + 1]
                                + _val2[j * node_num + i] / sval;
                        vnode[j * node_num * 3 + i * 3 + 2] = vnode[j * node_num * 3 + i * 3 + 2]
                                + _val3[j * node_num + i] / sval;
                        sol[0][j * node_num + i] = 0.0f;
                    }
                frame_num = new int[1];
                frame_num[0] = _vframe_num;
            }
        } else {
            sol = null;
            field_num = 3;
            if ((_val1.length / node_num == 1) && (_val2.length / node_num == 1)
                    && (_val3.length / node_num == 1)) {
                sol = new float[3][node_num];
                for (int i = 0; i < node_num; i++) {
                    sol[0][i] = _val1[i];
                    sol[1][i] = _val2[i];
                    sol[2][i] = _val3[i];
                }
                frame_num = new int[3];
                frame_num[0] = 1;
                frame_num[1] = 1;
                frame_num[2] = 1;
            } else {
                int _vframe_num = (_val1.length / node_num);
                sol = new float[3][node_num * _vframe_num];
                for (int i = 0; i < node_num; i++)
                    for (int j = 0; j < _vframe_num; j++) {
                        sol[0][j * node_num + i] = _val1[j * node_num + i];
                        sol[1][j * node_num + i] = _val2[j * node_num + i];
                        sol[2][j * node_num + i] = _val3[j * node_num + i];
                    }
                frame_num = new int[3];
                frame_num[0] = _vframe_num;
                frame_num[1] = _vframe_num;
                frame_num[2] = _vframe_num;
            }
        }
        cal_color_data();
    }

    // assign 4 field solutions (4th field is sol col)
    public void set_field_data(float[] _val1, float[] _val2, float[] _val3, float[] _val4) {
        sol = null;

        // the solution field is the displacement field
        // merge displacement field into current vertex data
        field_num = 1;
        float val_min = _val1[0];
        float val_max = _val1[0];
        for (int i = 0; i < _val1.length; i++) {
            val_min = (val_min > _val1[i]) ? _val1[i] : val_min;
            val_max = (val_max < _val1[i]) ? _val1[i] : val_max;
        }
        for (int i = 0; i < _val2.length; i++) {
            val_min = (val_min > _val2[i]) ? _val2[i] : val_min;
            val_max = (val_max < _val2[i]) ? _val2[i] : val_max;
        }
        for (int i = 0; i < _val3.length; i++) {
            val_min = (val_min > _val3[i]) ? _val3[i] : val_min;
            val_max = (val_max < _val3[i]) ? _val3[i] : val_max;
        }
        float sval = (val_max - val_min) / boxsize * 5.0f;
        if ((_val1.length / node_num == 1) && (_val2.length / node_num == 1) && (_val3.length / node_num == 1)) {
            sol = new float[1][node_num];
            for (int i = 0; i < node_num; i++) {
                node[i * 3 + 0] = node[i * 3 + 0] + _val1[i] / sval;
                node[i * 3 + 1] = node[i * 3 + 1] + _val2[i] / sval;
                node[i * 3 + 2] = node[i * 3 + 2] + _val3[i] / sval;
                sol[0][i] = _val4[i];
                frame_num = new int[1];
                frame_num[0] = 1;
            }
        } else {
            int _vframe_num = (_val1.length / node_num);
            sol = new float[1][node_num * _vframe_num];
            for (int i = 0; i < node_num; i++)
                for (int j = 0; j < _vframe_num; j++) {
                    vnode[j * node_num * 3 + i * 3 + 0] = vnode[j * node_num * 3 + i * 3 + 0]
                            + _val1[j * node_num + i] / sval;
                    vnode[j * node_num * 3 + i * 3 + 1] = vnode[j * node_num * 3 + i * 3 + 1]
                            + _val2[j * node_num + i] / sval;
                    vnode[j * node_num * 3 + i * 3 + 2] = vnode[j * node_num * 3 + i * 3 + 2]
                            + _val3[j * node_num + i] / sval;
                    sol[0][j * node_num + i] = _val4[j * node_num + i];
                }
            frame_num = new int[1];
            frame_num[0] = _vframe_num;
        }
        cal_color_data();
    }

    // assign vertex data
    public void set_node_data(float[] _node) {
        node_num = _node.length / 3;
        node = null;
        node = _node;
        cal_boxsize();
        model_centerize();
    }

    // assign node region data
    public void set_node_reg_data(int[] _node_reg) {
        node_reg = null;
        node_reg = _node_reg;
    }

    // assign ref_node data
    public void set_ref_node_data(float[] _node) {
        node_num = _node.length / 3;
        ref_node = null;
        ref_node = _node;
        // copy ref_node to node
        if (node == null) {
            node = new float[node_num * 3];
            for (int i = 0; i < node_num; i++)
                for (int j = 0; j < 3; j++)
                    node[i * 3 + j] = ref_node[i * 3 + j];
        }
        cal_boxsize();
        model_centerize();
        //node = null;
    }

    // assign face data
    public void set_face_data(short[] _face) {
        face_num = _face.length / 3;
        face = null;
        face = _face;

        // Create a wireframe list
        face_wf = null;
        face_wf = new short[face_num * 3 * 2];
        for (int i = 0; i < face_num; i++) {
            face_wf[i * 6 + 0 * 2 + 0] = face[i * 3 + 0];
            face_wf[i * 6 + 0 * 2 + 1] = face[i * 3 + 1];
            face_wf[i * 6 + 1 * 2 + 0] = face[i * 3 + 1];
            face_wf[i * 6 + 1 * 2 + 1] = face[i * 3 + 2];
            face_wf[i * 6 + 2 * 2 + 0] = face[i * 3 + 2];
            face_wf[i * 6 + 2 * 2 + 1] = face[i * 3 + 0];
        }

        // Calculate normal data for 3D object
        if (!is2D())
            cal_normal_data();
    }

    // how many field we currently have?
    public float[] get_field_data(int ifn) {
        return sol[ifn];
    }

    // the vertex data
    public float[] get_node_data() {
        return node;
    }

    // the reference vertex data
    public float[] get_ref_node_data() {
        return ref_node;
    }

    // the face data
    public short[] get_face_data() {
        return face;
    }

    // the number of subdomain
    public int get_reg_num() {
        return reg_num;
    }

    // is our model flat (2D)?
    public boolean is2D() {
        return is2D;
    }

    // get node_reg data
    public int[] get_node_reg() {
        return node_reg;
    }

    // get LTfunc data
    // this also get us vertex animation data
    public void set_LTfunc(float[][][] _LTfunc, int _reg_num, int _vframe_num) {
        reg_num = _reg_num;
        vframe_num = _vframe_num;
        if (vframe_num == 0)
            isgeoani = false;
        else
            isgeoani = true;
        vLTfunc = _LTfunc;
        vnode = new float[vframe_num * node_num * 3];
        for (int i = 0; i < vframe_num; i++) {
            // get current nodal data
            nodal_transform(vLTfunc[i]);
            // copy current nodal data into animation list
            for (int j = 0; j < node_num; j++)
                for (int k = 0; k < 3; k++)
                    vnode[i * node_num * 3 + j * 3 + k] = node[j * 3 + k];
        }
    }

    // get LTfunc data
    // this also get us vertex animation data
    public void set_LTfunc(float[][][] _LTfunc) {
        vframe_num = _LTfunc.length;
        if (vframe_num == 1)
            isgeoani = false;
        else
            isgeoani = true;
        vLTfunc = _LTfunc;
        vnode = new float[vframe_num * node_num * 3];
        for (int i = 0; i < vframe_num; i++) {
            // get current nodal data
            nodal_transform(vLTfunc[i]);
            // copy current nodal data into animation list
            for (int j = 0; j < node_num; j++)
                for (int k = 0; k < 3; k++)
                    vnode[i * node_num * 3 + j * 3 + k] = node[j * 3 + k];
        }
    }

    public void mesh_transform_custom(Parameter[] mu) {
        vframe_num = mu.length;
        if (vframe_num == 1)
            isgeoani = false;
        else
            isgeoani = true;
        vnode = new float[vframe_num * node_num * 3];
        for (int i = 0; i < vframe_num; i++) {
            // get current nodal data
            float[] tmpnode = RBActivity.mRbSystem.mesh_transform(mu[i].getArray(), ref_node.clone());
            Log.d("GLRenderer", mu[i].getEntry(0) + " " + mu[i].getEntry(1));
            Log.d("GLRenderer", tmpnode[4] + " " + node[4]);
            node = tmpnode.clone();
            // copy current nodal data into animation list
            for (int j = 0; j < node_num; j++)
                for (int k = 0; k < 3; k++) {
                    vnode[i * node_num * 3 + j * 3 + k] = tmpnode[j * 3 + k];
                }
        }
    }
}