Merge "Adding freetype font rendering to renderscript."
This commit is contained in:
committed by
Android (Google) Code Review
commit
5b7e333cf2
@@ -386,6 +386,21 @@ public class Allocation extends BaseObj {
|
||||
Bitmap b = BitmapFactory.decodeResource(res, id, mBitmapOptions);
|
||||
return createFromBitmapBoxed(rs, b, dstFmt, genMips);
|
||||
}
|
||||
|
||||
static public Allocation createFromString(RenderScript rs, String str)
|
||||
throws IllegalArgumentException {
|
||||
byte[] allocArray = null;
|
||||
try {
|
||||
allocArray = str.getBytes("UTF-8");
|
||||
Allocation alloc = Allocation.createSized(rs, Element.U8(rs), allocArray.length);
|
||||
alloc.data(allocArray);
|
||||
return alloc;
|
||||
}
|
||||
catch (Exception e) {
|
||||
Log.e("rs", "could not convert string to utf-8");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
59
graphics/java/android/renderscript/Font.java
Normal file
59
graphics/java/android/renderscript/Font.java
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2008 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 android.renderscript;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.AssetManager;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*
|
||||
**/
|
||||
public class Font extends BaseObj {
|
||||
|
||||
Font(int id, RenderScript rs) {
|
||||
super(rs);
|
||||
mID = id;
|
||||
}
|
||||
|
||||
static public Font create(RenderScript rs, Resources res, String fileName, int size)
|
||||
throws IllegalArgumentException {
|
||||
|
||||
rs.validate();
|
||||
try {
|
||||
int dpi = res.getDisplayMetrics().densityDpi;
|
||||
int fontId = rs.nFontCreateFromFile(fileName, size, dpi);
|
||||
|
||||
if(fontId == 0) {
|
||||
throw new IllegalStateException("Load loading a font");
|
||||
}
|
||||
Font rsFont = new Font(fontId, rs);
|
||||
|
||||
return rsFont;
|
||||
|
||||
} catch (Exception e) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -123,6 +123,8 @@ public class RenderScript {
|
||||
native void nFileA3DGetIndexEntries(int fileA3D, int numEntries, int[] IDs, String[] names);
|
||||
native int nFileA3DGetEntryByIndex(int fileA3D, int index);
|
||||
|
||||
native int nFontCreateFromFile(String fileName, int size, int dpi);
|
||||
|
||||
native void nAdapter1DBindAllocation(int ad, int alloc);
|
||||
native void nAdapter1DSetConstraint(int ad, int dim, int value);
|
||||
native void nAdapter1DData(int ad, int[] d);
|
||||
|
||||
@@ -762,6 +762,19 @@ nFileA3DGetEntryByIndex(JNIEnv *_env, jobject _this, jint fileA3D, jint index)
|
||||
return id;
|
||||
}
|
||||
|
||||
// -----------------------------------
|
||||
|
||||
static int
|
||||
nFontCreateFromFile(JNIEnv *_env, jobject _this, jstring fileName, jint fontSize, jint dpi)
|
||||
{
|
||||
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
|
||||
const char* fileNameUTF = _env->GetStringUTFChars(fileName, NULL);
|
||||
|
||||
jint id = (jint)rsFontCreateFromFile(con, fileNameUTF, fontSize, dpi);
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------
|
||||
|
||||
static void
|
||||
@@ -1395,6 +1408,12 @@ static JNINativeMethod methods[] = {
|
||||
{"nContextDeinitToClient", "()V", (void*)nContextDeinitToClient },
|
||||
|
||||
{"nFileOpen", "([B)I", (void*)nFileOpen },
|
||||
{"nFileA3DCreateFromAssetStream", "(I)I", (void*)nFileA3DCreateFromAssetStream },
|
||||
{"nFileA3DGetNumIndexEntries", "(I)I", (void*)nFileA3DGetNumIndexEntries },
|
||||
{"nFileA3DGetIndexEntries", "(II[I[Ljava/lang/String;)V", (void*)nFileA3DGetIndexEntries },
|
||||
{"nFileA3DGetEntryByIndex", "(II)I", (void*)nFileA3DGetEntryByIndex },
|
||||
|
||||
{"nFontCreateFromFile", "(Ljava/lang/String;II)I", (void*)nFontCreateFromFile },
|
||||
|
||||
{"nElementCreate", "(IIZI)I", (void*)nElementCreate },
|
||||
{"nElementCreate2", "([I[Ljava/lang/String;)I", (void*)nElementCreate2 },
|
||||
@@ -1494,11 +1513,6 @@ static JNINativeMethod methods[] = {
|
||||
{"nSimpleMeshBindVertex", "(III)V", (void*)nSimpleMeshBindVertex },
|
||||
{"nSimpleMeshBindIndex", "(II)V", (void*)nSimpleMeshBindIndex },
|
||||
|
||||
{"nFileA3DCreateFromAssetStream", "(I)I", (void*)nFileA3DCreateFromAssetStream },
|
||||
{"nFileA3DGetNumIndexEntries", "(I)I", (void*)nFileA3DGetNumIndexEntries },
|
||||
{"nFileA3DGetIndexEntries", "(II[I[Ljava/lang/String;)V", (void*)nFileA3DGetIndexEntries },
|
||||
{"nFileA3DGetEntryByIndex", "(II)I", (void*)nFileA3DGetEntryByIndex },
|
||||
|
||||
};
|
||||
|
||||
static int registerFuncs(JNIEnv *_env)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
118
libs/rs/ScriptC_Modelviewer.java
Normal file
118
libs/rs/ScriptC_Modelviewer.java
Normal file
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "rsMesh.h"
|
||||
#include "rsAnimation.h"
|
||||
|
||||
|
||||
using namespace android;
|
||||
using namespace android::renderscript;
|
||||
|
||||
|
||||
689
libs/rs/rsFont.cpp
Normal file
689
libs/rs/rsFont.cpp
Normal file
@@ -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
|
||||
209
libs/rs/rsFont.h
Normal file
209
libs/rs/rsFont.h
Normal file
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -89,7 +89,9 @@ void Type::compute()
|
||||
mLODCount = 1;
|
||||
}
|
||||
if (mLODCount != oldLODCount) {
|
||||
delete [] mLODs;
|
||||
if(mLODs){
|
||||
delete [] mLODs;
|
||||
}
|
||||
mLODs = new LOD[mLODCount];
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)));
|
||||
|
||||
Reference in New Issue
Block a user