new plotter
This commit is contained in:
parent
b0608b8204
commit
8c172bbd8a
@ -284,4 +284,8 @@
|
|||||||
<string name="cpp_this_change_may_require_reboot">This change may require reboot</string>
|
<string name="cpp_this_change_may_require_reboot">This change may require reboot</string>
|
||||||
<string name="cpp_plot_3d">3D</string>
|
<string name="cpp_plot_3d">3D</string>
|
||||||
|
|
||||||
|
<string name="cpp_prefs_graph_plot_imag_title">Plot imaginary part of function</string>
|
||||||
|
<string name="cpp_prefs_graph_plot_imag_summary">If checked imaginary part of function will be plotted</string>
|
||||||
|
|
||||||
|
|
||||||
</resources>
|
</resources>
|
@ -129,6 +129,7 @@ public final class CalculatorPreferences {
|
|||||||
public static final Preference<Boolean> interpolate = new BooleanPreference("graph_interpolate", true);
|
public static final Preference<Boolean> interpolate = new BooleanPreference("graph_interpolate", true);
|
||||||
public static final Preference<GraphLineColor> lineColorReal = StringPreference.newInstance("graph_line_color_real", GraphLineColor.white, GraphLineColor.class);
|
public static final Preference<GraphLineColor> lineColorReal = StringPreference.newInstance("graph_line_color_real", GraphLineColor.white, GraphLineColor.class);
|
||||||
public static final Preference<GraphLineColor> lineColorImag = StringPreference.newInstance("graph_line_color_imag", GraphLineColor.blue, GraphLineColor.class);
|
public static final Preference<GraphLineColor> lineColorImag = StringPreference.newInstance("graph_line_color_imag", GraphLineColor.blue, GraphLineColor.class);
|
||||||
|
public static final Preference<Boolean> plotImag = new BooleanPreference("graph_plot_imag", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class History {
|
public static class History {
|
||||||
@ -185,6 +186,7 @@ public final class CalculatorPreferences {
|
|||||||
applyDefaultPreference(preferences, Graph.interpolate);
|
applyDefaultPreference(preferences, Graph.interpolate);
|
||||||
applyDefaultPreference(preferences, Graph.lineColorImag);
|
applyDefaultPreference(preferences, Graph.lineColorImag);
|
||||||
applyDefaultPreference(preferences, Graph.lineColorReal);
|
applyDefaultPreference(preferences, Graph.lineColorReal);
|
||||||
|
applyDefaultPreference(preferences, Graph.plotImag);
|
||||||
applyDefaultPreference(preferences, History.showIntermediateCalculations);
|
applyDefaultPreference(preferences, History.showIntermediateCalculations);
|
||||||
applyDefaultPreference(preferences, Calculations.calculateOnFly);
|
applyDefaultPreference(preferences, Calculations.calculateOnFly);
|
||||||
applyDefaultPreference(preferences, Calculations.preferredAngleUnits);
|
applyDefaultPreference(preferences, Calculations.preferredAngleUnits);
|
||||||
|
BIN
android-app/assets/Roboto-Regular.ttf
Normal file
BIN
android-app/assets/Roboto-Regular.ttf
Normal file
Binary file not shown.
@ -6,10 +6,15 @@
|
|||||||
|
|
||||||
<org.solovyev.android.ads.AdViewPreference a:layout="@layout/admob_pref"/>
|
<org.solovyev.android.ads.AdViewPreference a:layout="@layout/admob_pref"/>
|
||||||
|
|
||||||
<android.preference.CheckBoxPreference
|
<!--<android.preference.CheckBoxPreference
|
||||||
a:key="graph_interpolate"
|
a:key="graph_interpolate"
|
||||||
a:title="@string/prefs_graph_interpolate_function"
|
a:title="@string/prefs_graph_interpolate_function"
|
||||||
a:summary="@string/prefs_graph_interpolate_function_summary"/>
|
a:summary="@string/prefs_graph_interpolate_function_summary"/>-->
|
||||||
|
|
||||||
|
<android.preference.CheckBoxPreference
|
||||||
|
a:key="graph_plot_imag"
|
||||||
|
a:title="@string/cpp_prefs_graph_plot_imag_title"
|
||||||
|
a:summary="@string/cpp_prefs_graph_plot_imag_summary"/>
|
||||||
|
|
||||||
<ListPreference a:key="graph_line_color_real"
|
<ListPreference a:key="graph_line_color_real"
|
||||||
a:title="@string/prefs_graph_real_color_title"
|
a:title="@string/prefs_graph_real_color_title"
|
||||||
|
@ -44,6 +44,7 @@ public class CalculatorArityPlotFragment extends AbstractCalculatorPlotFragment
|
|||||||
|
|
||||||
final GraphLineColor realLineColor = CalculatorPreferences.Graph.lineColorReal.getPreference(preferences);
|
final GraphLineColor realLineColor = CalculatorPreferences.Graph.lineColorReal.getPreference(preferences);
|
||||||
final GraphLineColor imagLineColor = CalculatorPreferences.Graph.lineColorImag.getPreference(preferences);
|
final GraphLineColor imagLineColor = CalculatorPreferences.Graph.lineColorImag.getPreference(preferences);
|
||||||
|
final boolean plotImag = CalculatorPreferences.Graph.plotImag.getPreference(preferences);
|
||||||
|
|
||||||
// remove old
|
// remove old
|
||||||
final ViewGroup graphContainer = (ViewGroup) root.findViewById(R.id.main_fragment_layout);
|
final ViewGroup graphContainer = (ViewGroup) root.findViewById(R.id.main_fragment_layout);
|
||||||
@ -61,8 +62,10 @@ public class CalculatorArityPlotFragment extends AbstractCalculatorPlotFragment
|
|||||||
|
|
||||||
final List<FunctionPlotDef> functions = new ArrayList<FunctionPlotDef>();
|
final List<FunctionPlotDef> functions = new ArrayList<FunctionPlotDef>();
|
||||||
|
|
||||||
functions.add(FunctionPlotDef.newInstance(new RealArityFunction(arity, expression, xVariable, yVariable), FunctionLineDef.newInstance(realLineColor.getColor(), FunctionLineStyle.solid, 3f)));
|
functions.add(FunctionPlotDef.newInstance(new RealArityFunction(arity, expression, xVariable, yVariable), FunctionLineDef.newInstance(realLineColor.getColor(), FunctionLineStyle.solid, 3f, FunctionLineColorType.color_map)));
|
||||||
functions.add(FunctionPlotDef.newInstance(new ImaginaryArityFunction(arity, expression, xVariable, yVariable), FunctionLineDef.newInstance(imagLineColor.getColor(), FunctionLineStyle.solid, 3f)));
|
if (plotImag) {
|
||||||
|
functions.add(FunctionPlotDef.newInstance(new ImaginaryArityFunction(arity, expression, xVariable, yVariable), FunctionLineDef.newInstance(imagLineColor.getColor(), FunctionLineStyle.solid, 3f, FunctionLineColorType.color_map)));
|
||||||
|
}
|
||||||
|
|
||||||
switch (arity) {
|
switch (arity) {
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -0,0 +1,390 @@
|
|||||||
|
// This is a OpenGL ES 1.0 dynamic font rendering system. It loads actual font
|
||||||
|
// files, generates a font map (texture) from them, and allows rendering of
|
||||||
|
// text strings.
|
||||||
|
//
|
||||||
|
// NOTE: the rendering portions of this class uses a sprite batcher in order
|
||||||
|
// provide decent speed rendering. Also, rendering assumes a BOTTOM-LEFT
|
||||||
|
// origin, and the (x,y) positions are relative to that, as well as the
|
||||||
|
// bottom-left of the string to render.
|
||||||
|
|
||||||
|
package org.solovyev.android.calculator.plot;
|
||||||
|
|
||||||
|
import android.content.res.AssetManager;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Typeface;
|
||||||
|
import android.opengl.GLUtils;
|
||||||
|
|
||||||
|
import javax.microedition.khronos.opengles.GL10;
|
||||||
|
|
||||||
|
public class GLText {
|
||||||
|
|
||||||
|
//--Constants--//
|
||||||
|
public final static int CHAR_START = 32; // First Character (ASCII Code)
|
||||||
|
public final static int CHAR_END = 126; // Last Character (ASCII Code)
|
||||||
|
public final static int CHAR_CNT = ( ( ( CHAR_END - CHAR_START ) + 1 ) + 1 ); // Character Count (Including Character to use for Unknown)
|
||||||
|
|
||||||
|
public final static int CHAR_NONE = 32; // Character to Use for Unknown (ASCII Code)
|
||||||
|
public final static int CHAR_UNKNOWN = ( CHAR_CNT - 1 ); // Index of the Unknown Character
|
||||||
|
|
||||||
|
public final static int FONT_SIZE_MIN = 6; // Minumum Font Size (Pixels)
|
||||||
|
public final static int FONT_SIZE_MAX = 180; // Maximum Font Size (Pixels)
|
||||||
|
|
||||||
|
public final static int CHAR_BATCH_SIZE = 100; // Number of Characters to Render Per Batch
|
||||||
|
|
||||||
|
//--Members--//
|
||||||
|
GL10 gl; // GL10 Instance
|
||||||
|
AssetManager assets; // Asset Manager
|
||||||
|
SpriteBatch batch; // Batch Renderer
|
||||||
|
|
||||||
|
int fontPadX, fontPadY; // Font Padding (Pixels; On Each Side, ie. Doubled on Both X+Y Axis)
|
||||||
|
|
||||||
|
float fontHeight; // Font Height (Actual; Pixels)
|
||||||
|
float fontAscent; // Font Ascent (Above Baseline; Pixels)
|
||||||
|
float fontDescent; // Font Descent (Below Baseline; Pixels)
|
||||||
|
|
||||||
|
int textureId; // Font Texture ID [NOTE: Public for Testing Purposes Only!]
|
||||||
|
int textureSize; // Texture Size for Font (Square) [NOTE: Public for Testing Purposes Only!]
|
||||||
|
TextureRegion textureRgn; // Full Texture Region
|
||||||
|
|
||||||
|
float charWidthMax; // Character Width (Maximum; Pixels)
|
||||||
|
float charHeight; // Character Height (Maximum; Pixels)
|
||||||
|
final float[] charWidths; // Width of Each Character (Actual; Pixels)
|
||||||
|
TextureRegion[] charRgn; // Region of Each Character (Texture Coordinates)
|
||||||
|
int cellWidth, cellHeight; // Character Cell Width/Height
|
||||||
|
int rowCnt, colCnt; // Number of Rows/Columns
|
||||||
|
|
||||||
|
float scaleX, scaleY; // Font Scale (X,Y Axis)
|
||||||
|
float spaceX; // Additional (X,Y Axis) Spacing (Unscaled)
|
||||||
|
|
||||||
|
|
||||||
|
//--Constructor--//
|
||||||
|
// D: save GL instance + asset manager, create arrays, and initialize the members
|
||||||
|
// A: gl - OpenGL ES 10 Instance
|
||||||
|
public GLText(GL10 gl, AssetManager assets) {
|
||||||
|
this.gl = gl; // Save the GL10 Instance
|
||||||
|
this.assets = assets; // Save the Asset Manager Instance
|
||||||
|
|
||||||
|
batch = new SpriteBatch( gl, CHAR_BATCH_SIZE ); // Create Sprite Batch (with Defined Size)
|
||||||
|
|
||||||
|
charWidths = new float[CHAR_CNT]; // Create the Array of Character Widths
|
||||||
|
charRgn = new TextureRegion[CHAR_CNT]; // Create the Array of Character Regions
|
||||||
|
|
||||||
|
// initialize remaining members
|
||||||
|
fontPadX = 0;
|
||||||
|
fontPadY = 0;
|
||||||
|
|
||||||
|
fontHeight = 0.0f;
|
||||||
|
fontAscent = 0.0f;
|
||||||
|
fontDescent = 0.0f;
|
||||||
|
|
||||||
|
textureId = -1;
|
||||||
|
textureSize = 0;
|
||||||
|
|
||||||
|
charWidthMax = 0;
|
||||||
|
charHeight = 0;
|
||||||
|
|
||||||
|
cellWidth = 0;
|
||||||
|
cellHeight = 0;
|
||||||
|
rowCnt = 0;
|
||||||
|
colCnt = 0;
|
||||||
|
|
||||||
|
scaleX = 1.0f; // Default Scale = 1 (Unscaled)
|
||||||
|
scaleY = 1.0f; // Default Scale = 1 (Unscaled)
|
||||||
|
spaceX = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--Load Font--//
|
||||||
|
// description
|
||||||
|
// this will load the specified font file, create a texture for the defined
|
||||||
|
// character range, and setup all required values used to render with it.
|
||||||
|
// arguments:
|
||||||
|
// file - Filename of the font (.ttf, .otf) to use. In 'Assets' folder.
|
||||||
|
// size - Requested pixel size of font (height)
|
||||||
|
// padX, padY - Extra padding per character (X+Y Axis); to prevent overlapping characters.
|
||||||
|
public boolean load(String file, int size, int padX, int padY) {
|
||||||
|
|
||||||
|
// setup requested values
|
||||||
|
fontPadX = padX; // Set Requested X Axis Padding
|
||||||
|
fontPadY = padY; // Set Requested Y Axis Padding
|
||||||
|
|
||||||
|
// load the font and setup paint instance for drawing
|
||||||
|
Typeface tf = Typeface.createFromAsset( assets, file ); // Create the Typeface from Font File
|
||||||
|
Paint paint = new Paint(); // Create Android Paint Instance
|
||||||
|
paint.setAntiAlias( true ); // Enable Anti Alias
|
||||||
|
paint.setTextSize( size ); // Set Text Size
|
||||||
|
paint.setColor( 0xffffffff ); // Set ARGB (White, Opaque)
|
||||||
|
paint.setTypeface( tf ); // Set Typeface
|
||||||
|
|
||||||
|
// get font metrics
|
||||||
|
Paint.FontMetrics fm = paint.getFontMetrics(); // Get Font Metrics
|
||||||
|
fontHeight = (float)Math.ceil( Math.abs( fm.bottom ) + Math.abs( fm.top ) ); // Calculate Font Height
|
||||||
|
fontAscent = (float)Math.ceil( Math.abs( fm.ascent ) ); // Save Font Ascent
|
||||||
|
fontDescent = (float)Math.ceil( Math.abs( fm.descent ) ); // Save Font Descent
|
||||||
|
|
||||||
|
// determine the width of each character (including unknown character)
|
||||||
|
// also determine the maximum character width
|
||||||
|
char[] s = new char[2]; // Create Character Array
|
||||||
|
charWidthMax = charHeight = 0; // Reset Character Width/Height Maximums
|
||||||
|
float[] w = new float[2]; // Working Width Value
|
||||||
|
int cnt = 0; // Array Counter
|
||||||
|
for ( char c = CHAR_START; c <= CHAR_END; c++ ) { // FOR Each Character
|
||||||
|
s[0] = c; // Set Character
|
||||||
|
paint.getTextWidths( s, 0, 1, w ); // Get Character Bounds
|
||||||
|
charWidths[cnt] = w[0]; // Get Width
|
||||||
|
if ( charWidths[cnt] > charWidthMax ) // IF Width Larger Than Max Width
|
||||||
|
charWidthMax = charWidths[cnt]; // Save New Max Width
|
||||||
|
cnt++; // Advance Array Counter
|
||||||
|
}
|
||||||
|
s[0] = CHAR_NONE; // Set Unknown Character
|
||||||
|
paint.getTextWidths( s, 0, 1, w ); // Get Character Bounds
|
||||||
|
charWidths[cnt] = w[0]; // Get Width
|
||||||
|
if ( charWidths[cnt] > charWidthMax ) // IF Width Larger Than Max Width
|
||||||
|
charWidthMax = charWidths[cnt]; // Save New Max Width
|
||||||
|
cnt++; // Advance Array Counter
|
||||||
|
|
||||||
|
// set character height to font height
|
||||||
|
charHeight = fontHeight; // Set Character Height
|
||||||
|
|
||||||
|
// find the maximum size, validate, and setup cell sizes
|
||||||
|
cellWidth = (int)charWidthMax + ( 2 * fontPadX ); // Set Cell Width
|
||||||
|
cellHeight = (int)charHeight + ( 2 * fontPadY ); // Set Cell Height
|
||||||
|
int maxSize = cellWidth > cellHeight ? cellWidth : cellHeight; // Save Max Size (Width/Height)
|
||||||
|
if ( maxSize < FONT_SIZE_MIN || maxSize > FONT_SIZE_MAX ) // IF Maximum Size Outside Valid Bounds
|
||||||
|
return false; // Return Error
|
||||||
|
|
||||||
|
// set texture size based on max font size (width or height)
|
||||||
|
// NOTE: these values are fixed, based on the defined characters. when
|
||||||
|
// changing start/end characters (CHAR_START/CHAR_END) this will need adjustment too!
|
||||||
|
if ( maxSize <= 24 ) // IF Max Size is 18 or Less
|
||||||
|
textureSize = 256; // Set 256 Texture Size
|
||||||
|
else if ( maxSize <= 40 ) // ELSE IF Max Size is 40 or Less
|
||||||
|
textureSize = 512; // Set 512 Texture Size
|
||||||
|
else if ( maxSize <= 80 ) // ELSE IF Max Size is 80 or Less
|
||||||
|
textureSize = 1024; // Set 1024 Texture Size
|
||||||
|
else // ELSE IF Max Size is Larger Than 80 (and Less than FONT_SIZE_MAX)
|
||||||
|
textureSize = 2048; // Set 2048 Texture Size
|
||||||
|
|
||||||
|
// create an empty bitmap (alpha only)
|
||||||
|
Bitmap bitmap = Bitmap.createBitmap( textureSize, textureSize, Bitmap.Config.ALPHA_8 ); // Create Bitmap
|
||||||
|
Canvas canvas = new Canvas( bitmap ); // Create Canvas for Rendering to Bitmap
|
||||||
|
bitmap.eraseColor( 0x00000000 ); // Set Transparent Background (ARGB)
|
||||||
|
|
||||||
|
// calculate rows/columns
|
||||||
|
// NOTE: while not required for anything, these may be useful to have :)
|
||||||
|
colCnt = textureSize / cellWidth; // Calculate Number of Columns
|
||||||
|
rowCnt = (int)Math.ceil( (float)CHAR_CNT / (float)colCnt ); // Calculate Number of Rows
|
||||||
|
|
||||||
|
// render each of the characters to the canvas (ie. build the font map)
|
||||||
|
float x = fontPadX; // Set Start Position (X)
|
||||||
|
float y = ( cellHeight - 1 ) - fontDescent - fontPadY; // Set Start Position (Y)
|
||||||
|
for ( char c = CHAR_START; c <= CHAR_END; c++ ) { // FOR Each Character
|
||||||
|
s[0] = c; // Set Character to Draw
|
||||||
|
canvas.drawText( s, 0, 1, x, y, paint ); // Draw Character
|
||||||
|
x += cellWidth; // Move to Next Character
|
||||||
|
if ( ( x + cellWidth - fontPadX ) > textureSize ) { // IF End of Line Reached
|
||||||
|
x = fontPadX; // Set X for New Row
|
||||||
|
y += cellHeight; // Move Down a Row
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s[0] = CHAR_NONE; // Set Character to Use for NONE
|
||||||
|
canvas.drawText( s, 0, 1, x, y, paint ); // Draw Character
|
||||||
|
|
||||||
|
// generate a new texture
|
||||||
|
int[] textureIds = new int[1]; // Array to Get Texture Id
|
||||||
|
gl.glGenTextures( 1, textureIds, 0 ); // Generate New Texture
|
||||||
|
textureId = textureIds[0]; // Save Texture Id
|
||||||
|
|
||||||
|
// setup filters for texture
|
||||||
|
gl.glBindTexture( GL10.GL_TEXTURE_2D, textureId ); // Bind Texture
|
||||||
|
gl.glTexParameterf( GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST ); // Set Minification Filter
|
||||||
|
gl.glTexParameterf( GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR ); // Set Magnification Filter
|
||||||
|
gl.glTexParameterf( GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE ); // Set U Wrapping
|
||||||
|
gl.glTexParameterf( GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE ); // Set V Wrapping
|
||||||
|
|
||||||
|
// load the generated bitmap onto the texture
|
||||||
|
GLUtils.texImage2D( GL10.GL_TEXTURE_2D, 0, bitmap, 0 ); // Load Bitmap to Texture
|
||||||
|
gl.glBindTexture( GL10.GL_TEXTURE_2D, 0 ); // Unbind Texture
|
||||||
|
|
||||||
|
// release the bitmap
|
||||||
|
bitmap.recycle(); // Release the Bitmap
|
||||||
|
|
||||||
|
// setup the array of character texture regions
|
||||||
|
x = 0; // Initialize X
|
||||||
|
y = 0; // Initialize Y
|
||||||
|
for ( int c = 0; c < CHAR_CNT; c++ ) { // FOR Each Character (On Texture)
|
||||||
|
charRgn[c] = new TextureRegion( textureSize, textureSize, x, y, cellWidth-1, cellHeight-1 ); // Create Region for Character
|
||||||
|
x += cellWidth; // Move to Next Char (Cell)
|
||||||
|
if ( x + cellWidth > textureSize ) {
|
||||||
|
x = 0; // Reset X Position to Start
|
||||||
|
y += cellHeight; // Move to Next Row (Cell)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// create full texture region
|
||||||
|
textureRgn = new TextureRegion( textureSize, textureSize, 0, 0, textureSize, textureSize ); // Create Full Texture Region
|
||||||
|
|
||||||
|
// return success
|
||||||
|
return true; // Return Success
|
||||||
|
}
|
||||||
|
|
||||||
|
//--Begin/End Text Drawing--//
|
||||||
|
// D: call these methods before/after (respectively all draw() calls using a text instance
|
||||||
|
// NOTE: color is set on a per-batch basis, and fonts should be 8-bit alpha only!!!
|
||||||
|
// A: red, green, blue - RGB values for font (default = 1.0)
|
||||||
|
// alpha - optional alpha value for font (default = 1.0)
|
||||||
|
// R: [none]
|
||||||
|
public void begin() {
|
||||||
|
begin( 1.0f, 1.0f, 1.0f, 1.0f ); // Begin with White Opaque
|
||||||
|
}
|
||||||
|
public void begin(float alpha) {
|
||||||
|
begin( 1.0f, 1.0f, 1.0f, alpha ); // Begin with White (Explicit Alpha)
|
||||||
|
}
|
||||||
|
public void begin(float red, float green, float blue, float alpha) {
|
||||||
|
gl.glColor4f( red, green, blue, alpha ); // Set Color+Alpha
|
||||||
|
gl.glBindTexture( GL10.GL_TEXTURE_2D, textureId ); // Bind the Texture
|
||||||
|
batch.beginBatch(); // Begin Batch
|
||||||
|
}
|
||||||
|
public void end() {
|
||||||
|
batch.endBatch(); // End Batch
|
||||||
|
gl.glColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); // Restore Default Color/Alpha
|
||||||
|
}
|
||||||
|
|
||||||
|
//--Draw Text--//
|
||||||
|
// D: draw text at the specified x,y position
|
||||||
|
// A: text - the string to draw
|
||||||
|
// x, y - the x,y position to draw text at (bottom left of text; including descent)
|
||||||
|
// R: [none]
|
||||||
|
public void draw(String text, float x, float y) {
|
||||||
|
float chrHeight = cellHeight * scaleY; // Calculate Scaled Character Height
|
||||||
|
float chrWidth = cellWidth * scaleX; // Calculate Scaled Character Width
|
||||||
|
int len = text.length(); // Get String Length
|
||||||
|
x += ( chrWidth / 2.0f ) - ( fontPadX * scaleX ); // Adjust Start X
|
||||||
|
y += ( chrHeight / 2.0f ) - ( fontPadY * scaleY ); // Adjust Start Y
|
||||||
|
for ( int i = 0; i < len; i++ ) { // FOR Each Character in String
|
||||||
|
int c = (int)text.charAt( i ) - CHAR_START; // Calculate Character Index (Offset by First Char in Font)
|
||||||
|
if ( c < 0 || c >= CHAR_CNT ) // IF Character Not In Font
|
||||||
|
c = CHAR_UNKNOWN; // Set to Unknown Character Index
|
||||||
|
batch.drawSprite( x, y, chrWidth, chrHeight, charRgn[c] ); // Draw the Character
|
||||||
|
x += ( charWidths[c] + spaceX ) * scaleX; // Advance X Position by Scaled Character Width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--Draw Text Centered--//
|
||||||
|
// D: draw text CENTERED at the specified x,y position
|
||||||
|
// A: text - the string to draw
|
||||||
|
// x, y - the x,y position to draw text at (bottom left of text)
|
||||||
|
// R: the total width of the text that was drawn
|
||||||
|
public float drawC(String text, float x, float y) {
|
||||||
|
float len = getLength( text ); // Get Text Length
|
||||||
|
draw( text, x - ( len / 2.0f ), y - ( getCharHeight() / 2.0f ) ); // Draw Text Centered
|
||||||
|
return len; // Return Length
|
||||||
|
}
|
||||||
|
public float drawCX(String text, float x, float y) {
|
||||||
|
float len = getLength( text ); // Get Text Length
|
||||||
|
draw( text, x - ( len / 2.0f ), y ); // Draw Text Centered (X-Axis Only)
|
||||||
|
return len; // Return Length
|
||||||
|
}
|
||||||
|
public void drawCY(String text, float x, float y) {
|
||||||
|
draw( text, x, y - ( getCharHeight() / 2.0f ) ); // Draw Text Centered (Y-Axis Only)
|
||||||
|
}
|
||||||
|
|
||||||
|
//--Set Scale--//
|
||||||
|
// D: set the scaling to use for the font
|
||||||
|
// A: scale - uniform scale for both x and y axis scaling
|
||||||
|
// sx, sy - separate x and y axis scaling factors
|
||||||
|
// R: [none]
|
||||||
|
public void setScale(float scale) {
|
||||||
|
scaleX = scaleY = scale; // Set Uniform Scale
|
||||||
|
}
|
||||||
|
public void setScale(float sx, float sy) {
|
||||||
|
scaleX = sx; // Set X Scale
|
||||||
|
scaleY = sy; // Set Y Scale
|
||||||
|
}
|
||||||
|
|
||||||
|
//--Get Scale--//
|
||||||
|
// D: get the current scaling used for the font
|
||||||
|
// A: [none]
|
||||||
|
// R: the x/y scale currently used for scale
|
||||||
|
public float getScaleX() {
|
||||||
|
return scaleX; // Return X Scale
|
||||||
|
}
|
||||||
|
public float getScaleY() {
|
||||||
|
return scaleY; // Return Y Scale
|
||||||
|
}
|
||||||
|
|
||||||
|
//--Set Space--//
|
||||||
|
// D: set the spacing (unscaled; ie. pixel size) to use for the font
|
||||||
|
// A: space - space for x axis spacing
|
||||||
|
// R: [none]
|
||||||
|
public void setSpace(float space) {
|
||||||
|
spaceX = space; // Set Space
|
||||||
|
}
|
||||||
|
|
||||||
|
//--Get Space--//
|
||||||
|
// D: get the current spacing used for the font
|
||||||
|
// A: [none]
|
||||||
|
// R: the x/y space currently used for scale
|
||||||
|
public float getSpace() {
|
||||||
|
return spaceX; // Return X Space
|
||||||
|
}
|
||||||
|
|
||||||
|
//--Get Length of a String--//
|
||||||
|
// D: return the length of the specified string if rendered using current settings
|
||||||
|
// A: text - the string to get length for
|
||||||
|
// R: the length of the specified string (pixels)
|
||||||
|
public float getLength(String text) {
|
||||||
|
float len = 0.0f; // Working Length
|
||||||
|
int strLen = text.length(); // Get String Length (Characters)
|
||||||
|
for ( int i = 0; i < strLen; i++ ) { // For Each Character in String (Except Last
|
||||||
|
int c = (int)text.charAt( i ) - CHAR_START; // Calculate Character Index (Offset by First Char in Font)
|
||||||
|
len += ( charWidths[c] * scaleX ); // Add Scaled Character Width to Total Length
|
||||||
|
}
|
||||||
|
len += ( strLen > 1 ? ( ( strLen - 1 ) * spaceX ) * scaleX : 0 ); // Add Space Length
|
||||||
|
return len; // Return Total Length
|
||||||
|
}
|
||||||
|
|
||||||
|
//--Get Width/Height of Character--//
|
||||||
|
// D: return the scaled width/height of a character, or max character width
|
||||||
|
// NOTE: since all characters are the same height, no character index is required!
|
||||||
|
// NOTE: excludes spacing!!
|
||||||
|
// A: chr - the character to get width for
|
||||||
|
// R: the requested character size (scaled)
|
||||||
|
public float getCharWidth(char chr) {
|
||||||
|
int c = chr - CHAR_START; // Calculate Character Index (Offset by First Char in Font)
|
||||||
|
return ( charWidths[c] * scaleX ); // Return Scaled Character Width
|
||||||
|
}
|
||||||
|
public float getCharWidthMax() {
|
||||||
|
return ( charWidthMax * scaleX ); // Return Scaled Max Character Width
|
||||||
|
}
|
||||||
|
public float getCharHeight() {
|
||||||
|
return ( charHeight * scaleY ); // Return Scaled Character Height
|
||||||
|
}
|
||||||
|
|
||||||
|
//--Get Font Metrics--//
|
||||||
|
// D: return the specified (scaled) font metric
|
||||||
|
// A: [none]
|
||||||
|
// R: the requested font metric (scaled)
|
||||||
|
public float getAscent() {
|
||||||
|
return ( fontAscent * scaleY ); // Return Font Ascent
|
||||||
|
}
|
||||||
|
public float getDescent() {
|
||||||
|
return ( fontDescent * scaleY ); // Return Font Descent
|
||||||
|
}
|
||||||
|
public float getHeight() {
|
||||||
|
return ( fontHeight * scaleY ); // Return Font Height (Actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
//--Draw Font Texture--//
|
||||||
|
// D: draw the entire font texture (NOTE: for testing purposes only)
|
||||||
|
// A: width, height - the width and height of the area to draw to. this is used
|
||||||
|
// to draw the texture to the top-left corner.
|
||||||
|
public void drawTexture(int width, int height) {
|
||||||
|
batch.beginBatch( textureId ); // Begin Batch (Bind Texture)
|
||||||
|
batch.drawSprite( textureSize / 2, height - ( textureSize / 2 ), textureSize, textureSize, textureRgn ); // Draw
|
||||||
|
batch.endBatch(); // End Batch
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -15,31 +15,39 @@ import java.nio.ShortBuffer;
|
|||||||
|
|
||||||
class Graph3d {
|
class Graph3d {
|
||||||
|
|
||||||
private final int N;
|
// vertices count per polygon (triangle = 3)
|
||||||
|
public static final int VERTICES_COUNT = 3;
|
||||||
|
|
||||||
|
// color components count per color
|
||||||
|
public static final int COLOR_COMPONENTS_COUNT = 4;
|
||||||
|
|
||||||
|
// linear polygons count
|
||||||
|
private final int n;
|
||||||
|
|
||||||
private final boolean useHighQuality3d;
|
private final boolean useHighQuality3d;
|
||||||
private ShortBuffer verticeIdx;
|
private ShortBuffer verticeIdx;
|
||||||
private FloatBuffer vertexBuf;
|
private FloatBuffer vertexBuf;
|
||||||
private ByteBuffer colorBuf;
|
private ByteBuffer colorBuf;
|
||||||
private int vertexVbo, colorVbo, vertexElementVbo;
|
private int vertexVbo, colorVbo, vertexElementVbo;
|
||||||
private boolean useVBO;
|
private boolean useVBO;
|
||||||
private int nVertex;
|
private int polygonsⁿ;
|
||||||
|
|
||||||
Graph3d(GL11 gl, boolean useHighQuality3d) {
|
Graph3d(GL11 gl, boolean useHighQuality3d) {
|
||||||
this.useHighQuality3d = useHighQuality3d;
|
this.useHighQuality3d = useHighQuality3d;
|
||||||
this.N = useHighQuality3d ? 36 : 24;
|
this.n = useHighQuality3d ? 36 : 24;
|
||||||
|
|
||||||
short[] b = new short[N * N];
|
short[] b = new short[n * n];
|
||||||
int p = 0;
|
int p = 0;
|
||||||
for (int i = 0; i < N; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
short v = 0;
|
short v = 0;
|
||||||
for (int j = 0; j < N; v += N + N, j += 2) {
|
for (int j = 0; j < n; v += n + n, j += 2) {
|
||||||
b[p++] = (short) (v + i);
|
b[p++] = (short) (v + i);
|
||||||
b[p++] = (short) (v + N + N - 1 - i);
|
b[p++] = (short) (v + n + n - 1 - i);
|
||||||
}
|
}
|
||||||
v = (short) (N * (N - 2));
|
v = (short) (n * (n - 2));
|
||||||
i++;
|
i++;
|
||||||
for (int j = N - 1; j >= 0; v -= N + N, j -= 2) {
|
for (int j = n - 1; j >= 0; v -= n + n, j -= 2) {
|
||||||
b[p++] = (short) (v + N + N - 1 - i);
|
b[p++] = (short) (v + n + n - 1 - i);
|
||||||
b[p++] = (short) (v + i);
|
b[p++] = (short) (v + i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -88,147 +96,56 @@ class Graph3d {
|
|||||||
final Function function = fpd.getFunction();
|
final Function function = fpd.getFunction();
|
||||||
final FunctionLineDef lineDef = fpd.getLineDef();
|
final FunctionLineDef lineDef = fpd.getLineDef();
|
||||||
final int NTICK = useHighQuality3d ? 5 : 0;
|
final int NTICK = useHighQuality3d ? 5 : 0;
|
||||||
|
|
||||||
final float size = 4 * zoom;
|
final float size = 4 * zoom;
|
||||||
final float minX = -size, maxX = size, minY = -size, maxY = size;
|
|
||||||
|
|
||||||
//Calculator.log("update VBOs " + vertexVbo + ' ' + colorVbo + ' ' + vertexElementVbo);
|
//Calculator.log("update VBOs " + vertexVbo + ' ' + colorVbo + ' ' + vertexElementVbo);
|
||||||
nVertex = N * N + 6 + 8 + NTICK * 6;
|
polygonsⁿ = n * n + 6 + 8 + NTICK * 6;
|
||||||
|
|
||||||
final float vertices[] = new float[nVertex * 3];
|
// triangle polygon => 3 vertices per polygon
|
||||||
final byte colors[] = new byte[nVertex * 4];
|
final float vertices[] = new float[polygonsⁿ * VERTICES_COUNT];
|
||||||
|
|
||||||
if (fpd != null) {
|
float maxAbsZ = fillFunctionPolygonVertices(function, size, vertices);
|
||||||
//Calculator.log("Graph3d update");
|
final byte[] colors = prepareFunctionPolygonColors(lineDef, vertices, maxAbsZ);
|
||||||
float sizeX = maxX - minX;
|
|
||||||
float sizeY = maxY - minY;
|
|
||||||
float stepX = sizeX / (N - 1);
|
|
||||||
float stepY = sizeY / (N - 1);
|
|
||||||
int pos = 0;
|
|
||||||
double sum = 0;
|
|
||||||
float y = minY;
|
|
||||||
float x = minX - stepX;
|
|
||||||
int nRealPoints = 0;
|
|
||||||
|
|
||||||
final int arity = function.arity();
|
|
||||||
|
|
||||||
for (int i = 0; i < N; i++, y += stepY) {
|
int base = n * n * 3;
|
||||||
float xinc = (i & 1) == 0 ? stepX : -stepX;
|
int colorBase = n * n * 4;
|
||||||
|
|
||||||
x += xinc;
|
|
||||||
for (int j = 0; j < N; ++j, x += xinc, pos += 3) {
|
|
||||||
|
|
||||||
final float z;
|
|
||||||
switch (arity) {
|
|
||||||
case 2:
|
|
||||||
z = (float) function.eval(x, y);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
// todo serso: optimize (can be calculated once before loop)
|
|
||||||
z = (float) function.eval(x);
|
|
||||||
break;
|
|
||||||
case 0:
|
|
||||||
// todo serso: optimize (can be calculated once)
|
|
||||||
z = (float) function.eval();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException();
|
|
||||||
}
|
|
||||||
|
|
||||||
vertices[pos] = x;
|
|
||||||
vertices[pos + 1] = y;
|
|
||||||
vertices[pos + 2] = z;
|
|
||||||
|
|
||||||
if (!Float.isNaN(z)) {
|
|
||||||
sum += z * z;
|
|
||||||
++nRealPoints;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float maxAbs = (float) Math.sqrt(sum / nRealPoints);
|
|
||||||
maxAbs *= .9f;
|
|
||||||
maxAbs = Math.min(maxAbs, 15);
|
|
||||||
maxAbs = Math.max(maxAbs, .001f);
|
|
||||||
|
|
||||||
final int lineColor = lineDef.getLineColor();
|
|
||||||
final int limitColor = N * N * 4;
|
|
||||||
for (int i = 0, j = 2; i < limitColor; i += 4, j += 3) {
|
|
||||||
final float z = vertices[j];
|
|
||||||
|
|
||||||
if (!Float.isNaN(z)) {
|
|
||||||
if (lineDef.getLineColorType() == FunctionLineColorType.color_map) {
|
|
||||||
final float a = z / maxAbs;
|
|
||||||
final float abs = a < 0 ? -a : a;
|
|
||||||
colors[i] = floatToByte(a);
|
|
||||||
colors[i + 1] = floatToByte(1 - abs * .3f);
|
|
||||||
colors[i + 2] = floatToByte(-a);
|
|
||||||
} else {
|
|
||||||
colors[i] = (byte) Color.red(lineColor);
|
|
||||||
colors[i + 1] = (byte) Color.green(lineColor);
|
|
||||||
colors[i + 2] = (byte) Color.blue(lineColor);
|
|
||||||
}
|
|
||||||
colors[i + 3] = (byte) 255;
|
|
||||||
} else {
|
|
||||||
vertices[j] = 0;
|
|
||||||
colors[i] = 0;
|
|
||||||
colors[i + 1] = 0;
|
|
||||||
colors[i + 2] = 0;
|
|
||||||
colors[i + 3] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int base = N * N * 3;
|
|
||||||
int colorBase = N * N * 4;
|
|
||||||
int p = base;
|
|
||||||
final int baseSize = 2;
|
final int baseSize = 2;
|
||||||
for (int i = -baseSize; i <= baseSize; i += 2 * baseSize) {
|
|
||||||
vertices[p] = i;
|
fillBasePolygonVectors(vertices, colors, base, colorBase, baseSize);
|
||||||
vertices[p + 1] = -baseSize;
|
|
||||||
vertices[p + 2] = 0;
|
|
||||||
p += 3;
|
|
||||||
vertices[p] = i;
|
|
||||||
vertices[p + 1] = baseSize;
|
|
||||||
vertices[p + 2] = 0;
|
|
||||||
p += 3;
|
|
||||||
vertices[p] = -baseSize;
|
|
||||||
vertices[p + 1] = i;
|
|
||||||
vertices[p + 2] = 0;
|
|
||||||
p += 3;
|
|
||||||
vertices[p] = baseSize;
|
|
||||||
vertices[p + 1] = i;
|
|
||||||
vertices[p + 2] = 0;
|
|
||||||
p += 3;
|
|
||||||
}
|
|
||||||
for (int i = colorBase; i < colorBase + 8 * 4; i += 4) {
|
|
||||||
colors[i] = 0;
|
|
||||||
colors[i + 1] = 0;
|
|
||||||
colors[i + 2] = (byte) 255;
|
|
||||||
colors[i + 3] = (byte) 255;
|
|
||||||
}
|
|
||||||
base += 8 * 3;
|
base += 8 * 3;
|
||||||
colorBase += 8 * 4;
|
colorBase += 8 * 4;
|
||||||
|
|
||||||
final float unit = 2;
|
fillAxisPolygonVectors(vertices, colors, base, colorBase);
|
||||||
final float axis[] = {
|
|
||||||
0, 0, 0,
|
|
||||||
unit, 0, 0,
|
|
||||||
0, 0, 0,
|
|
||||||
0, unit, 0,
|
|
||||||
0, 0, 0,
|
|
||||||
0, 0, unit,
|
|
||||||
};
|
|
||||||
System.arraycopy(axis, 0, vertices, base, 6 * 3);
|
|
||||||
for (int i = colorBase; i < colorBase + 6 * 4; i += 4) {
|
|
||||||
colors[i] = (byte) 255;
|
|
||||||
colors[i + 1] = (byte) 255;
|
|
||||||
colors[i + 2] = (byte) 255;
|
|
||||||
colors[i + 3] = (byte) 255;
|
|
||||||
}
|
|
||||||
base += 6 * 3;
|
base += 6 * 3;
|
||||||
colorBase += 6 * 4;
|
colorBase += 6 * 4;
|
||||||
|
|
||||||
p = base;
|
fillAxisGridPolygonVectors(NTICK, vertices, colors, base, colorBase);
|
||||||
|
|
||||||
|
vertexBuf = buildBuffer(vertices);
|
||||||
|
colorBuf = buildBuffer(colors);
|
||||||
|
|
||||||
|
if (useVBO) {
|
||||||
|
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, vertexVbo);
|
||||||
|
gl.glBufferData(GL11.GL_ARRAY_BUFFER, vertexBuf.capacity() * 4, vertexBuf, GL11.GL_STATIC_DRAW);
|
||||||
|
vertexBuf = null;
|
||||||
|
|
||||||
|
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, colorVbo);
|
||||||
|
gl.glBufferData(GL11.GL_ARRAY_BUFFER, colorBuf.capacity(), colorBuf, GL11.GL_STATIC_DRAW);
|
||||||
|
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);
|
||||||
|
colorBuf = null;
|
||||||
|
|
||||||
|
gl.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, vertexElementVbo);
|
||||||
|
gl.glBufferData(GL11.GL_ELEMENT_ARRAY_BUFFER, verticeIdx.capacity() * 2, verticeIdx, GL11.GL_STATIC_DRAW);
|
||||||
|
gl.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fillAxisGridPolygonVectors(int NTICK, float[] vertices, byte[] colors, int base, int colorBase) {
|
||||||
|
int p = base;
|
||||||
final float tick = .03f;
|
final float tick = .03f;
|
||||||
final float offset = .01f;
|
final float offset = .01f;
|
||||||
for (int i = 1; i <= NTICK; ++i) {
|
for (int i = 1; i <= NTICK; ++i) {
|
||||||
@ -263,26 +180,143 @@ class Graph3d {
|
|||||||
for (int i = colorBase + NTICK * 6 * 4 - 1; i >= colorBase; --i) {
|
for (int i = colorBase + NTICK * 6 * 4 - 1; i >= colorBase; --i) {
|
||||||
colors[i] = (byte) 255;
|
colors[i] = (byte) 255;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
vertexBuf = buildBuffer(vertices);
|
private void fillAxisPolygonVectors(float[] vertices, byte[] colors, int base, int colorBase) {
|
||||||
colorBuf = buildBuffer(colors);
|
final float unit = 2;
|
||||||
|
final float axis[] = {
|
||||||
if (useVBO) {
|
0, 0, 0,
|
||||||
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, vertexVbo);
|
unit, 0, 0,
|
||||||
gl.glBufferData(GL11.GL_ARRAY_BUFFER, vertexBuf.capacity() * 4, vertexBuf, GL11.GL_STATIC_DRAW);
|
0, 0, 0,
|
||||||
vertexBuf = null;
|
0, unit, 0,
|
||||||
|
0, 0, 0,
|
||||||
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, colorVbo);
|
0, 0, unit,
|
||||||
gl.glBufferData(GL11.GL_ARRAY_BUFFER, colorBuf.capacity(), colorBuf, GL11.GL_STATIC_DRAW);
|
};
|
||||||
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);
|
System.arraycopy(axis, 0, vertices, base, 6 * 3);
|
||||||
colorBuf = null;
|
for (int i = colorBase; i < colorBase + 6 * 4; i += 4) {
|
||||||
|
colors[i] = (byte) 255;
|
||||||
gl.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, vertexElementVbo);
|
colors[i + 1] = (byte) 255;
|
||||||
gl.glBufferData(GL11.GL_ELEMENT_ARRAY_BUFFER, verticeIdx.capacity() * 2, verticeIdx, GL11.GL_STATIC_DRAW);
|
colors[i + 2] = (byte) 255;
|
||||||
gl.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, 0);
|
colors[i + 3] = (byte) 255;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void fillBasePolygonVectors(float[] vertices, byte[] colors, int base, int colorBase, int baseSize) {
|
||||||
|
int p = base;
|
||||||
|
for (int i = -baseSize; i <= baseSize; i += 2 * baseSize) {
|
||||||
|
vertices[p] = i;
|
||||||
|
vertices[p + 1] = -baseSize;
|
||||||
|
vertices[p + 2] = 0;
|
||||||
|
p += 3;
|
||||||
|
vertices[p] = i;
|
||||||
|
vertices[p + 1] = baseSize;
|
||||||
|
vertices[p + 2] = 0;
|
||||||
|
p += 3;
|
||||||
|
vertices[p] = -baseSize;
|
||||||
|
vertices[p + 1] = i;
|
||||||
|
vertices[p + 2] = 0;
|
||||||
|
p += 3;
|
||||||
|
vertices[p] = baseSize;
|
||||||
|
vertices[p + 1] = i;
|
||||||
|
vertices[p + 2] = 0;
|
||||||
|
p += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = colorBase; i < colorBase + 8 * 4; i += 4) {
|
||||||
|
colors[i] = (byte) 255;
|
||||||
|
colors[i + 1] = (byte) 255;
|
||||||
|
colors[i + 2] = (byte) 255;
|
||||||
|
colors[i + 3] = (byte) 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private float fillFunctionPolygonVertices(Function function, float size, float[] vertices) {
|
||||||
|
final int arity = function.arity();
|
||||||
|
|
||||||
|
final float minX = -size;
|
||||||
|
final float maxX = size;
|
||||||
|
final float minY = -size;
|
||||||
|
final float maxY = size;
|
||||||
|
|
||||||
|
float Δx = (maxX - minX) / (n - 1);
|
||||||
|
float Δy = (maxY - minY) / (n - 1);
|
||||||
|
|
||||||
|
float y = minY;
|
||||||
|
float x = minX - Δx;
|
||||||
|
|
||||||
|
float maxAbsZ = 0;
|
||||||
|
|
||||||
|
float z = 0;
|
||||||
|
if (arity == 0) {
|
||||||
|
z = (float) function.eval();
|
||||||
|
}
|
||||||
|
|
||||||
|
int k = 0;
|
||||||
|
for (int i = 0; i < n; i++, y += Δy) {
|
||||||
|
float xinc = (i & 1) == 0 ? Δx : -Δx;
|
||||||
|
|
||||||
|
x += xinc;
|
||||||
|
|
||||||
|
if (arity == 1) {
|
||||||
|
z = (float) function.eval(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < n; j++, x += xinc, k += VERTICES_COUNT) {
|
||||||
|
|
||||||
|
if (arity == 2) {
|
||||||
|
z = (float) function.eval(y, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
vertices[k] = x;
|
||||||
|
vertices[k + 1] = y;
|
||||||
|
vertices[k + 2] = z;
|
||||||
|
|
||||||
|
if (!Float.isNaN(z)) {
|
||||||
|
final float absZ = Math.abs(z);
|
||||||
|
if (absZ > maxAbsZ) {
|
||||||
|
maxAbsZ = absZ;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
vertices[k + 2] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return maxAbsZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] prepareFunctionPolygonColors(FunctionLineDef lineDef, float[] vertices, float maxAbsZ) {
|
||||||
|
// 4 color components per polygon (color[i] = red, color[i+1] = green, color[i+2] = blue, color[i+3] = alpha )
|
||||||
|
final byte colors[] = new byte[polygonsⁿ * COLOR_COMPONENTS_COUNT];
|
||||||
|
|
||||||
|
final int lineColor = lineDef.getLineColor();
|
||||||
|
final int colorComponentsCount = n * n * COLOR_COMPONENTS_COUNT;
|
||||||
|
for (int i = 0, j = VERTICES_COUNT - 1; i < colorComponentsCount; i += COLOR_COMPONENTS_COUNT, j += VERTICES_COUNT) {
|
||||||
|
final float z = vertices[j];
|
||||||
|
|
||||||
|
if (!Float.isNaN(z)) {
|
||||||
|
if (lineDef.getLineColorType() == FunctionLineColorType.color_map) {
|
||||||
|
final float color = z / maxAbsZ;
|
||||||
|
final float abs = Math.abs(color);
|
||||||
|
colors[i] = floatToByte(color);
|
||||||
|
colors[i + 1] = floatToByte(1 - abs * .3f);
|
||||||
|
colors[i + 2] = floatToByte(-color);
|
||||||
|
} else {
|
||||||
|
colors[i] = (byte) Color.red(lineColor);
|
||||||
|
colors[i + 1] = (byte) Color.green(lineColor);
|
||||||
|
colors[i + 2] = (byte) Color.blue(lineColor);
|
||||||
|
}
|
||||||
|
colors[i + 3] = (byte) 255;
|
||||||
|
} else {
|
||||||
|
colors[i] = 0;
|
||||||
|
colors[i + 1] = 0;
|
||||||
|
colors[i + 2] = 0;
|
||||||
|
colors[i + 3] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return colors;
|
||||||
|
}
|
||||||
|
|
||||||
private byte floatToByte(float v) {
|
private byte floatToByte(float v) {
|
||||||
if (v <= 0) {
|
if (v <= 0) {
|
||||||
return (byte) 0;
|
return (byte) 0;
|
||||||
@ -307,16 +341,16 @@ class Graph3d {
|
|||||||
// gl.glDrawArrays(GL10.GL_LINE_STRIP, 0, N*N);
|
// gl.glDrawArrays(GL10.GL_LINE_STRIP, 0, N*N);
|
||||||
|
|
||||||
gl.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, vertexElementVbo);
|
gl.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, vertexElementVbo);
|
||||||
gl.glDrawElements(GL10.GL_LINE_STRIP, N * N, GL10.GL_UNSIGNED_SHORT, 0);
|
gl.glDrawElements(GL10.GL_LINE_STRIP, n * n, GL10.GL_UNSIGNED_SHORT, 0);
|
||||||
gl.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, 0);
|
gl.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
} else {
|
} else {
|
||||||
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuf);
|
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuf);
|
||||||
gl.glColorPointer(4, GL10.GL_UNSIGNED_BYTE, 0, colorBuf);
|
gl.glColorPointer(4, GL10.GL_UNSIGNED_BYTE, 0, colorBuf);
|
||||||
gl.glDrawElements(GL10.GL_LINE_STRIP, N * N, GL10.GL_UNSIGNED_SHORT, verticeIdx);
|
gl.glDrawElements(GL10.GL_LINE_STRIP, n * n, GL10.GL_UNSIGNED_SHORT, verticeIdx);
|
||||||
}
|
}
|
||||||
final int N2 = N * N;
|
final int N2 = n * n;
|
||||||
gl.glDrawArrays(GL10.GL_LINE_STRIP, 0, N2);
|
gl.glDrawArrays(GL10.GL_LINE_STRIP, 0, N2);
|
||||||
gl.glDrawArrays(GL10.GL_LINES, N2, nVertex - N2);
|
gl.glDrawArrays(GL10.GL_LINES, N2, polygonsⁿ - N2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isUseHighQuality3d() {
|
public boolean isUseHighQuality3d() {
|
||||||
|
@ -10,6 +10,7 @@ import android.util.AttributeSet;
|
|||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.widget.ZoomButtonsController;
|
import android.widget.ZoomButtonsController;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.solovyev.android.calculator.App;
|
||||||
|
|
||||||
import javax.microedition.khronos.opengles.GL10;
|
import javax.microedition.khronos.opengles.GL10;
|
||||||
import javax.microedition.khronos.opengles.GL11;
|
import javax.microedition.khronos.opengles.GL11;
|
||||||
@ -27,6 +28,9 @@ public class Graph3dView extends GLView implements GraphView {
|
|||||||
private float zoomLevel = 1, targetZoom, zoomStep = 0, currentZoom;
|
private float zoomLevel = 1, targetZoom, zoomStep = 0, currentZoom;
|
||||||
private FPS fps = new FPS();
|
private FPS fps = new FPS();
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private GLText glText;
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private List<Graph3d> graphs = new ArrayList<Graph3d>();
|
private List<Graph3d> graphs = new ArrayList<Graph3d>();
|
||||||
|
|
||||||
@ -204,6 +208,9 @@ public class Graph3dView extends GLView implements GraphView {
|
|||||||
gl.glViewport(0, 0, width, height);
|
gl.glViewport(0, 0, width, height);
|
||||||
initFrustum(gl, DISTANCE * zoomLevel);
|
initFrustum(gl, DISTANCE * zoomLevel);
|
||||||
currentZoom = zoomLevel;
|
currentZoom = zoomLevel;
|
||||||
|
|
||||||
|
glText = new GLText( gl, App.getInstance().getApplication().getAssets() );
|
||||||
|
glText.load("Roboto-Regular.ttf", 32, 2, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -229,6 +236,7 @@ public class Graph3dView extends GLView implements GraphView {
|
|||||||
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
|
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
|
||||||
gl.glMatrixMode(GL10.GL_MODELVIEW);
|
gl.glMatrixMode(GL10.GL_MODELVIEW);
|
||||||
gl.glLoadIdentity();
|
gl.glLoadIdentity();
|
||||||
|
|
||||||
gl.glTranslatef(0, 0, -DISTANCE * zoomLevel);
|
gl.glTranslatef(0, 0, -DISTANCE * zoomLevel);
|
||||||
|
|
||||||
Matrix.setIdentityM(matrix2, 0);
|
Matrix.setIdentityM(matrix2, 0);
|
||||||
@ -253,6 +261,24 @@ public class Graph3dView extends GLView implements GraphView {
|
|||||||
for (Graph3d graph : graphs) {
|
for (Graph3d graph : graphs) {
|
||||||
graph.draw(gl);
|
graph.draw(gl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//updateText(gl, glText);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawText(@NotNull GLText glText) {
|
||||||
|
glText.begin(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
glText.draw( "Test!", 0, 0 );
|
||||||
|
glText.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateText(@NotNull GL11 gl, @NotNull GLText glText) {
|
||||||
|
gl.glEnable( GL10.GL_TEXTURE_2D );
|
||||||
|
gl.glEnable( GL10.GL_BLEND );
|
||||||
|
gl.glBlendFunc( GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA );
|
||||||
|
drawText(glText);
|
||||||
|
gl.glDisable( GL10.GL_BLEND );
|
||||||
|
gl.glDisable( GL10.GL_TEXTURE_2D );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ensureGraphsSize(@NotNull GL11 gl) {
|
private void ensureGraphsSize(@NotNull GL11 gl) {
|
||||||
|
@ -0,0 +1,120 @@
|
|||||||
|
package org.solovyev.android.calculator.plot;
|
||||||
|
|
||||||
|
import javax.microedition.khronos.opengles.GL10;
|
||||||
|
|
||||||
|
public class SpriteBatch {
|
||||||
|
|
||||||
|
//--Constants--//
|
||||||
|
final static int VERTEX_SIZE = 4; // Vertex Size (in Components) ie. (X,Y,U,V)
|
||||||
|
final static int VERTICES_PER_SPRITE = 4; // Vertices Per Sprite
|
||||||
|
final static int INDICES_PER_SPRITE = 6; // Indices Per Sprite
|
||||||
|
|
||||||
|
//--Members--//
|
||||||
|
GL10 gl; // GL Instance
|
||||||
|
Vertices vertices; // Vertices Instance Used for Rendering
|
||||||
|
float[] vertexBuffer; // Vertex Buffer
|
||||||
|
int bufferIndex; // Vertex Buffer Start Index
|
||||||
|
int maxSprites; // Maximum Sprites Allowed in Buffer
|
||||||
|
int numSprites; // Number of Sprites Currently in Buffer
|
||||||
|
|
||||||
|
//--Constructor--//
|
||||||
|
// D: prepare the sprite batcher for specified maximum number of sprites
|
||||||
|
// A: gl - the gl instance to use for rendering
|
||||||
|
// maxSprites - the maximum allowed sprites per batch
|
||||||
|
public SpriteBatch(GL10 gl, int maxSprites) {
|
||||||
|
this.gl = gl; // Save GL Instance
|
||||||
|
this.vertexBuffer = new float[maxSprites * VERTICES_PER_SPRITE * VERTEX_SIZE]; // Create Vertex Buffer
|
||||||
|
this.vertices = new Vertices( gl, maxSprites * VERTICES_PER_SPRITE, maxSprites * INDICES_PER_SPRITE, false, true, false ); // Create Rendering Vertices
|
||||||
|
this.bufferIndex = 0; // Reset Buffer Index
|
||||||
|
this.maxSprites = maxSprites; // Save Maximum Sprites
|
||||||
|
this.numSprites = 0; // Clear Sprite Counter
|
||||||
|
|
||||||
|
short[] indices = new short[maxSprites * INDICES_PER_SPRITE]; // Create Temp Index Buffer
|
||||||
|
int len = indices.length; // Get Index Buffer Length
|
||||||
|
short j = 0; // Counter
|
||||||
|
for ( int i = 0; i < len; i+= INDICES_PER_SPRITE, j += VERTICES_PER_SPRITE ) { // FOR Each Index Set (Per Sprite)
|
||||||
|
indices[i + 0] = (short)( j + 0 ); // Calculate Index 0
|
||||||
|
indices[i + 1] = (short)( j + 1 ); // Calculate Index 1
|
||||||
|
indices[i + 2] = (short)( j + 2 ); // Calculate Index 2
|
||||||
|
indices[i + 3] = (short)( j + 2 ); // Calculate Index 3
|
||||||
|
indices[i + 4] = (short)( j + 3 ); // Calculate Index 4
|
||||||
|
indices[i + 5] = (short)( j + 0 ); // Calculate Index 5
|
||||||
|
}
|
||||||
|
vertices.setIndices( indices, 0, len ); // Set Index Buffer for Rendering
|
||||||
|
}
|
||||||
|
|
||||||
|
//--Begin Batch--//
|
||||||
|
// D: signal the start of a batch. set the texture and clear buffer
|
||||||
|
// NOTE: the overloaded (non-texture) version assumes that the texture is already bound!
|
||||||
|
// A: textureId - the ID of the texture to use for the batch
|
||||||
|
// R: [none]
|
||||||
|
public void beginBatch(int textureId) {
|
||||||
|
gl.glBindTexture( GL10.GL_TEXTURE_2D, textureId ); // Bind the Texture
|
||||||
|
numSprites = 0; // Empty Sprite Counter
|
||||||
|
bufferIndex = 0; // Reset Buffer Index (Empty)
|
||||||
|
}
|
||||||
|
public void beginBatch() {
|
||||||
|
numSprites = 0; // Empty Sprite Counter
|
||||||
|
bufferIndex = 0; // Reset Buffer Index (Empty)
|
||||||
|
}
|
||||||
|
|
||||||
|
//--End Batch--//
|
||||||
|
// D: signal the end of a batch. render the batched sprites
|
||||||
|
// A: [none]
|
||||||
|
// R: [none]
|
||||||
|
public void endBatch() {
|
||||||
|
if ( numSprites > 0 ) { // IF Any Sprites to Render
|
||||||
|
vertices.setVertices( vertexBuffer, 0, bufferIndex ); // Set Vertices from Buffer
|
||||||
|
vertices.bind(); // Bind Vertices
|
||||||
|
vertices.draw( GL10.GL_TRIANGLES, 0, numSprites * INDICES_PER_SPRITE ); // Render Batched Sprites
|
||||||
|
vertices.unbind(); // Unbind Vertices
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--Draw Sprite to Batch--//
|
||||||
|
// D: batch specified sprite to batch. adds vertices for sprite to vertex buffer
|
||||||
|
// NOTE: MUST be called after beginBatch(), and before endBatch()!
|
||||||
|
// NOTE: if the batch overflows, this will render the current batch, restart it,
|
||||||
|
// and then batch this sprite.
|
||||||
|
// A: x, y - the x,y position of the sprite (center)
|
||||||
|
// width, height - the width and height of the sprite
|
||||||
|
// region - the texture region to use for sprite
|
||||||
|
// R: [none]
|
||||||
|
public void drawSprite(float x, float y, float width, float height, TextureRegion region) {
|
||||||
|
if ( numSprites == maxSprites ) { // IF Sprite Buffer is Full
|
||||||
|
endBatch(); // End Batch
|
||||||
|
// NOTE: leave current texture bound!!
|
||||||
|
numSprites = 0; // Empty Sprite Counter
|
||||||
|
bufferIndex = 0; // Reset Buffer Index (Empty)
|
||||||
|
}
|
||||||
|
|
||||||
|
float halfWidth = width / 2.0f; // Calculate Half Width
|
||||||
|
float halfHeight = height / 2.0f; // Calculate Half Height
|
||||||
|
float x1 = x - halfWidth; // Calculate Left X
|
||||||
|
float y1 = y - halfHeight; // Calculate Bottom Y
|
||||||
|
float x2 = x + halfWidth; // Calculate Right X
|
||||||
|
float y2 = y + halfHeight; // Calculate Top Y
|
||||||
|
|
||||||
|
vertexBuffer[bufferIndex++] = x1; // Add X for Vertex 0
|
||||||
|
vertexBuffer[bufferIndex++] = y1; // Add Y for Vertex 0
|
||||||
|
vertexBuffer[bufferIndex++] = region.u1; // Add U for Vertex 0
|
||||||
|
vertexBuffer[bufferIndex++] = region.v2; // Add V for Vertex 0
|
||||||
|
|
||||||
|
vertexBuffer[bufferIndex++] = x2; // Add X for Vertex 1
|
||||||
|
vertexBuffer[bufferIndex++] = y1; // Add Y for Vertex 1
|
||||||
|
vertexBuffer[bufferIndex++] = region.u2; // Add U for Vertex 1
|
||||||
|
vertexBuffer[bufferIndex++] = region.v2; // Add V for Vertex 1
|
||||||
|
|
||||||
|
vertexBuffer[bufferIndex++] = x2; // Add X for Vertex 2
|
||||||
|
vertexBuffer[bufferIndex++] = y2; // Add Y for Vertex 2
|
||||||
|
vertexBuffer[bufferIndex++] = region.u2; // Add U for Vertex 2
|
||||||
|
vertexBuffer[bufferIndex++] = region.v1; // Add V for Vertex 2
|
||||||
|
|
||||||
|
vertexBuffer[bufferIndex++] = x1; // Add X for Vertex 3
|
||||||
|
vertexBuffer[bufferIndex++] = y2; // Add Y for Vertex 3
|
||||||
|
vertexBuffer[bufferIndex++] = region.u1; // Add U for Vertex 3
|
||||||
|
vertexBuffer[bufferIndex++] = region.v1; // Add V for Vertex 3
|
||||||
|
|
||||||
|
numSprites++; // Increment Sprite Count
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,89 @@
|
|||||||
|
// This is based on the OpenGL ES 1.0 sample application from the Android Developer website:
|
||||||
|
// http://developer.android.com/resources/tutorials/opengl/opengl-es10.html
|
||||||
|
|
||||||
|
package org.solovyev.android.calculator.plot;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.opengl.GLSurfaceView;
|
||||||
|
|
||||||
|
import javax.microedition.khronos.egl.EGLConfig;
|
||||||
|
import javax.microedition.khronos.opengles.GL10;
|
||||||
|
|
||||||
|
public class TexampleRenderer implements GLSurfaceView.Renderer {
|
||||||
|
|
||||||
|
private GLText glText; // A GLText Instance
|
||||||
|
private Context context; // Context (from Activity)
|
||||||
|
|
||||||
|
private int width = 100; // Updated to the Current Width + Height in onSurfaceChanged()
|
||||||
|
private int height = 100;
|
||||||
|
|
||||||
|
public TexampleRenderer(Context context) {
|
||||||
|
super();
|
||||||
|
this.context = context; // Save Specified Context
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
|
||||||
|
// Set the background frame color
|
||||||
|
gl.glClearColor( 0.5f, 0.5f, 0.5f, 1.0f );
|
||||||
|
|
||||||
|
// Create the GLText
|
||||||
|
glText = new GLText( gl, context.getAssets() );
|
||||||
|
|
||||||
|
// Load the font from file (set size + padding), creates the texture
|
||||||
|
// NOTE: after a successful call to this the font is ready for rendering!
|
||||||
|
glText.load( "Roboto-Regular.ttf", 14, 2, 2 ); // Create Font (Height: 14 Pixels / X+Y Padding 2 Pixels)
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onDrawFrame(GL10 gl) {
|
||||||
|
// Redraw background color
|
||||||
|
gl.glClear( GL10.GL_COLOR_BUFFER_BIT );
|
||||||
|
|
||||||
|
// Set to ModelView mode
|
||||||
|
gl.glMatrixMode( GL10.GL_MODELVIEW ); // Activate Model View Matrix
|
||||||
|
gl.glLoadIdentity(); // Load Identity Matrix
|
||||||
|
|
||||||
|
// enable texture + alpha blending
|
||||||
|
// NOTE: this is required for text rendering! we could incorporate it into
|
||||||
|
// the GLText class, but then it would be called multiple times (which impacts performance).
|
||||||
|
gl.glEnable( GL10.GL_TEXTURE_2D ); // Enable Texture Mapping
|
||||||
|
gl.glEnable( GL10.GL_BLEND ); // Enable Alpha Blend
|
||||||
|
gl.glBlendFunc( GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA ); // Set Alpha Blend Function
|
||||||
|
|
||||||
|
// TEST: render the entire font texture
|
||||||
|
gl.glColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); // Set Color to Use
|
||||||
|
glText.drawTexture( width, height ); // Draw the Entire Texture
|
||||||
|
|
||||||
|
// TEST: render some strings with the font
|
||||||
|
glText.begin( 1.0f, 1.0f, 1.0f, 1.0f ); // Begin Text Rendering (Set Color WHITE)
|
||||||
|
glText.draw( "Test String :)", 0, 0 ); // Draw Test String
|
||||||
|
glText.draw( "Line 1", 50, 50 ); // Draw Test String
|
||||||
|
glText.draw( "Line 2", 100, 100 ); // Draw Test String
|
||||||
|
glText.end(); // End Text Rendering
|
||||||
|
|
||||||
|
glText.begin( 0.0f, 0.0f, 1.0f, 1.0f ); // Begin Text Rendering (Set Color BLUE)
|
||||||
|
glText.draw( "More Lines...", 50, 150 ); // Draw Test String
|
||||||
|
glText.draw( "The End.", 50, 150 + glText.getCharHeight() ); // Draw Test String
|
||||||
|
glText.end(); // End Text Rendering
|
||||||
|
|
||||||
|
// disable texture + alpha
|
||||||
|
gl.glDisable( GL10.GL_BLEND ); // Disable Alpha Blend
|
||||||
|
gl.glDisable( GL10.GL_TEXTURE_2D ); // Disable Texture Mapping
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onSurfaceChanged(GL10 gl, int width, int height) {
|
||||||
|
gl.glViewport( 0, 0, width, height );
|
||||||
|
|
||||||
|
// Setup orthographic projection
|
||||||
|
gl.glMatrixMode( GL10.GL_PROJECTION ); // Activate Projection Matrix
|
||||||
|
gl.glLoadIdentity(); // Load Identity Matrix
|
||||||
|
gl.glOrthof( // Set Ortho Projection (Left,Right,Bottom,Top,Front,Back)
|
||||||
|
0, width,
|
||||||
|
0, height,
|
||||||
|
1.0f, -1.0f
|
||||||
|
);
|
||||||
|
|
||||||
|
// Save width and height
|
||||||
|
this.width = width; // Save Current Width
|
||||||
|
this.height = height; // Save Current Height
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package org.solovyev.android.calculator.plot;
|
||||||
|
|
||||||
|
class TextureRegion {
|
||||||
|
|
||||||
|
//--Members--//
|
||||||
|
public float u1, v1; // Top/Left U,V Coordinates
|
||||||
|
public float u2, v2; // Bottom/Right U,V Coordinates
|
||||||
|
|
||||||
|
//--Constructor--//
|
||||||
|
// D: calculate U,V coordinates from specified texture coordinates
|
||||||
|
// A: texWidth, texHeight - the width and height of the texture the region is for
|
||||||
|
// x, y - the top/left (x,y) of the region on the texture (in pixels)
|
||||||
|
// width, height - the width and height of the region on the texture (in pixels)
|
||||||
|
public TextureRegion(float texWidth, float texHeight, float x, float y, float width, float height) {
|
||||||
|
this.u1 = x / texWidth; // Calculate U1
|
||||||
|
this.v1 = y / texHeight; // Calculate V1
|
||||||
|
this.u2 = this.u1 + ( width / texWidth ); // Calculate U2
|
||||||
|
this.v2 = this.v1 + ( height / texHeight ); // Calculate V2
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,257 @@
|
|||||||
|
package org.solovyev.android.calculator.plot;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.nio.IntBuffer;
|
||||||
|
import java.nio.ShortBuffer;
|
||||||
|
|
||||||
|
import javax.microedition.khronos.opengles.GL10;
|
||||||
|
|
||||||
|
public class Vertices {
|
||||||
|
|
||||||
|
//--Constants--//
|
||||||
|
final static int POSITION_CNT_2D = 2; // Number of Components in Vertex Position for 2D
|
||||||
|
final static int POSITION_CNT_3D = 3; // Number of Components in Vertex Position for 3D
|
||||||
|
final static int COLOR_CNT = 4; // Number of Components in Vertex Color
|
||||||
|
final static int TEXCOORD_CNT = 2; // Number of Components in Vertex Texture Coords
|
||||||
|
final static int NORMAL_CNT = 3; // Number of Components in Vertex Normal
|
||||||
|
|
||||||
|
final static int INDEX_SIZE = Short.SIZE / 8; // Index Byte Size (Short.SIZE = bits)
|
||||||
|
|
||||||
|
//--Members--//
|
||||||
|
// NOTE: all members are constant, and initialized in constructor!
|
||||||
|
final GL10 gl; // GL Instance
|
||||||
|
final boolean hasColor; // Use Color in Vertices
|
||||||
|
final boolean hasTexCoords; // Use Texture Coords in Vertices
|
||||||
|
final boolean hasNormals; // Use Normals in Vertices
|
||||||
|
public final int positionCnt; // Number of Position Components (2=2D, 3=3D)
|
||||||
|
public final int vertexStride; // Vertex Stride (Element Size of a Single Vertex)
|
||||||
|
public final int vertexSize; // Bytesize of a Single Vertex
|
||||||
|
final IntBuffer vertices; // Vertex Buffer
|
||||||
|
final ShortBuffer indices; // Index Buffer
|
||||||
|
public int numVertices; // Number of Vertices in Buffer
|
||||||
|
public int numIndices; // Number of Indices in Buffer
|
||||||
|
final int[] tmpBuffer; // Temp Buffer for Vertex Conversion
|
||||||
|
|
||||||
|
//--Constructor--//
|
||||||
|
// D: create the vertices/indices as specified (for 2d/3d)
|
||||||
|
// A: gl - the gl instance to use
|
||||||
|
// maxVertices - maximum vertices allowed in buffer
|
||||||
|
// maxIndices - maximum indices allowed in buffer
|
||||||
|
// hasColor - use color values in vertices
|
||||||
|
// hasTexCoords - use texture coordinates in vertices
|
||||||
|
// hasNormals - use normals in vertices
|
||||||
|
// use3D - (false, default) use 2d positions (ie. x/y only)
|
||||||
|
// (true) use 3d positions (ie. x/y/z)
|
||||||
|
public Vertices(GL10 gl, int maxVertices, int maxIndices, boolean hasColor, boolean hasTexCoords, boolean hasNormals) {
|
||||||
|
this( gl, maxVertices, maxIndices, hasColor, hasTexCoords, hasNormals, false ); // Call Overloaded Constructor
|
||||||
|
}
|
||||||
|
public Vertices(GL10 gl, int maxVertices, int maxIndices, boolean hasColor, boolean hasTexCoords, boolean hasNormals, boolean use3D) {
|
||||||
|
this.gl = gl; // Save GL Instance
|
||||||
|
this.hasColor = hasColor; // Save Color Flag
|
||||||
|
this.hasTexCoords = hasTexCoords; // Save Texture Coords Flag
|
||||||
|
this.hasNormals = hasNormals; // Save Normals Flag
|
||||||
|
this.positionCnt = use3D ? POSITION_CNT_3D : POSITION_CNT_2D; // Set Position Component Count
|
||||||
|
this.vertexStride = this.positionCnt + ( hasColor ? COLOR_CNT : 0 ) + ( hasTexCoords ? TEXCOORD_CNT : 0 ) + ( hasNormals ? NORMAL_CNT : 0 ); // Calculate Vertex Stride
|
||||||
|
this.vertexSize = this.vertexStride * 4; // Calculate Vertex Byte Size
|
||||||
|
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocateDirect( maxVertices * vertexSize ); // Allocate Buffer for Vertices (Max)
|
||||||
|
buffer.order( ByteOrder.nativeOrder() ); // Set Native Byte Order
|
||||||
|
this.vertices = buffer.asIntBuffer(); // Save Vertex Buffer
|
||||||
|
|
||||||
|
if ( maxIndices > 0 ) { // IF Indices Required
|
||||||
|
buffer = ByteBuffer.allocateDirect( maxIndices * INDEX_SIZE ); // Allocate Buffer for Indices (MAX)
|
||||||
|
buffer.order( ByteOrder.nativeOrder() ); // Set Native Byte Order
|
||||||
|
this.indices = buffer.asShortBuffer(); // Save Index Buffer
|
||||||
|
}
|
||||||
|
else // ELSE Indices Not Required
|
||||||
|
indices = null; // No Index Buffer
|
||||||
|
|
||||||
|
numVertices = 0; // Zero Vertices in Buffer
|
||||||
|
numIndices = 0; // Zero Indices in Buffer
|
||||||
|
|
||||||
|
this.tmpBuffer = new int[maxVertices * vertexSize / 4]; // Create Temp Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
//--Set Vertices--//
|
||||||
|
// D: set the specified vertices in the vertex buffer
|
||||||
|
// NOTE: optimized to use integer buffer!
|
||||||
|
// A: vertices - array of vertices (floats) to set
|
||||||
|
// offset - offset to first vertex in array
|
||||||
|
// length - number of floats in the vertex array (total)
|
||||||
|
// for easy setting use: vtx_cnt * (this.vertexSize / 4)
|
||||||
|
// R: [none]
|
||||||
|
public void setVertices(float[] vertices, int offset, int length) {
|
||||||
|
this.vertices.clear(); // Remove Existing Vertices
|
||||||
|
int last = offset + length; // Calculate Last Element
|
||||||
|
for ( int i = offset, j = 0; i < last; i++, j++ ) // FOR Each Specified Vertex
|
||||||
|
tmpBuffer[j] = Float.floatToRawIntBits( vertices[i] ); // Set Vertex as Raw Integer Bits in Buffer
|
||||||
|
this.vertices.put( tmpBuffer, 0, length ); // Set New Vertices
|
||||||
|
this.vertices.flip(); // Flip Vertex Buffer
|
||||||
|
this.numVertices = length / this.vertexStride; // Save Number of Vertices
|
||||||
|
//this.numVertices = length / ( this.vertexSize / 4 ); // Save Number of Vertices
|
||||||
|
}
|
||||||
|
|
||||||
|
//--Set Indices--//
|
||||||
|
// D: set the specified indices in the index buffer
|
||||||
|
// A: indices - array of indices (shorts) to set
|
||||||
|
// offset - offset to first index in array
|
||||||
|
// length - number of indices in array (from offset)
|
||||||
|
// R: [none]
|
||||||
|
public void setIndices(short[] indices, int offset, int length) {
|
||||||
|
this.indices.clear(); // Clear Existing Indices
|
||||||
|
this.indices.put( indices, offset, length ); // Set New Indices
|
||||||
|
this.indices.flip(); // Flip Index Buffer
|
||||||
|
this.numIndices = length; // Save Number of Indices
|
||||||
|
}
|
||||||
|
|
||||||
|
//--Bind--//
|
||||||
|
// D: perform all required binding/state changes before rendering batches.
|
||||||
|
// USAGE: call once before calling draw() multiple times for this buffer.
|
||||||
|
// A: [none]
|
||||||
|
// R: [none]
|
||||||
|
public void bind() {
|
||||||
|
gl.glEnableClientState( GL10.GL_VERTEX_ARRAY ); // Enable Position in Vertices
|
||||||
|
vertices.position( 0 ); // Set Vertex Buffer to Position
|
||||||
|
gl.glVertexPointer( positionCnt, GL10.GL_FLOAT, vertexSize, vertices ); // Set Vertex Pointer
|
||||||
|
|
||||||
|
if ( hasColor ) { // IF Vertices Have Color
|
||||||
|
gl.glEnableClientState( GL10.GL_COLOR_ARRAY ); // Enable Color in Vertices
|
||||||
|
vertices.position( positionCnt ); // Set Vertex Buffer to Color
|
||||||
|
gl.glColorPointer( COLOR_CNT, GL10.GL_FLOAT, vertexSize, vertices ); // Set Color Pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( hasTexCoords ) { // IF Vertices Have Texture Coords
|
||||||
|
gl.glEnableClientState( GL10.GL_TEXTURE_COORD_ARRAY ); // Enable Texture Coords in Vertices
|
||||||
|
vertices.position( positionCnt + ( hasColor ? COLOR_CNT : 0 ) ); // Set Vertex Buffer to Texture Coords (NOTE: position based on whether color is also specified)
|
||||||
|
gl.glTexCoordPointer( TEXCOORD_CNT, GL10.GL_FLOAT, vertexSize, vertices ); // Set Texture Coords Pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( hasNormals ) {
|
||||||
|
gl.glEnableClientState( GL10.GL_NORMAL_ARRAY ); // Enable Normals in Vertices
|
||||||
|
vertices.position( positionCnt + ( hasColor ? COLOR_CNT : 0 ) + ( hasTexCoords ? TEXCOORD_CNT : 0 ) ); // Set Vertex Buffer to Normals (NOTE: position based on whether color/texcoords is also specified)
|
||||||
|
gl.glNormalPointer( GL10.GL_FLOAT, vertexSize, vertices ); // Set Normals Pointer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--Draw--//
|
||||||
|
// D: draw the currently bound vertices in the vertex/index buffers
|
||||||
|
// USAGE: can only be called after calling bind() for this buffer.
|
||||||
|
// A: primitiveType - the type of primitive to draw
|
||||||
|
// offset - the offset in the vertex/index buffer to start at
|
||||||
|
// numVertices - the number of vertices (indices) to draw
|
||||||
|
// R: [none]
|
||||||
|
public void draw(int primitiveType, int offset, int numVertices) {
|
||||||
|
if ( indices != null ) { // IF Indices Exist
|
||||||
|
indices.position( offset ); // Set Index Buffer to Specified Offset
|
||||||
|
gl.glDrawElements( primitiveType, numVertices, GL10.GL_UNSIGNED_SHORT, indices ); // Draw Indexed
|
||||||
|
}
|
||||||
|
else { // ELSE No Indices Exist
|
||||||
|
gl.glDrawArrays( primitiveType, offset, numVertices ); // Draw Direct (Array)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--Unbind--//
|
||||||
|
// D: clear binding states when done rendering batches.
|
||||||
|
// USAGE: call once before calling draw() multiple times for this buffer.
|
||||||
|
// A: [none]
|
||||||
|
// R: [none]
|
||||||
|
public void unbind() {
|
||||||
|
if ( hasColor ) // IF Vertices Have Color
|
||||||
|
gl.glDisableClientState( GL10.GL_COLOR_ARRAY ); // Clear Color State
|
||||||
|
|
||||||
|
if ( hasTexCoords ) // IF Vertices Have Texture Coords
|
||||||
|
gl.glDisableClientState( GL10.GL_TEXTURE_COORD_ARRAY ); // Clear Texture Coords State
|
||||||
|
|
||||||
|
if ( hasNormals ) // IF Vertices Have Normals
|
||||||
|
gl.glDisableClientState( GL10.GL_NORMAL_ARRAY ); // Clear Normals State
|
||||||
|
}
|
||||||
|
|
||||||
|
//--Draw Full--//
|
||||||
|
// D: draw the vertices in the vertex/index buffers
|
||||||
|
// NOTE: unoptimized version! use bind()/draw()/unbind() for batches
|
||||||
|
// A: primitiveType - the type of primitive to draw
|
||||||
|
// offset - the offset in the vertex/index buffer to start at
|
||||||
|
// numVertices - the number of vertices (indices) to draw
|
||||||
|
// R: [none]
|
||||||
|
public void drawFull(int primitiveType, int offset, int numVertices) {
|
||||||
|
gl.glEnableClientState( GL10.GL_VERTEX_ARRAY ); // Enable Position in Vertices
|
||||||
|
vertices.position( 0 ); // Set Vertex Buffer to Position
|
||||||
|
gl.glVertexPointer( positionCnt, GL10.GL_FLOAT, vertexSize, vertices ); // Set Vertex Pointer
|
||||||
|
|
||||||
|
if ( hasColor ) { // IF Vertices Have Color
|
||||||
|
gl.glEnableClientState( GL10.GL_COLOR_ARRAY ); // Enable Color in Vertices
|
||||||
|
vertices.position( positionCnt ); // Set Vertex Buffer to Color
|
||||||
|
gl.glColorPointer( COLOR_CNT, GL10.GL_FLOAT, vertexSize, vertices ); // Set Color Pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( hasTexCoords ) { // IF Vertices Have Texture Coords
|
||||||
|
gl.glEnableClientState( GL10.GL_TEXTURE_COORD_ARRAY ); // Enable Texture Coords in Vertices
|
||||||
|
vertices.position( positionCnt + ( hasColor ? COLOR_CNT : 0 ) ); // Set Vertex Buffer to Texture Coords (NOTE: position based on whether color is also specified)
|
||||||
|
gl.glTexCoordPointer( TEXCOORD_CNT, GL10.GL_FLOAT, vertexSize, vertices ); // Set Texture Coords Pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( indices != null ) { // IF Indices Exist
|
||||||
|
indices.position( offset ); // Set Index Buffer to Specified Offset
|
||||||
|
gl.glDrawElements( primitiveType, numVertices, GL10.GL_UNSIGNED_SHORT, indices ); // Draw Indexed
|
||||||
|
}
|
||||||
|
else { // ELSE No Indices Exist
|
||||||
|
gl.glDrawArrays( primitiveType, offset, numVertices ); // Draw Direct (Array)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( hasTexCoords ) // IF Vertices Have Texture Coords
|
||||||
|
gl.glDisableClientState( GL10.GL_TEXTURE_COORD_ARRAY ); // Clear Texture Coords State
|
||||||
|
|
||||||
|
if ( hasColor ) // IF Vertices Have Color
|
||||||
|
gl.glDisableClientState( GL10.GL_COLOR_ARRAY ); // Clear Color State
|
||||||
|
}
|
||||||
|
|
||||||
|
//--Set Vertex Elements--//
|
||||||
|
// D: use these methods to alter the values (position, color, textcoords, normals) for vertices
|
||||||
|
// WARNING: these do NOT validate any values, ensure that the index AND specified
|
||||||
|
// elements EXIST before using!!
|
||||||
|
// A: x, y, z - the x,y,z position to set in buffer
|
||||||
|
// r, g, b, a - the r,g,b,a color to set in buffer
|
||||||
|
// u, v - the u,v texture coords to set in buffer
|
||||||
|
// nx, ny, nz - the x,y,z normal to set in buffer
|
||||||
|
// R: [none]
|
||||||
|
void setVtxPosition(int vtxIdx, float x, float y) {
|
||||||
|
int index = vtxIdx * vertexStride; // Calculate Actual Index
|
||||||
|
vertices.put( index + 0, Float.floatToRawIntBits( x ) ); // Set X
|
||||||
|
vertices.put( index + 1, Float.floatToRawIntBits( y ) ); // Set Y
|
||||||
|
}
|
||||||
|
void setVtxPosition(int vtxIdx, float x, float y, float z) {
|
||||||
|
int index = vtxIdx * vertexStride; // Calculate Actual Index
|
||||||
|
vertices.put( index + 0, Float.floatToRawIntBits( x ) ); // Set X
|
||||||
|
vertices.put( index + 1, Float.floatToRawIntBits( y ) ); // Set Y
|
||||||
|
vertices.put( index + 2, Float.floatToRawIntBits( z ) ); // Set Z
|
||||||
|
}
|
||||||
|
void setVtxColor(int vtxIdx, float r, float g, float b, float a) {
|
||||||
|
int index = ( vtxIdx * vertexStride ) + positionCnt; // Calculate Actual Index
|
||||||
|
vertices.put( index + 0, Float.floatToRawIntBits( r ) ); // Set Red
|
||||||
|
vertices.put( index + 1, Float.floatToRawIntBits( g ) ); // Set Green
|
||||||
|
vertices.put( index + 2, Float.floatToRawIntBits( b ) ); // Set Blue
|
||||||
|
vertices.put( index + 3, Float.floatToRawIntBits( a ) ); // Set Alpha
|
||||||
|
}
|
||||||
|
void setVtxColor(int vtxIdx, float r, float g, float b) {
|
||||||
|
int index = ( vtxIdx * vertexStride ) + positionCnt; // Calculate Actual Index
|
||||||
|
vertices.put( index + 0, Float.floatToRawIntBits( r ) ); // Set Red
|
||||||
|
vertices.put( index + 1, Float.floatToRawIntBits( g ) ); // Set Green
|
||||||
|
vertices.put( index + 2, Float.floatToRawIntBits( b ) ); // Set Blue
|
||||||
|
}
|
||||||
|
void setVtxColor(int vtxIdx, float a) {
|
||||||
|
int index = ( vtxIdx * vertexStride ) + positionCnt; // Calculate Actual Index
|
||||||
|
vertices.put( index + 3, Float.floatToRawIntBits( a ) ); // Set Alpha
|
||||||
|
}
|
||||||
|
void setVtxTexCoords(int vtxIdx, float u, float v) {
|
||||||
|
int index = ( vtxIdx * vertexStride ) + positionCnt + ( hasColor ? COLOR_CNT : 0 ); // Calculate Actual Index
|
||||||
|
vertices.put( index + 0, Float.floatToRawIntBits( u ) ); // Set U
|
||||||
|
vertices.put( index + 1, Float.floatToRawIntBits( v ) ); // Set V
|
||||||
|
}
|
||||||
|
void setVtxNormal(int vtxIdx, float x, float y, float z) {
|
||||||
|
int index = ( vtxIdx * vertexStride ) + positionCnt + ( hasColor ? COLOR_CNT : 0 ) + ( hasTexCoords ? TEXCOORD_CNT : 0 ); // Calculate Actual Index
|
||||||
|
vertices.put( index + 0, Float.floatToRawIntBits( x ) ); // Set X
|
||||||
|
vertices.put( index + 1, Float.floatToRawIntBits( y ) ); // Set Y
|
||||||
|
vertices.put( index + 2, Float.floatToRawIntBits( z ) ); // Set Z
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user