summaryrefslogtreecommitdiffstats
path: root/libs/rs
diff options
context:
space:
mode:
authorAlex Sakhartchouk <alexst@google.com>2010-06-24 17:15:34 -0700
committerAlex Sakhartchouk <alexst@google.com>2010-06-24 17:15:34 -0700
commit9b949fce39f0f39ce9275b71d7c347210775e7a8 (patch)
tree76b739126b5b3f10e8fd0bc63071dd22a105e227 /libs/rs
parent8f31bd6b68c796d4a4176721a6e13bfdba2166e0 (diff)
downloadframeworks_base-9b949fce39f0f39ce9275b71d7c347210775e7a8.zip
frameworks_base-9b949fce39f0f39ce9275b71d7c347210775e7a8.tar.gz
frameworks_base-9b949fce39f0f39ce9275b71d7c347210775e7a8.tar.bz2
Adding freetype font rendering to renderscript.
Change-Id: I3a10ffe27092a41df156341c9cb3f7aa19c49f19
Diffstat (limited to 'libs/rs')
-rw-r--r--libs/rs/Android.mk16
-rw-r--r--libs/rs/RenderScript.h1
-rw-r--r--libs/rs/ScriptC_Modelviewer.java118
-rw-r--r--libs/rs/java/ModelViewer/res/raw/modelviewer.rs17
-rw-r--r--libs/rs/java/ModelViewer/res/raw/modelviewer_bc.bcbin1688 -> 6220 bytes
-rw-r--r--libs/rs/java/ModelViewer/src/com/android/modelviewer/ModelViewerRS.java16
-rw-r--r--libs/rs/java/ModelViewer/src/com/android/modelviewer/ModelViewerView.java1
-rw-r--r--libs/rs/java/ModelViewer/src/com/android/modelviewer/ScriptC_Modelviewer.java22
-rw-r--r--libs/rs/rs.spec11
-rw-r--r--libs/rs/rsContext.cpp23
-rw-r--r--libs/rs/rsContext.h9
-rw-r--r--libs/rs/rsFileA3D.cpp1
-rw-r--r--libs/rs/rsFont.cpp689
-rw-r--r--libs/rs/rsFont.h209
-rw-r--r--libs/rs/rsScriptC_LibGL.cpp23
-rw-r--r--libs/rs/rsType.cpp4
-rw-r--r--libs/rs/scriptc/rs_graphics.rsh4
-rw-r--r--libs/rs/scriptc/rs_types.rsh1
18 files changed, 1155 insertions, 10 deletions
diff --git a/libs/rs/Android.mk b/libs/rs/Android.mk
index 3f01415..7afc4f2 100644
--- a/libs/rs/Android.mk
+++ b/libs/rs/Android.mk
@@ -81,13 +81,14 @@ LOCAL_SRC_FILES:= \
rsContext.cpp \
rsDevice.cpp \
rsElement.cpp \
- rsFileA3D.cpp \
+ rsFileA3D.cpp \
+ rsFont.cpp \
rsLight.cpp \
rsLocklessFifo.cpp \
rsObjectBase.cpp \
rsMatrix.cpp \
- rsMesh.cpp \
- rsMutex.cpp \
+ rsMesh.cpp \
+ rsMutex.cpp \
rsProgram.cpp \
rsProgramFragment.cpp \
rsProgramStore.cpp \
@@ -99,16 +100,21 @@ LOCAL_SRC_FILES:= \
rsScriptC_Lib.cpp \
rsScriptC_LibCL.cpp \
rsScriptC_LibGL.cpp \
- rsShaderCache.cpp \
+ rsShaderCache.cpp \
rsSignal.cpp \
rsSimpleMesh.cpp \
- rsStream.cpp \
+ rsStream.cpp \
rsThreadIO.cpp \
rsType.cpp \
rsVertexArray.cpp
LOCAL_SHARED_LIBRARIES += libcutils libutils libEGL libGLESv1_CM libGLESv2 libui libbcc
+
+LOCAL_STATIC_LIBRARIES := libft2
+
+LOCAL_C_INCLUDES += external/freetype/include
+
LOCAL_LDLIBS := -lpthread -ldl
LOCAL_MODULE:= libRS
LOCAL_MODULE_TAGS := optional
diff --git a/libs/rs/RenderScript.h b/libs/rs/RenderScript.h
index 6302b90..1428318 100644
--- a/libs/rs/RenderScript.h
+++ b/libs/rs/RenderScript.h
@@ -35,6 +35,7 @@ typedef void * RsContext;
typedef void * RsDevice;
typedef void * RsElement;
typedef void * RsFile;
+typedef void * RsFont;
typedef void * RsSampler;
typedef void * RsScript;
typedef void * RsSimpleMesh;
diff --git a/libs/rs/ScriptC_Modelviewer.java b/libs/rs/ScriptC_Modelviewer.java
new file mode 100644
index 0000000..083fb60
--- /dev/null
+++ b/libs/rs/ScriptC_Modelviewer.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.modelviewer;
+
+import android.renderscript.*;
+import android.content.res.Resources;
+import android.util.Log;
+
+public class ScriptC_Modelviewer extends ScriptC {
+ // Constructor
+ public ScriptC_Modelviewer(RenderScript rs, Resources resources, int id, boolean isRoot) {
+ super(rs, resources, id, isRoot);
+ }
+
+ private final static int mExportVarIdx_gPVBackground = 0;
+ private ProgramVertex mExportVar_gPVBackground;
+ public void set_gPVBackground(ProgramVertex v) {
+ mExportVar_gPVBackground = v;
+ setVar(mExportVarIdx_gPVBackground, (v == null) ? 0 : v.getID());
+ }
+
+ public ProgramVertex get_gPVBackground() {
+ return mExportVar_gPVBackground;
+ }
+
+ private final static int mExportVarIdx_gPFBackground = 1;
+ private ProgramFragment mExportVar_gPFBackground;
+ public void set_gPFBackground(ProgramFragment v) {
+ mExportVar_gPFBackground = v;
+ setVar(mExportVarIdx_gPFBackground, (v == null) ? 0 : v.getID());
+ }
+
+ public ProgramFragment get_gPFBackground() {
+ return mExportVar_gPFBackground;
+ }
+
+ private final static int mExportVarIdx_gTGrid = 2;
+ private Allocation mExportVar_gTGrid;
+ public void set_gTGrid(Allocation v) {
+ mExportVar_gTGrid = v;
+ setVar(mExportVarIdx_gTGrid, (v == null) ? 0 : v.getID());
+ }
+
+ public Allocation get_gTGrid() {
+ return mExportVar_gTGrid;
+ }
+
+ private final static int mExportVarIdx_gTestMesh = 3;
+ private SimpleMesh mExportVar_gTestMesh;
+ public void set_gTestMesh(SimpleMesh v) {
+ mExportVar_gTestMesh = v;
+ setVar(mExportVarIdx_gTestMesh, (v == null) ? 0 : v.getID());
+ }
+
+ public SimpleMesh get_gTestMesh() {
+ return mExportVar_gTestMesh;
+ }
+
+ private final static int mExportVarIdx_gPFSBackground = 4;
+ private ProgramStore mExportVar_gPFSBackground;
+ public void set_gPFSBackground(ProgramStore v) {
+ mExportVar_gPFSBackground = v;
+ setVar(mExportVarIdx_gPFSBackground, (v == null) ? 0 : v.getID());
+ }
+
+ public ProgramStore get_gPFSBackground() {
+ return mExportVar_gPFSBackground;
+ }
+
+ private final static int mExportVarIdx_gRotate = 5;
+ private float mExportVar_gRotate;
+ public void set_gRotate(float v) {
+ mExportVar_gRotate = v;
+ setVar(mExportVarIdx_gRotate, v);
+ }
+
+ public float get_gRotate() {
+ return mExportVar_gRotate;
+ }
+
+ private final static int mExportVarIdx_gItalic = 6;
+ private Font mExportVar_gItalic;
+ public void set_gItalic(Font v) {
+ mExportVar_gItalic = v;
+ setVar(mExportVarIdx_gItalic, v);
+ }
+
+ public Font get_gItalic() {
+ return mExportVar_gItalic;
+ }
+
+ private final static int mExportVarIdx_gTextAlloc = 7;
+ private Allocation mExportVar_gTextAlloc;
+ public void set_gTextAlloc(Allocation v) {
+ mExportVar_gTextAlloc = v;
+ setVar(mExportVarIdx_gTextAlloc, (v == null) ? 0 : v.getID());
+ }
+
+ public Allocation get_gTextAlloc() {
+ return mExportVar_gTextAlloc;
+ }
+
+}
+
diff --git a/libs/rs/java/ModelViewer/res/raw/modelviewer.rs b/libs/rs/java/ModelViewer/res/raw/modelviewer.rs
index 6a98f90..91194e8 100644
--- a/libs/rs/java/ModelViewer/res/raw/modelviewer.rs
+++ b/libs/rs/java/ModelViewer/res/raw/modelviewer.rs
@@ -14,6 +14,8 @@
#pragma version(1)
+#pragma rs java_package_name(com.android.modelviewer)
+
#include "../../../../scriptc/rs_types.rsh"
#include "../../../../scriptc/rs_math.rsh"
#include "../../../../scriptc/rs_graphics.rsh"
@@ -28,7 +30,13 @@ rs_program_store gPFSBackground;
float gRotate;
-#pragma rs export_var(gPVBackground, gPFBackground, gTGrid, gTestMesh, gPFSBackground, gRotate)
+rs_font gItalic;
+rs_allocation gTextAlloc;
+
+#pragma rs export_var(gPVBackground, gPFBackground, gTGrid, gTestMesh, gPFSBackground, gRotate, gItalic, gTextAlloc)
+
+float gDT;
+int64_t gLastTime;
void init() {
gRotate = 0.0f;
@@ -50,10 +58,17 @@ int root(int launchID) {
// Position our model on the screen
rsMatrixTranslate(&matrix, 0.0f, -0.3f, 1.2f);
rsMatrixScale(&matrix, 0.2f, 0.2f, 0.2f);
+ rsMatrixRotate(&matrix, -25.0f, 1.0f, 0.0f, 0.0f);
rsMatrixRotate(&matrix, gRotate, 0.0f, 1.0f, 0.0f);
rsgProgramVertexLoadModelMatrix(&matrix);
rsgDrawSimpleMesh(gTestMesh);
+ color(0.3f, 0.3f, 0.3f, 1.0f);
+ rsgDrawText("Renderscript model test", 30, 695);
+
+ rsgBindFont(gItalic);
+ rsgDrawText(gTextAlloc, 30, 730);
+
return 10;
}
diff --git a/libs/rs/java/ModelViewer/res/raw/modelviewer_bc.bc b/libs/rs/java/ModelViewer/res/raw/modelviewer_bc.bc
index 367a3f4..a64e725 100644
--- a/libs/rs/java/ModelViewer/res/raw/modelviewer_bc.bc
+++ b/libs/rs/java/ModelViewer/res/raw/modelviewer_bc.bc
Binary files differ
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/ModelViewerRS.java b/libs/rs/java/ModelViewer/src/com/android/modelviewer/ModelViewerRS.java
index e581520..b6485dc 100644
--- a/libs/rs/java/ModelViewer/src/com/android/modelviewer/ModelViewerRS.java
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/ModelViewerRS.java
@@ -57,6 +57,9 @@ public class ModelViewerRS {
private SimpleMesh mMesh;
+ private Font mItalic;
+ private Allocation mTextAlloc;
+
private ScriptC_Modelviewer mScript;
int mLastX;
@@ -123,11 +126,17 @@ public class ModelViewerRS {
private void loadImage() {
mGridImage = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.robot, Element.RGB_565(mRS), true);
- mGridImage.uploadToTexture(1);
+ mGridImage.uploadToTexture(0);
mScript.set_gTGrid(mGridImage);
}
+ private void initTextAllocation() {
+ String allocString = "Displaying file: R.raw.robot";
+ mTextAlloc = Allocation.createFromString(mRS, allocString);
+ mScript.set_gTextAlloc(mTextAlloc);
+ }
+
private void initRS() {
mScript = new ScriptC_Modelviewer(mRS, mRes, R.raw.modelviewer_bc, true);
@@ -148,6 +157,11 @@ public class ModelViewerRS {
mScript.set_gTestMesh(mMesh);
}
+ mItalic = Font.create(mRS, mRes, "DroidSerif-Italic.ttf", 10);
+ mScript.set_gItalic(mItalic);
+
+ initTextAllocation();
+
mRS.contextBindRootScript(mScript);
}
}
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/ModelViewerView.java b/libs/rs/java/ModelViewer/src/com/android/modelviewer/ModelViewerView.java
index ce76e1a..061cf8e 100644
--- a/libs/rs/java/ModelViewer/src/com/android/modelviewer/ModelViewerView.java
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/ModelViewerView.java
@@ -86,7 +86,6 @@ public class ModelViewerView extends RSSurfaceView {
ret = false;
}
- Log.v("rs", "Values " + (int)ev.getX() + " " + (int)ev.getY());
mRender.touchEvent((int)ev.getX(), (int)ev.getY());
return ret;
}
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/ScriptC_Modelviewer.java b/libs/rs/java/ModelViewer/src/com/android/modelviewer/ScriptC_Modelviewer.java
index 7a965b8..d3a2a29 100644
--- a/libs/rs/java/ModelViewer/src/com/android/modelviewer/ScriptC_Modelviewer.java
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/ScriptC_Modelviewer.java
@@ -92,5 +92,27 @@ public class ScriptC_Modelviewer extends ScriptC {
return mExportVar_gRotate;
}
+ private final static int mExportVarIdx_gItalic = 6;
+ private Font mExportVar_gItalic;
+ public void set_gItalic(Font v) {
+ mExportVar_gItalic = v;
+ setVar(mExportVarIdx_gItalic, (v == null) ? 0 : v.getID());
+ }
+
+ public Font get_gItalic() {
+ return mExportVar_gItalic;
+ }
+
+ private final static int mExportVarIdx_gTextAlloc = 7;
+ private Allocation mExportVar_gTextAlloc;
+ public void set_gTextAlloc(Allocation v) {
+ mExportVar_gTextAlloc = v;
+ setVar(mExportVarIdx_gTextAlloc, (v == null) ? 0 : v.getID());
+ }
+
+ public Allocation get_gTextAlloc() {
+ return mExportVar_gTextAlloc;
+ }
+
}
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index 5f76486..0a168f4 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -23,6 +23,10 @@ ContextBindProgramRaster {
param RsProgramRaster pgm
}
+ContextBindFont {
+ param RsFont pgm
+ }
+
ContextPause {
}
@@ -467,6 +471,13 @@ FileA3DGetEntryByIndex {
ret RsObjectBase
}
+FontCreateFromFile {
+ param const char *name
+ param uint32_t fontSize
+ param uint32_t dpi
+ ret RsFont
+ }
+
SimpleMeshCreate {
ret RsSimpleMesh
param RsAllocation prim
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index b9349bd..d8c3861 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -133,6 +133,7 @@ uint32_t Context::runScript(Script *s)
ObjectBaseRef<ProgramVertex> vtx(mVertex);
ObjectBaseRef<ProgramStore> store(mFragmentStore);
ObjectBaseRef<ProgramRaster> raster(mRaster);
+ ObjectBaseRef<Font> font(mFont);
uint32_t ret = s->run(this);
@@ -140,6 +141,7 @@ uint32_t Context::runScript(Script *s)
mVertex.set(vtx);
mFragmentStore.set(store);
mRaster.set(raster);
+ mFont.set(font);
return ret;
}
@@ -290,6 +292,8 @@ void * Context::threadProc(void *vrsc)
rsc->setFragment(NULL);
rsc->mStateFragmentStore.init(rsc);
rsc->setFragmentStore(NULL);
+ rsc->mStateFont.init(rsc);
+ rsc->setFont(NULL);
rsc->mStateVertexArray.init(rsc);
}
@@ -328,11 +332,13 @@ void * Context::threadProc(void *vrsc)
rsc->mFragment.clear();
rsc->mVertex.clear();
rsc->mFragmentStore.clear();
+ rsc->mFont.clear();
rsc->mRootScript.clear();
rsc->mStateRaster.deinit(rsc);
rsc->mStateVertex.deinit(rsc);
rsc->mStateFragment.deinit(rsc);
rsc->mStateFragmentStore.deinit(rsc);
+ rsc->mStateFont.deinit(rsc);
}
ObjectBase::zeroAllUserRef(rsc);
@@ -597,6 +603,16 @@ void Context::setVertex(ProgramVertex *pv)
}
}
+void Context::setFont(Font *f)
+{
+ rsAssert(mIsGraphicsContext);
+ if (f == NULL) {
+ mFont.set(mStateFont.mDefault);
+ } else {
+ mFont.set(f);
+ }
+}
+
void Context::assignName(ObjectBase *obj, const char *name, uint32_t len)
{
rsAssert(!obj->getName());
@@ -807,6 +823,13 @@ void rsi_ContextBindProgramVertex(Context *rsc, RsProgramVertex vpv)
rsc->setVertex(pv);
}
+void rsi_ContextBindFont(Context *rsc, RsFont vfont)
+{
+ Font *font = static_cast<Font *>(vfont);
+ rsc->setFont(font);
+}
+
+
void rsi_AssignName(Context *rsc, void * obj, const char *name, uint32_t len)
{
ObjectBase *ob = static_cast<ObjectBase *>(obj);
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index 31bf5d6..1485d8a 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -32,6 +32,7 @@
#include "rsAdapter.h"
#include "rsSampler.h"
#include "rsLight.h"
+#include "rsFont.h"
#include "rsProgramFragment.h"
#include "rsProgramStore.h"
#include "rsProgramRaster.h"
@@ -76,6 +77,7 @@ public:
ProgramVertexState mStateVertex;
LightState mStateLight;
VertexArrayState mStateVertexArray;
+ FontState mStateFont;
ScriptCState mScriptC;
ShaderCache mShaderCache;
@@ -86,6 +88,7 @@ public:
void setVertex(ProgramVertex *);
void setFragment(ProgramFragment *);
void setFragmentStore(ProgramStore *);
+ void setFont(Font *);
void updateSurface(void *sur);
@@ -93,6 +96,7 @@ public:
const ProgramStore * getFragmentStore() {return mFragmentStore.get();}
const ProgramRaster * getRaster() {return mRaster.get();}
const ProgramVertex * getVertex() {return mVertex.get();}
+ Font * getFont() {return mFont.get();}
bool setupCheck();
bool checkDriver() const {return mEGL.mSurface != 0;}
@@ -124,6 +128,9 @@ public:
ProgramRaster * getDefaultProgramRaster() const {
return mStateRaster.mDefault.get();
}
+ Font* getDefaultFont() const {
+ return mStateFont.mDefault.get();
+ }
uint32_t getWidth() const {return mWidth;}
uint32_t getHeight() const {return mHeight;}
@@ -221,7 +228,7 @@ protected:
ObjectBaseRef<ProgramVertex> mVertex;
ObjectBaseRef<ProgramStore> mFragmentStore;
ObjectBaseRef<ProgramRaster> mRaster;
-
+ ObjectBaseRef<Font> mFont;
struct ObjDestroyOOB {
Mutex mMutex;
diff --git a/libs/rs/rsFileA3D.cpp b/libs/rs/rsFileA3D.cpp
index 23c0cf5..4fac421 100644
--- a/libs/rs/rsFileA3D.cpp
+++ b/libs/rs/rsFileA3D.cpp
@@ -26,6 +26,7 @@
#include "rsMesh.h"
#include "rsAnimation.h"
+
using namespace android;
using namespace android::renderscript;
diff --git a/libs/rs/rsFont.cpp b/libs/rs/rsFont.cpp
new file mode 100644
index 0000000..5740e65
--- /dev/null
+++ b/libs/rs/rsFont.cpp
@@ -0,0 +1,689 @@
+
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_RS_BUILD_FOR_HOST
+#include "rsContext.h"
+#else
+#include "rsContextHostStub.h"
+#endif
+
+#include "rsFont.h"
+#include "rsProgramFragment.h"
+#include FT_BITMAP_H
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+Font::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL)
+{
+ mInitialized = false;
+ mHasKerning = false;
+}
+
+bool Font::init(const char *name, uint32_t fontSize, uint32_t dpi)
+{
+ if(mInitialized) {
+ LOGE("Reinitialization of fonts not supported");
+ return false;
+ }
+
+ String8 fontsDir("/fonts/");
+ String8 fullPath(getenv("ANDROID_ROOT"));
+ fullPath += fontsDir;
+ fullPath += name;
+
+ FT_Error error = FT_New_Face(mRSC->mStateFont.mLibrary, fullPath.string(), 0, &mFace);
+ if(error) {
+ LOGE("Unable to initialize font %s", fullPath.string());
+ return false;
+ }
+
+ mFontName = name;
+ mFontSize = fontSize;
+ mDpi = dpi;
+
+ //LOGE("Font initialized: %s", fullPath.string());
+
+ error = FT_Set_Char_Size(mFace, fontSize * 64, 0, dpi, 0);
+ if(error) {
+ LOGE("Unable to set font size on %s", fullPath.string());
+ return false;
+ }
+
+ mHasKerning = FT_HAS_KERNING(mFace);
+ LOGE("Kerning: %i", mHasKerning);
+
+ mInitialized = true;
+ return true;
+}
+
+void Font::invalidateTextureCache()
+{
+ for(uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
+ mCachedGlyphs.valueAt(i)->mIsValid = false;
+ }
+}
+
+void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int x, int y)
+{
+ FontState *state = &mRSC->mStateFont;
+
+ int nPenX = x + glyph->mBitmapLeft;
+ int nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
+
+ state->appendMeshQuad(nPenX, nPenY, 0,
+ glyph->mBitmapMinU, glyph->mBitmapMaxV,
+
+ nPenX + (int)glyph->mBitmapWidth, nPenY, 0,
+ glyph->mBitmapMaxU, glyph->mBitmapMaxV,
+
+ nPenX + (int)glyph->mBitmapWidth, nPenY - (int)glyph->mBitmapHeight, 0,
+ glyph->mBitmapMaxU, glyph->mBitmapMinV,
+
+ nPenX, nPenY - (int)glyph->mBitmapHeight, 0,
+ glyph->mBitmapMinU, glyph->mBitmapMinV);
+}
+
+void Font::renderUTF(const char *text, uint32_t len, uint32_t start, int numGlyphs, int x, int y)
+{
+ if(!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
+ return;
+ }
+
+ int penX = x, penY = y;
+ int glyphsLeft = 1;
+ if(numGlyphs > 0) {
+ glyphsLeft = numGlyphs;
+ }
+
+ size_t index = start;
+ size_t nextIndex = 0;
+
+ while (glyphsLeft > 0) {
+
+ int32_t utfChar = utf32_at(text, len, index, &nextIndex);
+
+ // Reached the end of the string or encountered
+ if(utfChar < 0) {
+ break;
+ }
+
+ // Move to the next character in the array
+ index = nextIndex;
+
+ CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
+
+ if(cachedGlyph == NULL) {
+ cachedGlyph = cacheGlyph((uint32_t)utfChar);
+ }
+ // Is the glyph still in texture cache?
+ if(!cachedGlyph->mIsValid) {
+ updateGlyphCache(cachedGlyph);
+ }
+
+ // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
+ if(cachedGlyph->mIsValid) {
+ drawCachedGlyph(cachedGlyph, penX, penY);
+ }
+
+ penX += (cachedGlyph->mAdvance.x >> 6);
+
+ // If we were given a specific number of glyphs, decrement
+ if(numGlyphs > 0) {
+ glyphsLeft --;
+ }
+ }
+}
+
+void Font::updateGlyphCache(CachedGlyphInfo *glyph)
+{
+ if(!glyph->mBitmapValid) {
+
+ FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
+ if(error) {
+ LOGE("Couldn't load glyph.");
+ return;
+ }
+
+ glyph->mAdvance = mFace->glyph->advance;
+ glyph->mBitmapLeft = mFace->glyph->bitmap_left;
+ glyph->mBitmapTop = mFace->glyph->bitmap_top;
+
+ FT_Bitmap *bitmap = &mFace->glyph->bitmap;
+
+ FT_Bitmap_New(&glyph->mBitmap);
+ FT_Bitmap_Copy(mRSC->mStateFont.mLibrary, bitmap, &glyph->mBitmap);
+
+ glyph->mBitmapValid = true;
+ }
+
+ // Now copy the bitmap into the cache texture
+ uint32_t startX = 0;
+ uint32_t startY = 0;
+
+ // Let the font state figure out where to put the bitmap
+ FontState *state = &mRSC->mStateFont;
+ glyph->mIsValid = state->cacheBitmap(&glyph->mBitmap, &startX, &startY);
+
+ if(!glyph->mIsValid) {
+ return;
+ }
+
+ uint32_t endX = startX + glyph->mBitmap.width;
+ uint32_t endY = startY + glyph->mBitmap.rows;
+
+ glyph->mBitmapMinX = startX;
+ glyph->mBitmapMinY = startY;
+ glyph->mBitmapWidth = glyph->mBitmap.width;
+ glyph->mBitmapHeight = glyph->mBitmap.rows;
+
+ uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
+ uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
+
+ glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
+ glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
+ glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
+ glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
+}
+
+Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph)
+{
+ CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
+ mCachedGlyphs.add(glyph, newGlyph);
+
+ newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
+ newGlyph->mIsValid = false;
+ newGlyph->mBitmapValid = false;
+
+ //LOGE("Glyph = %c, face index: %u", (unsigned char)glyph, newGlyph->mGlyphIndex);
+
+ updateGlyphCache(newGlyph);
+
+ return newGlyph;
+}
+
+Font * Font::create(Context *rsc, const char *name, uint32_t fontSize, uint32_t dpi)
+{
+ Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
+
+ for(uint32_t i = 0; i < activeFonts.size(); i ++) {
+ Font *ithFont = activeFonts[i];
+ if(ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
+ ithFont->incUserRef();
+ return ithFont;
+ }
+ }
+
+ Font *newFont = new Font(rsc);
+ bool isInitialized = newFont->init(name, fontSize, dpi);
+ if(isInitialized) {
+ newFont->incUserRef();
+ activeFonts.push(newFont);
+ return newFont;
+ }
+
+ delete newFont;
+ return NULL;
+
+}
+
+Font::~Font()
+{
+ if(mFace) {
+ FT_Done_Face(mFace);
+ }
+
+ for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) {
+ if (mRSC->mStateFont.mActiveFonts[ct] == this) {
+ mRSC->mStateFont.mActiveFonts.removeAt(ct);
+ break;
+ }
+ }
+
+ for(uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
+ CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
+ if(glyph->mBitmapValid) {
+ FT_Bitmap_Done(mRSC->mStateFont.mLibrary, &glyph->mBitmap);
+ }
+ delete glyph;
+ }
+}
+
+FontState::FontState()
+{
+ mInitialized = false;
+ mMaxNumberOfQuads = 1024;
+ mCurrentQuadIndex = 0;
+ mRSC = NULL;
+}
+
+FontState::~FontState()
+{
+ for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
+ delete mCacheLines[i];
+ }
+
+ rsAssert(!mActiveFonts.size());
+}
+
+void FontState::init(Context *rsc)
+{
+ FT_Error error;
+
+ if(!mLibrary) {
+ error = FT_Init_FreeType(&mLibrary);
+ if(error) {
+ LOGE("Unable to initialize freetype");
+ return;
+ }
+ }
+
+ mRSC = rsc;
+
+ mDefault.set(Font::create(rsc, "DroidSans.ttf", 16, 96));
+}
+
+void FontState::flushAllAndInvalidate()
+{
+ if(mCurrentQuadIndex != 0) {
+ issueDrawCommand();
+ mCurrentQuadIndex = 0;
+ }
+ for(uint32_t i = 0; i < mActiveFonts.size(); i ++) {
+ mActiveFonts[i]->invalidateTextureCache();
+ }
+ for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
+ mCacheLines[i]->mCurrentCol = 0;
+ }
+}
+
+bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY)
+{
+ // If the glyph is too tall, don't cache it
+ if((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
+ LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
+ return false;
+ }
+
+ // Now copy the bitmap into the cache texture
+ uint32_t startX = 0;
+ uint32_t startY = 0;
+
+ bool bitmapFit = false;
+ for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
+ bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
+ if(bitmapFit) {
+ break;
+ }
+ }
+
+ // If the new glyph didn't fit, flush the state so far and invalidate everything
+ if(!bitmapFit) {
+ flushAllAndInvalidate();
+
+ // Try to fit it again
+ for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
+ bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
+ if(bitmapFit) {
+ break;
+ }
+ }
+
+ // if we still don't fit, something is wrong and we shouldn't draw
+ if(!bitmapFit) {
+ LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
+ return false;
+ }
+ }
+
+ *retOriginX = startX;
+ *retOriginY = startY;
+
+ uint32_t endX = startX + bitmap->width;
+ uint32_t endY = startY + bitmap->rows;
+
+ //LOGE("Bitmap width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
+
+ uint32_t cacheWidth = getCacheTextureType()->getDimX();
+
+ unsigned char *cacheBuffer = (unsigned char*)mTextTexture->getPtr();
+ unsigned char *bitmapBuffer = bitmap->buffer;
+
+ uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
+ for(cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
+ for(cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
+ unsigned char tempCol = bitmapBuffer[bY * bitmap->width + bX];
+ cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
+ }
+ }
+
+ // This will dirty the texture and the shader so next time
+ // we draw it will upload the data
+ mTextTexture->deferedUploadToTexture(mRSC, false, 0);
+ mFontShaderF->bindTexture(0, mTextTexture.get());
+
+ // Some debug code
+ /*for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
+ LOGE("Cache Line: H: %u Empty Space: %f",
+ mCacheLines[i]->mMaxHeight,
+ (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
+
+ }*/
+
+ return true;
+}
+
+void FontState::initRenderState()
+{
+ uint32_t tmp[5] = {
+ RS_TEX_ENV_MODE_REPLACE, 1,
+ RS_TEX_ENV_MODE_NONE, 0,
+ 0
+ };
+ ProgramFragment *pf = new ProgramFragment(mRSC, tmp, 5);
+ mFontShaderF.set(pf);
+ mFontShaderF->init(mRSC);
+
+ Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
+ RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP);
+ mFontSampler.set(sampler);
+ mFontShaderF->bindSampler(0, sampler);
+
+ ProgramStore *fontStore = new ProgramStore(mRSC);
+ mFontProgramStore.set(fontStore);
+ mFontProgramStore->setDepthFunc(RS_DEPTH_FUNC_ALWAYS);
+ mFontProgramStore->setBlendFunc(RS_BLEND_SRC_SRC_ALPHA, RS_BLEND_DST_ONE_MINUS_SRC_ALPHA);
+ mFontProgramStore->setDitherEnable(false);
+ mFontProgramStore->setDepthMask(false);
+}
+
+void FontState::initTextTexture()
+{
+ const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
+
+ // We will allocate a texture to initially hold 32 character bitmaps
+ Type *texType = new Type(mRSC);
+ texType->setElement(alphaElem);
+ texType->setDimX(1024);
+ texType->setDimY(256);
+ texType->compute();
+
+ Allocation *cacheAlloc = new Allocation(mRSC, texType);
+ mTextTexture.set(cacheAlloc);
+ mTextTexture->deferedUploadToTexture(mRSC, false, 0);
+
+ // Split up our cache texture into lines of certain widths
+ int nextLine = 0;
+ mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
+ nextLine += mCacheLines.top()->mMaxHeight;
+ mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
+ nextLine += mCacheLines.top()->mMaxHeight;
+ mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
+ nextLine += mCacheLines.top()->mMaxHeight;
+ mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
+ nextLine += mCacheLines.top()->mMaxHeight;
+ mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
+ nextLine += mCacheLines.top()->mMaxHeight;
+ mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
+}
+
+// Avoid having to reallocate memory and render quad by quad
+void FontState::initVertexArrayBuffers()
+{
+ // Now lets write index data
+ const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
+ Type *indexType = new Type(mRSC);
+ uint32_t numIndicies = mMaxNumberOfQuads * 6;
+ indexType->setDimX(numIndicies);
+ indexType->setElement(indexElem);
+ indexType->compute();
+
+ Allocation *indexAlloc = new Allocation(mRSC, indexType);
+ uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
+
+ // Four verts, two triangles , six indices per quad
+ for(uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
+ int i6 = i * 6;
+ int i4 = i * 4;
+
+ indexPtr[i6 + 0] = i4 + 0;
+ indexPtr[i6 + 1] = i4 + 1;
+ indexPtr[i6 + 2] = i4 + 2;
+
+ indexPtr[i6 + 3] = i4 + 0;
+ indexPtr[i6 + 4] = i4 + 2;
+ indexPtr[i6 + 5] = i4 + 3;
+ }
+
+ indexAlloc->deferedUploadToBufferObject(mRSC);
+ mIndexBuffer.set(indexAlloc);
+
+ const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
+ const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
+
+ const Element *elemArray[2];
+ elemArray[0] = posElem;
+ elemArray[1] = texElem;
+
+ String8 posName("position");
+ String8 texName("texture0");
+
+ const char *nameArray[2];
+ nameArray[0] = posName.string();
+ nameArray[1] = texName.string();
+ size_t lengths[2];
+ lengths[0] = posName.size();
+ lengths[1] = texName.size();
+
+ const Element *vertexDataElem = Element::create(mRSC, 2, elemArray, nameArray, lengths);
+
+ Type *vertexDataType = new Type(mRSC);
+ vertexDataType->setDimX(mMaxNumberOfQuads * 4);
+ vertexDataType->setElement(vertexDataElem);
+ vertexDataType->compute();
+
+ Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType);
+ mTextMeshPtr = (float*)vertexAlloc->getPtr();
+
+ mVertexArray.set(vertexAlloc);
+}
+
+// We don't want to allocate anything unless we actually draw text
+void FontState::checkInit()
+{
+ if(mInitialized) {
+ return;
+ }
+
+ initTextTexture();
+ initRenderState();
+
+ initVertexArrayBuffers();
+
+ /*mTextMeshRefs = new ObjectBaseRef<SimpleMesh>[mNumMeshes];
+
+ for(uint32_t i = 0; i < mNumMeshes; i ++){
+ SimpleMesh *textMesh = createTextMesh();
+ mTextMeshRefs[i].set(textMesh);
+ }*/
+
+ mInitialized = true;
+}
+
+void FontState::issueDrawCommand() {
+
+ ObjectBaseRef<const ProgramVertex> tmpV(mRSC->getVertex());
+ mRSC->setVertex(mRSC->getDefaultProgramVertex());
+
+ ObjectBaseRef<const ProgramFragment> tmpF(mRSC->getFragment());
+ mRSC->setFragment(mFontShaderF.get());
+
+ ObjectBaseRef<const ProgramStore> tmpPS(mRSC->getFragmentStore());
+ mRSC->setFragmentStore(mFontProgramStore.get());
+
+ if (!mRSC->setupCheck()) {
+ mRSC->setVertex((ProgramVertex *)tmpV.get());
+ mRSC->setFragment((ProgramFragment *)tmpF.get());
+ mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
+ return;
+ }
+
+ float *vtx = (float*)mVertexArray->getPtr();
+ float *tex = vtx + 3;
+
+ VertexArray va;
+ va.add(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "position");
+ va.add(GL_FLOAT, 2, 20, false, (uint32_t)tex, "texture0");
+ va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
+
+ mIndexBuffer->uploadCheck(mRSC);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
+ glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
+
+ // Reset the state
+ mRSC->setVertex((ProgramVertex *)tmpV.get());
+ mRSC->setFragment((ProgramFragment *)tmpF.get());
+ mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
+}
+
+void FontState::appendMeshQuad(float x1, float y1, float z1,
+ float u1, float v1,
+ float x2, float y2, float z2,
+ float u2, float v2,
+ float x3, float y3, float z3,
+ float u3, float v3,
+ float x4, float y4, float z4,
+ float u4, float v4)
+{
+ const uint32_t vertsPerQuad = 4;
+ const uint32_t floatsPerVert = 5;
+ float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
+
+ // Cull things that are off the screen
+ float width = (float)mRSC->getWidth();
+ float height = (float)mRSC->getHeight();
+
+ if(x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
+ return;
+ }
+
+ /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
+ LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
+ LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
+ LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
+
+ (*currentPos++) = x1;
+ (*currentPos++) = y1;
+ (*currentPos++) = z1;
+ (*currentPos++) = u1;
+ (*currentPos++) = v1;
+
+ (*currentPos++) = x2;
+ (*currentPos++) = y2;
+ (*currentPos++) = z2;
+ (*currentPos++) = u2;
+ (*currentPos++) = v2;
+
+ (*currentPos++) = x3;
+ (*currentPos++) = y3;
+ (*currentPos++) = z3;
+ (*currentPos++) = u3;
+ (*currentPos++) = v3;
+
+ (*currentPos++) = x4;
+ (*currentPos++) = y4;
+ (*currentPos++) = z4;
+ (*currentPos++) = u4;
+ (*currentPos++) = v4;
+
+ mCurrentQuadIndex ++;
+
+ if(mCurrentQuadIndex == mMaxNumberOfQuads) {
+ issueDrawCommand();
+ mCurrentQuadIndex = 0;
+ }
+}
+
+void FontState::renderText(const char *text, uint32_t len, uint32_t startIndex, int numGlyphs, int x, int y)
+{
+ checkInit();
+
+ String8 text8(text);
+
+ // Render code here
+ Font *currentFont = mRSC->getFont();
+ currentFont->renderUTF(text, len, startIndex, numGlyphs, x, y);
+
+ if(mCurrentQuadIndex != 0) {
+ issueDrawCommand();
+ mCurrentQuadIndex = 0;
+ }
+}
+
+void FontState::renderText(const char *text, int x, int y)
+{
+ size_t textLen = strlen(text);
+ renderText(text, textLen, 0, -1, x, y);
+}
+
+void FontState::renderText(Allocation *alloc, int x, int y)
+{
+ if(!alloc) {
+ return;
+ }
+
+ const char *text = (const char *)alloc->getPtr();
+ size_t allocSize = alloc->getType()->getSizeBytes();
+ renderText(text, allocSize, 0, -1, x, y);
+}
+
+void FontState::renderText(Allocation *alloc, uint32_t start, int len, int x, int y)
+{
+ if(!alloc) {
+ return;
+ }
+
+ const char *text = (const char *)alloc->getPtr();
+ size_t allocSize = alloc->getType()->getSizeBytes();
+ renderText(text, allocSize, start, len, x, y);
+}
+
+void FontState::deinit(Context *rsc)
+{
+ if(mLibrary) {
+ FT_Done_FreeType( mLibrary );
+ }
+
+ delete mDefault.get();
+ mDefault.clear();
+}
+
+namespace android {
+namespace renderscript {
+
+RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi)
+{
+ return Font::create(rsc, name, fontSize, dpi);
+}
+
+} // renderscript
+} // android
diff --git a/libs/rs/rsFont.h b/libs/rs/rsFont.h
new file mode 100644
index 0000000..8d1556d
--- /dev/null
+++ b/libs/rs/rsFont.h
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_RS_FONT_H
+#define ANDROID_RS_FONT_H
+
+#include "RenderScript.h"
+#include "rsStream.h"
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/KeyedVector.h>
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+namespace renderscript {
+
+class FontState;
+
+class Font : public ObjectBase
+{
+public:
+ ~Font();
+
+ // Pointer to the utf data, length of data, where to start, number of glyphs ot read
+ // (each glyph may be longer than a char because we are dealing with utf data)
+ // Last two variables are the initial pen position
+ void renderUTF(const char *text, uint32_t len, uint32_t start, int numGlyphs, int x, int y);
+
+ // Currently files do not get serialized,
+ // but we need to inherit from ObjectBase for ref tracking
+ virtual void serialize(OStream *stream) const {
+ }
+ virtual RsA3DClassID getClassId() const {
+ return RS_A3D_CLASS_ID_UNKNOWN;
+ }
+
+ static Font * create(Context *rsc, const char *name, uint32_t fontSize, uint32_t dpi);
+
+protected:
+
+ friend class FontState;
+
+ void invalidateTextureCache();
+ struct CachedGlyphInfo
+ {
+ // Has the cache been invalidated?
+ bool mIsValid;
+ // Location of the cached glyph in the bitmap
+ // in case we need to resize the texture
+ uint32_t mBitmapMinX;
+ uint32_t mBitmapMinY;
+ uint32_t mBitmapWidth;
+ uint32_t mBitmapHeight;
+ // Also cache texture coords for the quad
+ float mBitmapMinU;
+ float mBitmapMinV;
+ float mBitmapMaxU;
+ float mBitmapMaxV;
+ // Minimize how much we call freetype
+ FT_UInt mGlyphIndex;
+ FT_Vector mAdvance;
+ // Values below contain a glyph's origin in the bitmap
+ FT_Int mBitmapLeft;
+ FT_Int mBitmapTop;
+ // Hold on to the bitmap in case cache is invalidated
+ FT_Bitmap mBitmap;
+ bool mBitmapValid;
+ };
+
+ String8 mFontName;
+ uint32_t mFontSize;
+ uint32_t mDpi;
+
+ Font(Context *rsc);
+ bool init(const char *name, uint32_t fontSize, uint32_t dpi);
+
+ FT_Face mFace;
+ bool mInitialized;
+ bool mHasKerning;
+
+ DefaultKeyedVector<uint32_t, CachedGlyphInfo* > mCachedGlyphs;
+
+ CachedGlyphInfo *cacheGlyph(uint32_t glyph);
+ void updateGlyphCache(CachedGlyphInfo *glyph);
+ void drawCachedGlyph(CachedGlyphInfo *glyph, int x, int y);
+};
+
+class FontState
+{
+public:
+ FontState();
+ ~FontState();
+
+ void init(Context *rsc);
+ void deinit(Context *rsc);
+
+ ObjectBaseRef<Font> mDefault;
+ ObjectBaseRef<Font> mLast;
+
+ void renderText(const char *text, uint32_t len, uint32_t startIndex, int numGlyphs, int x, int y);
+ void renderText(const char *text, int x, int y);
+ void renderText(Allocation *alloc, int x, int y);
+ void renderText(Allocation *alloc, uint32_t start, int len, int x, int y);
+
+protected:
+
+ friend class Font;
+
+ struct CacheTextureLine
+ {
+ uint32_t mMaxHeight;
+ uint32_t mMaxWidth;
+ uint32_t mCurrentRow;
+ uint32_t mCurrentCol;
+
+ CacheTextureLine(uint32_t maxHeight, uint32_t maxWidth, uint32_t currentRow, uint32_t currentCol) :
+ mMaxHeight(maxHeight), mMaxWidth(maxWidth), mCurrentRow(currentRow), mCurrentCol(currentCol) {
+ }
+
+ bool fitBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
+ if((uint32_t)bitmap->rows > mMaxHeight) {
+ return false;
+ }
+
+ if(mCurrentCol + (uint32_t)bitmap->width < mMaxWidth) {
+ *retOriginX = mCurrentCol;
+ *retOriginY = mCurrentRow;
+ mCurrentCol += bitmap->width;
+ return true;
+ }
+
+ return false;
+ }
+ };
+
+ Vector<CacheTextureLine*> mCacheLines;
+
+ Context *mRSC;
+
+ // Free type library, we only need one copy
+ FT_Library mLibrary;
+ Vector<Font*> mActiveFonts;
+
+ // Render state for the font
+ ObjectBaseRef<ProgramFragment> mFontShaderF;
+ ObjectBaseRef<Sampler> mFontSampler;
+ ObjectBaseRef<ProgramStore> mFontProgramStore;
+ void initRenderState();
+
+ // Texture to cache glyph bitmaps
+ ObjectBaseRef<Allocation> mTextTexture;
+ void initTextTexture();
+
+ bool cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY);
+ const Type* getCacheTextureType() {
+ return mTextTexture->getType();
+ }
+
+ void flushAllAndInvalidate();
+
+ // Pointer to vertex data to speed up frame to frame work
+ float *mTextMeshPtr;
+ uint32_t mCurrentQuadIndex;
+ uint32_t mMaxNumberOfQuads;
+
+ void initVertexArrayBuffers();
+ ObjectBaseRef<Allocation> mIndexBuffer;
+ ObjectBaseRef<Allocation> mVertexArray;
+
+
+ bool mInitialized;
+
+ void checkInit();
+
+ void issueDrawCommand();
+
+ void appendMeshQuad(float x1, float y1, float z1,
+ float u1, float v1,
+ float x2, float y2, float z2,
+ float u2, float v2,
+ float x3, float y3, float z3,
+ float u3, float v3,
+ float x4, float y4, float z4,
+ float u4, float v4);
+
+};
+
+
+}
+}
+
+#endif
diff --git a/libs/rs/rsScriptC_LibGL.cpp b/libs/rs/rsScriptC_LibGL.cpp
index 052e144..dbd398e 100644
--- a/libs/rs/rsScriptC_LibGL.cpp
+++ b/libs/rs/rsScriptC_LibGL.cpp
@@ -309,6 +309,24 @@ static uint32_t SC_getHeight()
return rsc->getHeight();
}
+static void SC_DrawTextAlloc(RsAllocation va, int x, int y)
+{
+ GET_TLS();
+ Allocation *alloc = static_cast<Allocation *>(va);
+ rsc->mStateFont.renderText(alloc, x, y);
+}
+
+static void SC_DrawText(const char *text, int x, int y)
+{
+ GET_TLS();
+ rsc->mStateFont.renderText(text, x, y);
+}
+
+static void SC_BindFont(RsFont font)
+{
+ GET_TLS();
+ rsi_ContextBindFont(rsc, font);
+}
//////////////////////////////////////////////////////////////////////////////
// Class implementation
@@ -360,6 +378,11 @@ static ScriptCState::SymbolTable_t gSyms[] = {
{ "rsgClearColor", (void *)&SC_ClearColor },
{ "rsgClearDepth", (void *)&SC_ClearDepth },
+ { "_Z11rsgDrawTextPKcii", (void *)&SC_DrawText },
+ { "_Z11rsgDrawText13rs_allocationii", (void *)&SC_DrawTextAlloc },
+
+ { "rsgBindFont", (void *)&SC_BindFont },
+
//////////////////////////////////////
// IO
diff --git a/libs/rs/rsType.cpp b/libs/rs/rsType.cpp
index 75abc76..8dca0fe 100644
--- a/libs/rs/rsType.cpp
+++ b/libs/rs/rsType.cpp
@@ -89,7 +89,9 @@ void Type::compute()
mLODCount = 1;
}
if (mLODCount != oldLODCount) {
- delete [] mLODs;
+ if(mLODs){
+ delete [] mLODs;
+ }
mLODs = new LOD[mLODCount];
}
diff --git a/libs/rs/scriptc/rs_graphics.rsh b/libs/rs/scriptc/rs_graphics.rsh
index c9667d0..fba3d6d 100644
--- a/libs/rs/scriptc/rs_graphics.rsh
+++ b/libs/rs/scriptc/rs_graphics.rsh
@@ -35,6 +35,10 @@ extern void __attribute__((overloadable)) rsgDrawSimpleMesh(rs_mesh ism, int sta
extern void rsgClearColor(float, float, float, float);
extern void rsgClearDepth(float);
+extern void __attribute__((overloadable)) rsgDrawText(const char *, int x, int y);
+extern void __attribute__((overloadable)) rsgDrawText(rs_allocation, int x, int y);
+extern void rsgBindFont(rs_font);
+
///////////////////////////////////////////////////////
// misc
extern void color(float, float, float, float);
diff --git a/libs/rs/scriptc/rs_types.rsh b/libs/rs/scriptc/rs_types.rsh
index 1d8f1bd..69e1aed 100644
--- a/libs/rs/scriptc/rs_types.rsh
+++ b/libs/rs/scriptc/rs_types.rsh
@@ -24,6 +24,7 @@ typedef struct { int* p; } __attribute__((packed, aligned(4))) rs_program_fragme
typedef struct { int* p; } __attribute__((packed, aligned(4))) rs_program_vertex;
typedef struct { int* p; } __attribute__((packed, aligned(4))) rs_program_raster;
typedef struct { int* p; } __attribute__((packed, aligned(4))) rs_program_store;
+typedef struct { int* p; } __attribute__((packed, aligned(4))) rs_font;
typedef float float2 __attribute__((ext_vector_type(2)));
typedef float float3 __attribute__((ext_vector_type(3)));