diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/gpu/GrAllocPool.h | 64 | ||||
-rwxr-xr-x | src/gpu/GrAllocator.h | 249 | ||||
-rw-r--r-- | src/gpu/GrAtlas.h | 84 | ||||
-rw-r--r-- | src/gpu/GrDrawMesh.cpp | 147 | ||||
-rw-r--r-- | src/gpu/GrGLShaderVar.h | 1 | ||||
-rw-r--r-- | src/gpu/GrGpuVertex.h | 97 | ||||
-rw-r--r-- | src/gpu/GrPlotMgr.h | 77 | ||||
-rw-r--r-- | src/gpu/GrRandom.h | 55 | ||||
-rw-r--r-- | src/gpu/GrRectanizer.h | 57 | ||||
-rw-r--r-- | src/gpu/GrStencil.h | 211 | ||||
-rw-r--r-- | src/gpu/GrStringBuilder.h | 19 | ||||
-rw-r--r-- | src/gpu/GrTBSearch.h | 46 | ||||
-rw-r--r-- | src/gpu/GrTDArray.h | 216 | ||||
-rw-r--r-- | src/gpu/GrTHashCache.h | 219 | ||||
-rw-r--r-- | src/gpu/GrTLList.h | 54 | ||||
-rw-r--r-- | src/gpu/GrTextStrike.h | 115 | ||||
-rw-r--r-- | src/gpu/ios/SkUIView.mm | 827 |
17 files changed, 1564 insertions, 974 deletions
diff --git a/src/gpu/GrAllocPool.h b/src/gpu/GrAllocPool.h new file mode 100644 index 0000000000..3ecc4aa189 --- /dev/null +++ b/src/gpu/GrAllocPool.h @@ -0,0 +1,64 @@ + +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef GrAllocPool_DEFINED +#define GrAllocPool_DEFINED + +#include "GrNoncopyable.h" + +class GrAllocPool : GrNoncopyable { +public: + GrAllocPool(size_t blockSize = 0); + ~GrAllocPool(); + + /** + * Frees all blocks that have been allocated with alloc(). + */ + void reset(); + + /** + * Returns a block of memory bytes size big. This address must not be + * passed to realloc/free/delete or any other function that assumes the + * address was allocated by malloc or new (because it hasn't). + */ + void* alloc(size_t bytes); + + /** + * Releases the most recently allocated bytes back to allocpool. + */ + void release(size_t bytes); + +private: + struct Block; + + Block* fBlock; + size_t fMinBlockSize; + +#if GR_DEBUG + int fBlocksAllocated; + void validate() const; +#else + void validate() const {} +#endif +}; + +template <typename T> class GrTAllocPool { +public: + GrTAllocPool(int count) : fPool(count * sizeof(T)) {} + + void reset() { fPool.reset(); } + T* alloc() { return (T*)fPool.alloc(sizeof(T)); } + +private: + GrAllocPool fPool; +}; + +#endif + diff --git a/src/gpu/GrAllocator.h b/src/gpu/GrAllocator.h new file mode 100755 index 0000000000..21c79ec7aa --- /dev/null +++ b/src/gpu/GrAllocator.h @@ -0,0 +1,249 @@ + +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef GrAllocator_DEFINED +#define GrAllocator_DEFINED + +#include "GrConfig.h" +#include "SkTArray.h" + +class GrAllocator : GrNoncopyable { +public: + ~GrAllocator() { + reset(); + } + + /** + * Create an allocator + * + * @param itemSize the size of each item to allocate + * @param itemsPerBlock the number of items to allocate at once + * @param initialBlock optional memory to use for the first block. + * Must be at least itemSize*itemsPerBlock sized. + * Caller is responsible for freeing this memory. + */ + GrAllocator(size_t itemSize, int itemsPerBlock, void* initialBlock) : + fItemSize(itemSize), + fItemsPerBlock(itemsPerBlock), + fOwnFirstBlock(NULL == initialBlock), + fCount(0) { + GrAssert(itemsPerBlock > 0); + fBlockSize = fItemSize * fItemsPerBlock; + fBlocks.push_back() = initialBlock; + GR_DEBUGCODE(if (!fOwnFirstBlock) {*((char*)initialBlock+fBlockSize-1)='a';} ); + } + + /** + * Adds an item and returns pointer to it. + * + * @return pointer to the added item. + */ + void* push_back() { + int indexInBlock = fCount % fItemsPerBlock; + // we always have at least one block + if (0 == indexInBlock) { + if (0 != fCount) { + fBlocks.push_back() = GrMalloc(fBlockSize); + } else if (fOwnFirstBlock) { + fBlocks[0] = GrMalloc(fBlockSize); + } + } + void* ret = (char*)fBlocks[fCount/fItemsPerBlock] + + fItemSize * indexInBlock; + ++fCount; + return ret; + } + + /** + * removes all added items + */ + void reset() { + int blockCount = GrMax((unsigned)1, + GrUIDivRoundUp(fCount, fItemsPerBlock)); + for (int i = 1; i < blockCount; ++i) { + GrFree(fBlocks[i]); + } + if (fOwnFirstBlock) { + GrFree(fBlocks[0]); + fBlocks[0] = NULL; + } + fBlocks.pop_back_n(blockCount-1); + fCount = 0; + } + + /** + * count of items + */ + int count() const { + return fCount; + } + + /** + * is the count 0 + */ + bool empty() const { return fCount == 0; } + + /** + * access last item, only call if count() != 0 + */ + void* back() { + GrAssert(fCount); + return (*this)[fCount-1]; + } + + /** + * access last item, only call if count() != 0 + */ + const void* back() const { + GrAssert(fCount); + return (*this)[fCount-1]; + } + + /** + * access item by index. + */ + void* operator[] (int i) { + GrAssert(i >= 0 && i < fCount); + return (char*)fBlocks[i / fItemsPerBlock] + + fItemSize * (i % fItemsPerBlock); + } + + /** + * access item by index. + */ + const void* operator[] (int i) const { + GrAssert(i >= 0 && i < fCount); + return (const char*)fBlocks[i / fItemsPerBlock] + + fItemSize * (i % fItemsPerBlock); + } + +private: + static const int NUM_INIT_BLOCK_PTRS = 8; + + SkSTArray<NUM_INIT_BLOCK_PTRS, void*> fBlocks; + size_t fBlockSize; + size_t fItemSize; + int fItemsPerBlock; + bool fOwnFirstBlock; + int fCount; + + typedef GrNoncopyable INHERITED; +}; + +template <typename T> +class GrTAllocator : GrNoncopyable { + +public: + virtual ~GrTAllocator() {}; + + /** + * Create an allocator + * + * @param itemsPerBlock the number of items to allocate at once + * @param initialBlock optional memory to use for the first block. + * Must be at least size(T)*itemsPerBlock sized. + * Caller is responsible for freeing this memory. + */ + explicit GrTAllocator(int itemsPerBlock) + : fAllocator(sizeof(T), itemsPerBlock, NULL) {} + + /** + * Adds an item and returns it. + * + * @return the added item. + */ + T& push_back() { + void* item = fAllocator.push_back(); + GrAssert(NULL != item); + new (item) T; + return *(T*)item; + } + + T& push_back(const T& t) { + void* item = fAllocator.push_back(); + GrAssert(NULL != item); + new (item) T(t); + return *(T*)item; + } + + /** + * removes all added items + */ + void reset() { + int c = fAllocator.count(); + for (int i = 0; i < c; ++i) { + ((T*)fAllocator[i])->~T(); + } + fAllocator.reset(); + } + + /** + * count of items + */ + int count() const { + return fAllocator.count(); + } + + /** + * is the count 0 + */ + bool empty() const { return fAllocator.empty(); } + + /** + * access last item, only call if count() != 0 + */ + T& back() { + return *(T*)fAllocator.back(); + } + + /** + * access last item, only call if count() != 0 + */ + const T& back() const { + return *(const T*)fAllocator.back(); + } + + /** + * access item by index. + */ + T& operator[] (int i) { + return *(T*)(fAllocator[i]); + } + + /** + * access item by index. + */ + const T& operator[] (int i) const { + return *(const T*)(fAllocator[i]); + } + +protected: + GrTAllocator(int itemsPerBlock, void* initialBlock) + : fAllocator(sizeof(T), itemsPerBlock, initialBlock) { + } + +private: + GrAllocator fAllocator; + typedef GrNoncopyable INHERITED; +}; + +template <int N, typename T> class GrSTAllocator : public GrTAllocator<T> { +private: + typedef GrTAllocator<T> INHERITED; + +public: + GrSTAllocator() : INHERITED(N, fStorage.get()) { + } + +private: + SkAlignedSTStorage<N, T> fStorage; +}; + +#endif diff --git a/src/gpu/GrAtlas.h b/src/gpu/GrAtlas.h new file mode 100644 index 0000000000..f0114e399d --- /dev/null +++ b/src/gpu/GrAtlas.h @@ -0,0 +1,84 @@ + +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef GrAtlas_DEFINED +#define GrAtlas_DEFINED + +#include "GrPoint.h" +#include "GrTexture.h" +#include "GrTDArray.h" + +class GrGpu; +class GrRectanizer; +class GrAtlasMgr; + +class GrAtlas { +public: + GrAtlas(GrAtlasMgr*, int plotX, int plotY, GrMaskFormat); + + int getPlotX() const { return fPlot.fX; } + int getPlotY() const { return fPlot.fY; } + GrMaskFormat getMaskFormat() const { return fMaskFormat; } + + GrTexture* texture() const { return fTexture; } + + bool addSubImage(int width, int height, const void*, GrIPoint16*); + + static void FreeLList(GrAtlas* atlas) { + while (atlas) { + GrAtlas* next = atlas->fNext; + delete atlas; + atlas = next; + } + } + + // testing + GrAtlas* nextAtlas() const { return fNext; } + +private: + ~GrAtlas(); // does not try to delete the fNext field + + GrAtlas* fNext; + GrTexture* fTexture; + GrRectanizer* fRects; + GrAtlasMgr* fAtlasMgr; + GrIPoint16 fPlot; + GrMaskFormat fMaskFormat; + + friend class GrAtlasMgr; +}; + +class GrPlotMgr; + +class GrAtlasMgr { +public: + GrAtlasMgr(GrGpu*); + ~GrAtlasMgr(); + + GrAtlas* addToAtlas(GrAtlas*, int width, int height, const void*, + GrMaskFormat, GrIPoint16*); + + GrTexture* getTexture(GrMaskFormat format) const { + GrAssert((unsigned)format < kCount_GrMaskFormats); + return fTexture[format]; + } + + // to be called by ~GrAtlas() + void freePlot(int x, int y); + +private: + GrGpu* fGpu; + GrTexture* fTexture[kCount_GrMaskFormats]; + GrPlotMgr* fPlotMgr; +}; + +#endif + + diff --git a/src/gpu/GrDrawMesh.cpp b/src/gpu/GrDrawMesh.cpp deleted file mode 100644 index 75960e4f92..0000000000 --- a/src/gpu/GrDrawMesh.cpp +++ /dev/null @@ -1,147 +0,0 @@ - -/* - * Copyright 2011 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -#include "GrMesh.h" -#include "SkCanvas.h" - -GrMesh::GrMesh() : fPts(NULL), fCount(0), fIndices(NULL), fIndexCount(0) {} - -GrMesh::~GrMesh() { - delete[] fPts; - delete[] fIndices; -} - -GrMesh& GrMesh::operator=(const GrMesh& src) { - delete[] fPts; - delete[] fIndices; - - fBounds = src.fBounds; - fRows = src.fRows; - fCols = src.fCols; - - fCount = src.fCount; - fPts = new SkPoint[fCount * 2]; - fTex = fPts + fCount; - memcpy(fPts, src.fPts, fCount * 2 * sizeof(SkPoint)); - - delete[] fIndices; - fIndexCount = src.fIndexCount; - fIndices = new uint16_t[fIndexCount]; - memcpy(fIndices, src.fIndices, fIndexCount * sizeof(uint16_t)); - - return *this; -} - -void GrMesh::init(const SkRect& bounds, int rows, int cols, - const SkRect& texture) { - SkASSERT(rows > 0 && cols > 0); - - fBounds = bounds; - fRows = rows; - fCols = cols; - - delete[] fPts; - fCount = (rows + 1) * (cols + 1); - fPts = new SkPoint[fCount * 2]; - fTex = fPts + fCount; - - delete[] fIndices; - fIndexCount = rows * cols * 6; - fIndices = new uint16_t[fIndexCount]; - - SkPoint* pts = fPts; - const SkScalar dx = bounds.width() / rows; - const SkScalar dy = bounds.height() / cols; - SkPoint* tex = fTex; - const SkScalar dtx = texture.width() / rows; - const SkScalar dty = texture.height() / cols; - uint16_t* idx = fIndices; - int index = 0; - for (int y = 0; y <= cols; y++) { - for (int x = 0; x <= rows; x++) { - pts->set(bounds.fLeft + x*dx, bounds.fTop + y*dy); - pts += 1; - tex->set(texture.fLeft + x*dtx, texture.fTop + y*dty); - tex += 1; - - if (y < cols && x < rows) { - *idx++ = index; - *idx++ = index + rows + 1; - *idx++ = index + 1; - - *idx++ = index + 1; - *idx++ = index + rows + 1; - *idx++ = index + rows + 2; - - index += 1; - } - } - index += 1; - } -} - -void GrMesh::draw(SkCanvas* canvas, const SkPaint& paint) { - canvas->drawVertices(SkCanvas::kTriangles_VertexMode, fCount, - fPts, fTex, NULL, NULL, fIndices, fIndexCount, - paint); -} - -///////////////////////////////////////////// - -#include "SkBoundaryPatch.h" -#include "SkMeshUtils.h" - -static SkPoint SkPointInterp(const SkPoint& a, const SkPoint& b, SkScalar t) { - return SkPoint::Make(SkScalarInterp(a.fX, b.fX, t), - SkScalarInterp(a.fY, b.fY, t)); -} - -static void set_cubic(SkPoint pts[4], SkScalar x0, SkScalar y0, - SkScalar x3, SkScalar y3, SkScalar scale = 1) { - SkPoint tmp, tmp2; - - pts[0].set(x0, y0); - pts[3].set(x3, y3); - - tmp = SkPointInterp(pts[0], pts[3], SK_Scalar1/3); - tmp2 = pts[0] - tmp; - tmp2.rotateCW(); - tmp2.scale(scale); - pts[1] = tmp + tmp2; - - tmp = SkPointInterp(pts[0], pts[3], 2*SK_Scalar1/3); - tmp2 = pts[3] - tmp; - tmp2.rotateCW(); - tmp2.scale(scale); - pts[2] = tmp + tmp2; -} - -void test_patch(SkCanvas* canvas, const SkBitmap& bm, SkScalar scale) { - const float w = bm.width(); - const float h = bm.height(); - SkCubicBoundary cubic; - set_cubic(cubic.fPts + 0, 0, 0, w, 0, scale); - set_cubic(cubic.fPts + 3, w, 0, w, h, scale); - set_cubic(cubic.fPts + 6, w, h, 0, h, -scale); - set_cubic(cubic.fPts + 9, 0, h, 0, 0, scale); - - SkBoundaryPatch patch; - patch.setBoundary(&cubic); - - const int Rows = 16; - const int Cols = 16; - SkPoint pts[Rows * Cols]; - patch.evalPatch(pts, Rows, Cols); - - SkPaint paint; - paint.setAntiAlias(true); - paint.setFilterBitmap(true); - - SkMeshUtils::Draw(canvas, bm, Rows, Cols, pts, NULL, paint); -} - - diff --git a/src/gpu/GrGLShaderVar.h b/src/gpu/GrGLShaderVar.h index 5c50079558..8eba7140c9 100644 --- a/src/gpu/GrGLShaderVar.h +++ b/src/gpu/GrGLShaderVar.h @@ -10,6 +10,7 @@ #define GrGLShaderVar_DEFINED #include "GrGLInterface.h" +#include "GrStringBuilder.h" /** * Represents a variable in a shader diff --git a/src/gpu/GrGpuVertex.h b/src/gpu/GrGpuVertex.h new file mode 100644 index 0000000000..2abc2f407e --- /dev/null +++ b/src/gpu/GrGpuVertex.h @@ -0,0 +1,97 @@ + +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef GrGpuVertex_DEFINED +#define GrGpuVertex_DEFINED + +#include "GrGLConfig.h" +#include "GrPoint.h" + +#if GR_TEXT_SCALAR_IS_USHORT + typedef uint16_t GrTextScalar; + #define GrIntToTextScalar(x) ((uint16_t)x) + #define GrFixedToTextScalar(x) (x) +#elif GR_TEXT_SCALAR_IS_FIXED + typedef GrFixed GrTextScalar; + #define GrIntToTextScalar(x) GrIntToFixed(x) + #define GrFixedToTextScalar(x) (x) +#elif GR_TEXT_SCALAR_IS_FLOAT + typedef float GrTextScalar; + #define GrIntToTextScalar(x) ((GrTextScalar)x) + #define GrFixedToTextScalar(x) GrFixedToFloat(x) +#else + #error "Text scalar type not defined" +#endif + +// text has its own vertex class, since it may want to be in fixed point (given) +// that it starts with all integers) even when the default vertices are floats +struct GrGpuTextVertex { + GrTextScalar fX; + GrTextScalar fY; + + void set(GrTextScalar x, GrTextScalar y) { + fX = x; + fY = y; + } + + void setI(int x, int y) { + fX = GrIntToTextScalar(x); + fY = GrIntToTextScalar(y); + } + + void setX(GrFixed x, GrFixed y) { + fX = GrFixedToTextScalar(x); + fY = GrFixedToTextScalar(y); + } + + // rect fan is counter-clockwise + + void setRectFan(GrTextScalar l, GrTextScalar t, GrTextScalar r, + GrTextScalar b) { + GrGpuTextVertex* v = this; + v[0].set(l, t); + v[1].set(l, b); + v[2].set(r, b); + v[3].set(r, t); + } + + void setIRectFan(int l, int t, int r, int b) { + this->setRectFan(GrIntToTextScalar(l), GrIntToTextScalar(t), + GrIntToTextScalar(r), GrIntToTextScalar(b)); + } + + void setIRectFan(int l, int t, int r, int b, size_t stride) { + GrAssert(stride > sizeof(GrGpuTextVertex)); + char* v = (char*)this; + ((GrGpuTextVertex*)(v + 0*stride))->setI(l, t); + ((GrGpuTextVertex*)(v + 1*stride))->setI(l, b); + ((GrGpuTextVertex*)(v + 2*stride))->setI(r, b); + ((GrGpuTextVertex*)(v + 3*stride))->setI(r, t); + } + + // counter-clockwise fan + void setXRectFan(GrFixed l, GrFixed t, GrFixed r, GrFixed b) { + this->setRectFan(GrFixedToTextScalar(l), GrFixedToTextScalar(t), + GrFixedToTextScalar(r), GrFixedToTextScalar(b)); + } + + void setXRectFan(GrFixed l, GrFixed t, GrFixed r, GrFixed b, size_t stride) { + GrAssert(stride > sizeof(GrGpuTextVertex)); + char* v = (char*)this; + ((GrGpuTextVertex*)(v + 0*stride))->setX(l, t); + ((GrGpuTextVertex*)(v + 1*stride))->setX(l, b); + ((GrGpuTextVertex*)(v + 2*stride))->setX(r, b); + ((GrGpuTextVertex*)(v + 3*stride))->setX(r, t); + } + +}; + +#endif + diff --git a/src/gpu/GrPlotMgr.h b/src/gpu/GrPlotMgr.h new file mode 100644 index 0000000000..0e631a9ade --- /dev/null +++ b/src/gpu/GrPlotMgr.h @@ -0,0 +1,77 @@ + +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef GrPlotMgr_DEFINED +#define GrPlotMgr_DEFINED + +#include "GrTypes.h" +#include "GrPoint.h" + +class GrPlotMgr : GrNoncopyable { +public: + GrPlotMgr(int width, int height) { + fDim.set(width, height); + size_t needed = width * height; + if (needed <= sizeof(fStorage)) { + fBusy = fStorage; + } else { + fBusy = new char[needed]; + } + this->reset(); + } + + ~GrPlotMgr() { + if (fBusy != fStorage) { + delete[] fBusy; + } + } + + void reset() { + Gr_bzero(fBusy, fDim.fX * fDim.fY); + } + + bool newPlot(GrIPoint16* loc) { + char* busy = fBusy; + for (int y = 0; y < fDim.fY; y++) { + for (int x = 0; x < fDim.fX; x++) { + if (!*busy) { + *busy = true; + loc->set(x, y); + return true; + } + busy++; + } + } + return false; + } + + bool isBusy(int x, int y) const { + GrAssert((unsigned)x < (unsigned)fDim.fX); + GrAssert((unsigned)y < (unsigned)fDim.fY); + return fBusy[y * fDim.fX + x] != 0; + } + + void freePlot(int x, int y) { + GrAssert((unsigned)x < (unsigned)fDim.fX); + GrAssert((unsigned)y < (unsigned)fDim.fY); + fBusy[y * fDim.fX + x] = false; + } + +private: + enum { + STORAGE = 64 + }; + char fStorage[STORAGE]; + char* fBusy; + GrIPoint16 fDim; +}; + +#endif + diff --git a/src/gpu/GrRandom.h b/src/gpu/GrRandom.h new file mode 100644 index 0000000000..c98a8fbd94 --- /dev/null +++ b/src/gpu/GrRandom.h @@ -0,0 +1,55 @@ + +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef GrRandom_DEFINED +#define GrRandom_DEFINED + +class GrRandom { +public: + GrRandom() : fSeed(0) {} + GrRandom(uint32_t seed) : fSeed(seed) {} + + uint32_t seed() const { return fSeed; } + + uint32_t nextU() { + fSeed = fSeed * kMUL + kADD; + return fSeed; + } + + int32_t nextS() { return (int32_t)this->nextU(); } + + /** + * Returns value [0...1) as a float + */ + float nextF() { + // const is 1 / (2^32 - 1) + return (float)(this->nextU() * 2.32830644e-10); + } + + /** + * Returns value [min...max) as a float + */ + float nextF(float min, float max) { + return min + this->nextF() * (max - min); + } + +private: + /* + * These constants taken from "Numerical Recipes in C", reprinted 1999 + */ + enum { + kMUL = 1664525, + kADD = 1013904223 + }; + uint32_t fSeed; +}; + +#endif + diff --git a/src/gpu/GrRectanizer.h b/src/gpu/GrRectanizer.h new file mode 100644 index 0000000000..d1f5033259 --- /dev/null +++ b/src/gpu/GrRectanizer.h @@ -0,0 +1,57 @@ + +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef GrRectanizer_DEFINED +#define GrRectanizer_DEFINED + +#include "GrRect.h" +#include "GrTDArray.h" + +class GrRectanizerPurgeListener { +public: + virtual ~GrRectanizerPurgeListener() {} + + virtual void notifyPurgeStrip(void*, int yCoord) = 0; +}; + +class GrRectanizer { +public: + GrRectanizer(int width, int height) : fWidth(width), fHeight(height) { + GrAssert(width >= 0); + GrAssert(height >= 0); + } + + virtual ~GrRectanizer() {} + + int width() const { return fWidth; } + int height() const { return fHeight; } + + virtual bool addRect(int width, int height, GrIPoint16* loc) = 0; + virtual float percentFull() const = 0; + + // return the Y-coordinate of a strip that should be purged, given height + // i.e. return the oldest such strip, or some other criteria. Return -1 + // if there is no candidate + virtual int stripToPurge(int height) const = 0; + virtual void purgeStripAtY(int yCoord) = 0; + + /** + * Our factory, which returns the subclass du jour + */ + static GrRectanizer* Factory(int width, int height); + +private: + int fWidth; + int fHeight; +}; + +#endif + + diff --git a/src/gpu/GrStencil.h b/src/gpu/GrStencil.h new file mode 100644 index 0000000000..b8610f2017 --- /dev/null +++ b/src/gpu/GrStencil.h @@ -0,0 +1,211 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef GrStencil_DEFINED +#define GrStencil_DEFINED + +#include "GrTypes.h" +/** + * Gr uses the stencil buffer to implement complex clipping inside the + * GrDrawTarget class. The GrDrawTarget makes a subset of the stencil buffer + * bits available for other uses by external code (clients). Client code can + * modify these bits. GrDrawTarget will ignore ref, mask, and writemask bits + * provided by clients that overlap the bits used to implement clipping. + * + * When code outside the GrDrawTarget class uses the stencil buffer the contract + * is as follows: + * + * > Normal stencil funcs allow the client to pass / fail regardless of the + * reserved clip bits. + * > Additional functions allow a test against the clip along with a limited + * set of tests against the client bits. + * > Client can assume all client bits are zero initially. + * > Client must ensure that after all its passes are finished it has only + * written to the color buffer in the region inside the clip. Furthermore, it + * must zero all client bits that were modifed (both inside and outside the + * clip). + */ + +/** + * Determines which pixels pass / fail the stencil test. + * Stencil test passes if (ref & mask) FUNC (stencil & mask) is true + */ +enum GrStencilFunc { + kAlways_StencilFunc = 0, + kNever_StencilFunc, + kGreater_StencilFunc, + kGEqual_StencilFunc, + kLess_StencilFunc, + kLEqual_StencilFunc, + kEqual_StencilFunc, + kNotEqual_StencilFunc, + + // Gr stores the current clip in the + // stencil buffer in the high bits that + // are not directly accessible modifiable + // via the GrDrawTarget interface. The below + // stencil funcs test against the current + // clip in addition to the GrDrawTarget + // client's stencil bits. + + // pass if inside the clip + kAlwaysIfInClip_StencilFunc, + kEqualIfInClip_StencilFunc, + kLessIfInClip_StencilFunc, + kLEqualIfInClip_StencilFunc, + kNonZeroIfInClip_StencilFunc, // this one forces the ref to be 0 + + // counts + kStencilFuncCount, + kClipStencilFuncCount = kNonZeroIfInClip_StencilFunc - + kAlwaysIfInClip_StencilFunc + 1, + kBasicStencilFuncCount = kStencilFuncCount - kClipStencilFuncCount +}; + +/** + * Operations to perform based on whether stencil test passed failed. + */ +enum GrStencilOp { + kKeep_StencilOp = 0, // preserve existing stencil value + kReplace_StencilOp, // replace with reference value from stencl test + kIncWrap_StencilOp, // increment and wrap at max + kIncClamp_StencilOp, // increment and clamp at max + kDecWrap_StencilOp, // decrement and wrap at 0 + kDecClamp_StencilOp, // decrement and clamp at 0 + kZero_StencilOp, // zero stencil bits + kInvert_StencilOp, // invert stencil bits + + kStencilOpCount +}; + +/** + * Struct representing stencil state. + */ +struct GrStencilSettings { + GrStencilOp fFrontPassOp; // op to perform when front faces pass + GrStencilOp fBackPassOp; // op to perform when back faces pass + GrStencilOp fFrontFailOp; // op to perform when front faces fail + GrStencilOp fBackFailOp; // op to perform when back faces fail + GrStencilFunc fFrontFunc; // test function for front faces + GrStencilFunc fBackFunc; // test function for back faces + unsigned int fFrontFuncMask; // mask for front face test + unsigned int fBackFuncMask; // mask for back face test + unsigned int fFrontFuncRef; // reference value for front face test + unsigned int fBackFuncRef; // reference value for back face test + unsigned int fFrontWriteMask; // stencil write mask for front faces + unsigned int fBackWriteMask; // stencil write mask for back faces + + bool operator == (const GrStencilSettings& s) const { + // make sure this is tightly packed. + GR_STATIC_ASSERT(0 == sizeof(GrStencilOp)%4); + GR_STATIC_ASSERT(0 == sizeof(GrStencilFunc)%4); + GR_STATIC_ASSERT(sizeof(GrStencilSettings) == + 4*sizeof(GrStencilOp) + + 2*sizeof(GrStencilFunc) + + 6*sizeof(unsigned int)); + return 0 == memcmp(this, &s, sizeof(GrStencilSettings)); + } + + bool operator != (const GrStencilSettings& s) const { + return !(*this == s); + } + + GrStencilSettings& operator =(const GrStencilSettings& s) { + memcpy(this, &s, sizeof(GrStencilSettings)); + return *this; + } + + void setSame(GrStencilOp passOp, + GrStencilOp failOp, + GrStencilFunc func, + unsigned int funcMask, + unsigned int funcRef, + unsigned int writeMask) { + fFrontPassOp = passOp; + fBackPassOp = passOp; + fFrontFailOp = failOp; + fBackFailOp = failOp; + fFrontFunc = func; + fBackFunc = func; + fFrontFuncMask = funcMask; + fBackFuncMask = funcMask; + fFrontFuncRef = funcRef; + fBackFuncRef = funcRef; + fFrontWriteMask = writeMask; + fBackWriteMask = writeMask; + } + + // canonical value for disabled stenciling + static const GrStencilSettings gDisabled; + void setDisabled() { + *this = gDisabled; + } + bool isDisabled() const { + return kKeep_StencilOp == fFrontPassOp && + kKeep_StencilOp == fBackPassOp && + kKeep_StencilOp == fFrontFailOp && + kKeep_StencilOp == fBackFailOp && + kAlways_StencilFunc == fFrontFunc && + kAlways_StencilFunc == fBackFunc; + } + bool doesWrite() const { + return !((kNever_StencilFunc == fFrontFunc || + kKeep_StencilOp == fFrontPassOp) && + (kNever_StencilFunc == fBackFunc || + kKeep_StencilOp == fBackPassOp) && + (kAlways_StencilFunc == fFrontFunc || + kKeep_StencilOp == fFrontFailOp) && + (kAlways_StencilFunc == fBackFunc || + kKeep_StencilOp == fBackFailOp)); + } + void invalidate() { + // just write an illegal value to the first member + fFrontPassOp = (GrStencilOp)-1; + } + +private: + friend class GrGpu; + + enum { + kMaxStencilClipPasses = 2 // maximum number of passes to add a clip + // element to the stencil buffer. + }; + + /** + * Given a thing to draw into the stencil clip, a fill type, and a set op + * this function determines: + * 1. Whether the thing can be draw directly to the stencil clip or + * needs to be drawn to the client portion of the stencil first. + * 2. How many passes are needed. + * 3. What those passes are. + * 4. The fill rule that should actually be used to render (will + * always be non-inverted). + * + * @param op the set op to combine this element with the + * existing clip + * @param stencilClipMask mask with just the stencil bit used for clipping + * enabled. + * @param invertedFill is this path inverted + * @param numPasses out: the number of passes needed to add the + * element to the clip. + * @param settings out: the stencil settings to use for each pass + * + * @return true if the clip element's geometry can be drawn directly to the + * stencil clip bit. Will only be true if canBeDirect is true. + * numPasses will be 1 if return value is true. + */ + static bool GetClipPasses(GrSetOp op, + bool canBeDirect, + unsigned int stencilClipMask, + bool invertedFill, + int* numPasses, + GrStencilSettings settings[kMaxStencilClipPasses]); +}; + +#endif diff --git a/src/gpu/GrStringBuilder.h b/src/gpu/GrStringBuilder.h new file mode 100644 index 0000000000..558d0419c0 --- /dev/null +++ b/src/gpu/GrStringBuilder.h @@ -0,0 +1,19 @@ + +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef GrStringBuilder_DEFINED +#define GrStringBuilder_DEFINED + +#include "SkString.h" + +typedef SkString GrStringBuilder; + +#endif + diff --git a/src/gpu/GrTBSearch.h b/src/gpu/GrTBSearch.h new file mode 100644 index 0000000000..2697f3733b --- /dev/null +++ b/src/gpu/GrTBSearch.h @@ -0,0 +1,46 @@ + +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef GrTBSearch_DEFINED +#define GrTBSearch_DEFINED + +template <typename ELEM, typename KEY> +int GrTBSearch(const ELEM array[], int count, KEY target) { + GrAssert(count >= 0); + if (0 == count) { + // we should insert it at 0 + return ~0; + } + + int high = count - 1; + int low = 0; + while (high > low) { + int index = (low + high) >> 1; + if (LT(array[index], target)) { + low = index + 1; + } else { + high = index; + } + } + + // check if we found it + if (EQ(array[high], target)) { + return high; + } + + // now return the ~ of where we should insert it + if (LT(array[high], target)) { + high += 1; + } + return ~high; +} + +#endif + diff --git a/src/gpu/GrTDArray.h b/src/gpu/GrTDArray.h new file mode 100644 index 0000000000..731001a8c9 --- /dev/null +++ b/src/gpu/GrTDArray.h @@ -0,0 +1,216 @@ + +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef GrTDArray_DEFINED +#define GrTDArray_DEFINED + +#include "GrTypes.h" +#include "GrRefCnt.h" + +static int GrInitialArrayAllocationCount() { + return 4; +} + +static int GrNextArrayAllocationCount(int count) { + return count + ((count + 1) >> 1); +} + +template <typename T> class GrTDArray { +public: + GrTDArray() : fArray(NULL), fAllocated(0), fCount(0) {} + GrTDArray(const GrTDArray& src) { + fCount = fAllocated = src.fCount; + fArray = (T*)GrMalloc(fAllocated * sizeof(T)); + memcpy(fArray, src.fArray, fCount * sizeof(T)); + } + ~GrTDArray() { + if (fArray) { + GrFree(fArray); + } + } + + bool isEmpty() const { return 0 == fCount; } + int count() const { return fCount; } + + const T& at(int index) const { + GrAssert((unsigned)index < (unsigned)fCount); + return fArray[index]; + } + T& at(int index) { + GrAssert((unsigned)index < (unsigned)fCount); + return fArray[index]; + } + + const T& operator[](int index) const { return this->at(index); } + T& operator[](int index) { return this->at(index); } + + GrTDArray& operator=(const GrTDArray& src) { + if (fAllocated < src.fCount) { + fAllocated = src.fCount; + GrFree(fArray); + fArray = (T*)GrMalloc(fAllocated * sizeof(T)); + } + fCount = src.fCount; + memcpy(fArray, src.fArray, fCount * sizeof(T)); + return *this; + } + + void reset() { + if (fArray) { + GrFree(fArray); + fArray = NULL; + } + fAllocated = fCount = 0; + } + + T* begin() const { return fArray; } + T* end() const { return fArray + fCount; } + T* back() const { GrAssert(fCount); return fArray + (fCount - 1); } + + T* prepend() { + this->growAt(0); + return fArray; + } + + T* append() { + this->growAt(fCount); + return fArray + fCount - 1; + } + + /** + * index may be [0..count], so that you can insert at the end (like append) + */ + T* insert(int index) { + GrAssert((unsigned)index <= (unsigned)fCount); + this->growAt(index); + return fArray + index; + } + + void remove(int index) { + GrAssert((unsigned)index < (unsigned)fCount); + fCount -= 1; + if (index < fCount) { + int remaining = fCount - index; + memmove(fArray + index, fArray + index + 1, remaining * sizeof(T)); + } + } + + void removeShuffle(int index) { + GrAssert((unsigned)index < (unsigned)fCount); + fCount -= 1; + if (index < fCount) { + memmove(fArray + index, fArray + fCount, sizeof(T)); + } + } + + // Utility iterators + + /** + * Calls GrFree() on each element. Assumes each is NULL or was allocated + * with GrMalloc(). + */ + void freeAll() { + T* stop = this->end(); + for (T* curr = this->begin(); curr < stop; curr++) { + GrFree(*curr); + } + this->reset(); + } + + /** + * Calls delete on each element. Assumes each is NULL or was allocated + * with new. + */ + void deleteAll() { + T* stop = this->end(); + for (T* curr = this->begin(); curr < stop; curr++) { + delete *curr; + } + this->reset(); + } + + /** + * Calls GrSafeUnref() on each element. Assumes each is NULL or is a + * subclass of GrRefCnt. + */ + void unrefAll() { + T* stop = this->end(); + for (T* curr = this->begin(); curr < stop; curr++) { + GrSafeUnref(*curr); + } + this->reset(); + } + + void visit(void visitor(T&)) const { + T* stop = this->end(); + for (T* curr = this->begin(); curr < stop; curr++) { + if (*curr) { + visitor(*curr); + } + } + } + + int find(const T& elem) const { + int count = this->count(); + T* curr = this->begin(); + for (int i = 0; i < count; i++) { + if (elem == curr[i]) { + return i; + } + } + return -1; + } + + friend bool operator==(const GrTDArray<T>& a, const GrTDArray<T>& b) { + return a.count() == b.count() && + (0 == a.count() || + 0 == memcmp(a.begin(), b.begin(), a.count() * sizeof(T))); + } + friend bool operator!=(const GrTDArray<T>& a, const GrTDArray<T>& b) { + return !(a == b); + } + +private: + T* fArray; + int fAllocated, fCount; + + // growAt will increment fCount, reallocate fArray (as needed), and slide + // the contents of fArray to make a hole for new data at index. + void growAt(int index) { + GrAssert(fCount <= fAllocated); + if (0 == fAllocated) { + fAllocated = GrInitialArrayAllocationCount(); + fArray = (T*)GrMalloc(fAllocated * sizeof(T)); + } else if (fCount == fAllocated) { + fAllocated = GrNextArrayAllocationCount(fAllocated); + T* newArray = (T*)GrMalloc(fAllocated * sizeof(T)); + memcpy(newArray, fArray, index * sizeof(T)); + memcpy(newArray + index + 1, fArray + index, + (fCount - index) * sizeof(T)); + GrFree(fArray); + fArray = newArray; + } else { + // check that we're not just appending + if (index < fCount) { + memmove(fArray + index + 1, fArray + index, + (fCount - index) * sizeof(T)); + } + } + GrAssert(fCount < fAllocated); + fCount += 1; + } +}; + +extern void* GrTDArray_growAt(void*, int* allocated, int& count, int index, + size_t); + + +#endif + diff --git a/src/gpu/GrTHashCache.h b/src/gpu/GrTHashCache.h new file mode 100644 index 0000000000..8651c35c22 --- /dev/null +++ b/src/gpu/GrTHashCache.h @@ -0,0 +1,219 @@ + +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef GrTHashCache_DEFINED +#define GrTHashCache_DEFINED + +#include "GrTDArray.h" + +/** + * Key needs + * static bool EQ(const Entry&, const HashKey&); + * static bool LT(const Entry&, const HashKey&); + * uint32_t getHash() const; + * + * Allows duplicate key entries but on find you may get + * any of the duplicate entries returned. + */ +template <typename T, typename Key, size_t kHashBits> class GrTHashTable { +public: + GrTHashTable() { Gr_bzero(fHash, sizeof(fHash)); } + ~GrTHashTable() {} + + int count() const { return fSorted.count(); } + T* find(const Key&) const; + // return true if key was unique when inserted. + bool insert(const Key&, T*); + void remove(const Key&, const T*); + T* removeAt(int index, uint32_t hash); + void removeAll(); + void deleteAll(); + void unrefAll(); + + /** + * Return the index for the element, using a linear search. + */ + int slowFindIndex(T* elem) const { return fSorted.find(elem); } + +#if GR_DEBUG + void validate() const; + bool contains(T*) const; +#endif + + // testing + const GrTDArray<T*>& getArray() const { return fSorted; } +private: + enum { + kHashCount = 1 << kHashBits, + kHashMask = kHashCount - 1 + }; + static unsigned hash2Index(uint32_t hash) { + hash ^= hash >> 16; + if (kHashBits <= 8) { + hash ^= hash >> 8; + } + return hash & kHashMask; + } + + mutable T* fHash[kHashCount]; + GrTDArray<T*> fSorted; + + // search fSorted, and return the found index, or ~index of where it + // should be inserted + int searchArray(const Key&) const; +}; + +/////////////////////////////////////////////////////////////////////////////// + +template <typename T, typename Key, size_t kHashBits> +int GrTHashTable<T, Key, kHashBits>::searchArray(const Key& key) const { + int count = fSorted.count(); + if (0 == count) { + // we should insert it at 0 + return ~0; + } + + const T* const* array = fSorted.begin(); + int high = count - 1; + int low = 0; + while (high > low) { + int index = (low + high) >> 1; + if (Key::LT(*array[index], key)) { + low = index + 1; + } else { + high = index; + } + } + + // check if we found it + if (Key::EQ(*array[high], key)) { + // above search should have found the first occurrence if there + // are multiple. + GrAssert(0 == high || Key::LT(*array[high - 1], key)); + return high; + } + + // now return the ~ of where we should insert it + if (Key::LT(*array[high], key)) { + high += 1; + } + return ~high; +} + +template <typename T, typename Key, size_t kHashBits> +T* GrTHashTable<T, Key, kHashBits>::find(const Key& key) const { + int hashIndex = hash2Index(key.getHash()); + T* elem = fHash[hashIndex]; + + if (NULL == elem || !Key::EQ(*elem, key)) { + // bsearch for the key in our sorted array + int index = this->searchArray(key); + if (index < 0) { + return NULL; + } + elem = fSorted[index]; + // update the hash + fHash[hashIndex] = elem; + } + return elem; +} + +template <typename T, typename Key, size_t kHashBits> +bool GrTHashTable<T, Key, kHashBits>::insert(const Key& key, T* elem) { + int index = this->searchArray(key); + bool first = index < 0; + if (first) { + // turn it into the actual index + index = ~index; + } + // add it to our array + *fSorted.insert(index) = elem; + // update our hash table (overwrites any dupe's position in the hash) + fHash[hash2Index(key.getHash())] = elem; + return first; +} + +template <typename T, typename Key, size_t kHashBits> +void GrTHashTable<T, Key, kHashBits>::remove(const Key& key, const T* elem) { + int index = hash2Index(key.getHash()); + if (fHash[index] == elem) { + fHash[index] = NULL; + } + + // remove from our sorted array + index = this->searchArray(key); + GrAssert(index >= 0); + // if there are multiple matches searchArray will give us the first match + // march forward until we find elem. + while (elem != fSorted[index]) { + ++index; + GrAssert(index < fSorted.count()); + } + GrAssert(elem == fSorted[index]); + fSorted.remove(index); +} + +template <typename T, typename Key, size_t kHashBits> +T* GrTHashTable<T, Key, kHashBits>::removeAt(int elemIndex, uint32_t hash) { + int hashIndex = hash2Index(hash); + if (fHash[hashIndex] == fSorted[elemIndex]) { + fHash[hashIndex] = NULL; + } + // remove from our sorted array + T* elem = fSorted[elemIndex]; + fSorted.remove(elemIndex); + return elem; +} + +template <typename T, typename Key, size_t kHashBits> +void GrTHashTable<T, Key, kHashBits>::removeAll() { + fSorted.reset(); + Gr_bzero(fHash, sizeof(fHash)); +} + +template <typename T, typename Key, size_t kHashBits> +void GrTHashTable<T, Key, kHashBits>::deleteAll() { + fSorted.deleteAll(); + Gr_bzero(fHash, sizeof(fHash)); +} + +template <typename T, typename Key, size_t kHashBits> +void GrTHashTable<T, Key, kHashBits>::unrefAll() { + fSorted.unrefAll(); + Gr_bzero(fHash, sizeof(fHash)); +} + +#if GR_DEBUG +template <typename T, typename Key, size_t kHashBits> +void GrTHashTable<T, Key, kHashBits>::validate() const { + for (size_t i = 0; i < GR_ARRAY_COUNT(fHash); i++) { + if (fHash[i]) { + unsigned hashIndex = hash2Index(Key::GetHash(*fHash[i])); + GrAssert(hashIndex == i); + } + } + + int count = fSorted.count(); + for (int i = 1; i < count; i++) { + GrAssert(Key::LT(*fSorted[i - 1], *fSorted[i]) || + Key::EQ(*fSorted[i - 1], *fSorted[i])); + } +} + +template <typename T, typename Key, size_t kHashBits> +bool GrTHashTable<T, Key, kHashBits>::contains(T* elem) const { + int index = fSorted.find(elem); + return index >= 0; +} + +#endif + +#endif + diff --git a/src/gpu/GrTLList.h b/src/gpu/GrTLList.h new file mode 100644 index 0000000000..ea310ac20e --- /dev/null +++ b/src/gpu/GrTLList.h @@ -0,0 +1,54 @@ + +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef GrTLList_DEFINED +#define GrTLList_DEFINED + +#include "GrNoncopyable.h" + +template <typename T> class GrTLList : GrNoncopyable { +public: + class Entry { + Entry* fPrev; + Entry* fNext; + }; + + GrTLList() : fHead(NULL), fTail(NULL) {} +#if GR_DEBUG + ~GrTLList() { + GrAssert(NULL == fHead); + GrAssert(NULL == ftail); + } +#endif + + T* head() const { return fHead; } + T* tail() const { return fTail; } + + void addToHead(T*); + void addToTail(T*); + void removeFromList(T*); + +private: + Entry* fHead; + Entry* fTail; + + friend class Entry; +}; + + +class Parent { + GrTDLList<Child> fList; +}; + +class Child : public GrTLList::Entry<Child> { +}; + +#endif + diff --git a/src/gpu/GrTextStrike.h b/src/gpu/GrTextStrike.h new file mode 100644 index 0000000000..701acea7ab --- /dev/null +++ b/src/gpu/GrTextStrike.h @@ -0,0 +1,115 @@ + +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef GrTextStrike_DEFINED +#define GrTextStrike_DEFINED + +#include "GrAllocPool.h" +#include "GrFontScaler.h" +#include "GrTHashCache.h" +#include "GrPoint.h" +#include "GrGlyph.h" + +class GrAtlasMgr; +class GrFontCache; +class GrGpu; +class GrFontPurgeListener; + +/** + * The textcache maps a hostfontscaler instance to a dictionary of + * glyphid->strike + */ +class GrTextStrike { +public: + GrTextStrike(GrFontCache*, const GrKey* fontScalerKey, GrMaskFormat, + GrAtlasMgr*); + ~GrTextStrike(); + + const GrKey* getFontScalerKey() const { return fFontScalerKey; } + GrFontCache* getFontCache() const { return fFontCache; } + GrMaskFormat getMaskFormat() const { return fMaskFormat; } + + inline GrGlyph* getGlyph(GrGlyph::PackedID, GrFontScaler*); + bool getGlyphAtlas(GrGlyph*, GrFontScaler*); + + // testing + int countGlyphs() const { return fCache.getArray().count(); } + const GrGlyph* glyphAt(int index) const { + return fCache.getArray()[index]; + } + GrAtlas* getAtlas() const { return fAtlas; } + +public: + // for LRU + GrTextStrike* fPrev; + GrTextStrike* fNext; + +private: + class Key; + GrTHashTable<GrGlyph, Key, 7> fCache; + const GrKey* fFontScalerKey; + GrTAllocPool<GrGlyph> fPool; + + GrFontCache* fFontCache; + GrAtlasMgr* fAtlasMgr; + GrAtlas* fAtlas; // linklist + + GrMaskFormat fMaskFormat; + + GrGlyph* generateGlyph(GrGlyph::PackedID packed, GrFontScaler* scaler); + // returns true if after the purge, the strike is empty + bool purgeAtlasAtY(GrAtlas* atlas, int yCoord); + + friend class GrFontCache; +}; + +class GrFontCache { +public: + GrFontCache(GrGpu*); + ~GrFontCache(); + + inline GrTextStrike* getStrike(GrFontScaler*); + + void freeAll(); + + void purgeExceptFor(GrTextStrike*); + + // testing + int countStrikes() const { return fCache.getArray().count(); } + const GrTextStrike* strikeAt(int index) const { + return fCache.getArray()[index]; + } + GrTextStrike* getHeadStrike() const { return fHead; } + +#if GR_DEBUG + void validate() const; +#else + void validate() const {} +#endif + +private: + friend class GrFontPurgeListener; + + class Key; + GrTHashTable<GrTextStrike, Key, 8> fCache; + // for LRU + GrTextStrike* fHead; + GrTextStrike* fTail; + + GrGpu* fGpu; + GrAtlasMgr* fAtlasMgr; + + + GrTextStrike* generateStrike(GrFontScaler*, const Key&); + inline void detachStrikeFromList(GrTextStrike*); +}; + +#endif + diff --git a/src/gpu/ios/SkUIView.mm b/src/gpu/ios/SkUIView.mm deleted file mode 100644 index 261ed9ca1f..0000000000 --- a/src/gpu/ios/SkUIView.mm +++ /dev/null @@ -1,827 +0,0 @@ -#import "SkUIView.h" -#include <QuartzCore/QuartzCore.h> - -//#include "SkGpuCanvas.h" -#include "SkGpuDevice.h" -#include "SkCGUtils.h" -#include "GrContext.h" - -#define SKWIND_CONFIG SkBitmap::kRGB_565_Config -//#define SKWIND_CONFIG SkBitmap::kARGB_8888_Config -#define SKGL_CONFIG kEAGLColorFormatRGB565 -//#define SKGL_CONFIG kEAGLColorFormatRGBA8 - -#define SHOW_FPS -#define FORCE_REDRAW -//#define DUMP_FPS_TO_PRINTF - -//#define USE_ACCEL_TO_ROTATE - -//#define SHOULD_COUNTER_INIT 334 -static int gShouldCounter; -static bool should_draw() { - if (--gShouldCounter == 0) { - // printf("\n"); - } - return true; - return gShouldCounter >= 0; -} -#ifdef SHOULD_COUNTER_INIT - bool (*gShouldDrawProc)() = should_draw; -#else - bool (*gShouldDrawProc)() = NULL; -#endif - -//#define USE_GL_1 -//#define USE_GL_2 - -#if defined(USE_GL_1) || defined(USE_GL_2) - #define USE_GL -#endif - -@implementation SkUIView - - -@synthesize fWind; -@synthesize fTitle; -@synthesize fBackend; -@synthesize fComplexClip; -@synthesize fUseWarp; - -#include "SkWindow.h" -#include "SkEvent.h" - -static float gScreenScale = 1; - -extern SkOSWindow* create_sk_window(void* hwnd, int argc, char** argv); - -#define kREDRAW_UIVIEW_GL "sk_redraw_uiview_gl_iOS" - -#define TITLE_HEIGHT 0 - -static const float SCALE_FOR_ZOOM_LENS = 4.0; -#define Y_OFFSET_FOR_ZOOM_LENS 200 -#define SIZE_FOR_ZOOM_LENS 250 - -static const float MAX_ZOOM_SCALE = 4.0; -static const float MIN_ZOOM_SCALE = 2.0 / MAX_ZOOM_SCALE; - -extern bool gDoTraceDraw; -#define DO_TRACE_DRAW_MAX 100 - -#ifdef SHOW_FPS -struct FPSState { - static const int FRAME_COUNT = 60; - - CFTimeInterval fNow0, fNow1; - CFTimeInterval fTime0, fTime1, fTotalTime; - int fFrameCounter; - int fDrawCounter; - - FPSState() { - fTime0 = fTime1 = fTotalTime = 0; - fFrameCounter = 0; - } - - void startDraw() { - fNow0 = CACurrentMediaTime(); - - if (0 == fDrawCounter && false) { - gDoTraceDraw = true; - SkDebugf("\n"); - } - } - - void endDraw() { - fNow1 = CACurrentMediaTime(); - - if (0 == fDrawCounter) { - gDoTraceDraw = true; - } - if (DO_TRACE_DRAW_MAX == ++fDrawCounter) { - fDrawCounter = 0; - } - } - - void flush(SkOSWindow* wind) { - CFTimeInterval now2 = CACurrentMediaTime(); - - fTime0 += fNow1 - fNow0; - fTime1 += now2 - fNow1; - - if (++fFrameCounter == FRAME_COUNT) { - CFTimeInterval totalNow = CACurrentMediaTime(); - fTotalTime = totalNow - fTotalTime; - - SkMSec ms0 = (int)(1000 * fTime0 / FRAME_COUNT); - SkMSec msTotal = (int)(1000 * fTotalTime / FRAME_COUNT); - - SkString str; - str.printf("ms: %d [%d], fps: %3.1f", msTotal, ms0, - FRAME_COUNT / fTotalTime); -#ifdef DUMP_FPS_TO_PRINTF - SkDebugf("%s\n", str.c_str()); -#else - wind->setTitle(str.c_str()); -#endif - - fTotalTime = totalNow; - fTime0 = fTime1 = 0; - fFrameCounter = 0; - } - } -}; - -static FPSState gFPS; - - #define FPS_StartDraw() gFPS.startDraw() - #define FPS_EndDraw() gFPS.endDraw() - #define FPS_Flush(wind) gFPS.flush(wind) -#else - #define FPS_StartDraw() - #define FPS_EndDraw() - #define FPS_Flush(wind) -#endif - -/////////////////////////////////////////////////////////////////////////////// - -#ifdef USE_GL -+ (Class) layerClass -{ - return [CAEAGLLayer class]; -} -#endif - -- (id)initWithMyDefaults { - fBackend = kGL_Backend; - fUseWarp = false; - fRedrawRequestPending = false; - // FIXME: If iOS has argc & argv, pass them here. - //fWind = create_sk_window(self, 0, NULL); - //fWind->setConfig(SKWIND_CONFIG); - fMatrix.reset(); - fLocalMatrix.reset(); - fNeedGestureEnded = false; - fNeedFirstPinch = true; - fZoomAround = false; - fComplexClip = false; - - [self initGestures]; - -#ifdef USE_GL - CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer; - eaglLayer.opaque = TRUE; - eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithBool:NO], - kEAGLDrawablePropertyRetainedBacking, - SKGL_CONFIG, - kEAGLDrawablePropertyColorFormat, - nil]; - -#ifdef USE_GL_1 - fGL.fContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1]; -#else - fGL.fContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; -#endif - - if (!fGL.fContext || ![EAGLContext setCurrentContext:fGL.fContext]) - { - [self release]; - return nil; - } - - // Create default framebuffer object. The backing will be allocated for the current layer in -resizeFromLayer - glGenFramebuffersOES(1, &fGL.fFramebuffer); - glBindFramebufferOES(GL_FRAMEBUFFER_OES, fGL.fFramebuffer); - - glGenRenderbuffersOES(1, &fGL.fRenderbuffer); - glGenRenderbuffersOES(1, &fGL.fStencilbuffer); - - glBindRenderbufferOES(GL_RENDERBUFFER_OES, fGL.fRenderbuffer); - glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, fGL.fRenderbuffer); - - glBindRenderbufferOES(GL_RENDERBUFFER_OES, fGL.fStencilbuffer); - glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_STENCIL_ATTACHMENT_OES, GL_RENDERBUFFER_OES, fGL.fStencilbuffer); -#endif - -#ifdef USE_ACCEL_TO_ROTATE - fRotateMatrix.reset(); - [UIAccelerometer sharedAccelerometer].delegate = self; - [UIAccelerometer sharedAccelerometer].updateInterval = 1 / 30.0; -#endif - return self; -} - -- (id)initWithCoder:(NSCoder*)coder { - if ((self = [super initWithCoder:coder])) { - self = [self initWithMyDefaults]; - } - return self; -} - -- (id)initWithFrame:(CGRect)frame { - if (self = [super initWithFrame:frame]) { - self = [self initWithMyDefaults]; - } - return self; -} - -#include "SkImageDecoder.h" -#include "SkStream_NSData.h" - -static void zoom_around(SkCanvas* canvas, float cx, float cy, float zoom) { - float clipW = SIZE_FOR_ZOOM_LENS; - float clipH = SIZE_FOR_ZOOM_LENS; - - SkRect r; - r.set(0, 0, clipW, clipH); - r.offset(cx - clipW/2, cy - clipH/2); - - SkPaint paint; - paint.setColor(0xFF66AAEE); - paint.setStyle(SkPaint::kStroke_Style); - paint.setStrokeWidth(10); - - // draw our "frame" around the zoom lens - canvas->drawRect(r, paint); - - // now clip and scale the lens - canvas->clipRect(r); - canvas->translate(cx, cy); - canvas->scale(zoom, zoom); - canvas->translate(-cx, -cy); -} - -- (void)drawWithCanvas:(SkCanvas*)canvas { - if (fComplexClip) { - canvas->drawColor(SK_ColorBLUE); - - SkPath path; - static const SkRect r[] = { - { 50, 50, 250, 250 }, - { 150, 150, 500, 600 } - }; - for (size_t i = 0; i < GR_ARRAY_COUNT(r); i++) { - path.addRect(r[i]); - } - canvas->clipPath(path); - } - - // This is to consolidate multiple inval requests - fRedrawRequestPending = false; - - if (fFlingState.isActive()) { - if (!fFlingState.evaluateMatrix(&fLocalMatrix)) { - [self flushLocalMatrix]; - } - } - - SkMatrix localMatrix = fLocalMatrix; -#ifdef USE_ACCEL_TO_ROTATE - localMatrix.preConcat(fRotateMatrix); -#endif - - SkMatrix matrix; - matrix.setConcat(localMatrix, fMatrix); - - const SkMatrix* localM = NULL; - if (localMatrix.getType() & SkMatrix::kScale_Mask) { - localM = &localMatrix; - } -#ifdef USE_ACCEL_TO_ROTATE - localM = &localMatrix; -#endif - canvas->setExternalMatrix(localM); - -#ifdef SHOULD_COUNTER_INIT - gShouldCounter = SHOULD_COUNTER_INIT; -#endif - { - int saveCount = canvas->save(); - canvas->concat(matrix); - // SkRect r = { 10, 10, 500, 600 }; canvas->clipRect(r); - fWind->draw(canvas); - canvas->restoreToCount(saveCount); - } - - if (fZoomAround) { - zoom_around(canvas, fZoomAroundX, fZoomAroundY, SCALE_FOR_ZOOM_LENS); - canvas->concat(matrix); - fWind->draw(canvas); - } - -#ifdef FORCE_REDRAW - fWind->inval(NULL); -#endif -} - -/////////////////////////////////////////////////////////////////////////////// - -- (void)layoutSubviews { - int W, H; - - gScreenScale = [UIScreen mainScreen].scale; - -#ifdef USE_GL - - CAEAGLLayer* eaglLayer = (CAEAGLLayer*)self.layer; - if ([self respondsToSelector:@selector(setContentScaleFactor:)]) { - self.contentScaleFactor = gScreenScale; - } - - // Allocate color buffer backing based on the current layer size - glBindRenderbufferOES(GL_RENDERBUFFER_OES, fGL.fRenderbuffer); - [fGL.fContext renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:eaglLayer]; - - glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &fGL.fWidth); - glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &fGL.fHeight); - - glBindRenderbufferOES(GL_RENDERBUFFER_OES, fGL.fStencilbuffer); - glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_STENCIL_INDEX8_OES, fGL.fWidth, fGL.fHeight); - - - if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) - { - NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES)); - } - - W = fGL.fWidth; - H = fGL.fHeight; -#else - CGRect rect = [self bounds]; - W = (int)CGRectGetWidth(rect); - H = (int)CGRectGetHeight(rect) - TITLE_HEIGHT; -#endif - - printf("---- layoutSubviews %d %d\n", W, H); - fWind->resize(W, H); - fWind->inval(NULL); -} - -#ifdef USE_GL - -static GrContext* gCtx; -static GrContext* get_global_grctx() { - // should be pthread-local at least - if (NULL == gCtx) { -#ifdef USE_GL_1 - gCtx = GrContext::Create(kOpenGL_Fixed_GrEngine, 0); -#else - gCtx = GrContext::Create(kOpenGL_Shaders_GrEngine, 0); -#endif - } - return gCtx; -} - -#include "SkDevice.h" -#include "SkShader.h" -#include "SkGrTexturePixelRef.h" -#include "GrMesh.h" -#include "SkRandom.h" - -#include "GrAtlas.h" -#include "GrTextStrike.h" - -static void show_fontcache(GrContext* ctx, SkCanvas* canvas) { -#if 0 - SkPaint paint; - const int SIZE = 64; - GrAtlas* plot[64][64]; - - paint.setAntiAlias(true); - paint.setTextSize(24); - paint.setTextAlign(SkPaint::kCenter_Align); - - Gr_bzero(plot, sizeof(plot)); - - GrFontCache* cache = ctx->getFontCache(); - GrTextStrike* strike = cache->getHeadStrike(); - int count = 0; - while (strike) { - GrAtlas* atlas = strike->getAtlas(); - while (atlas) { - int x = atlas->getPlotX(); - int y = atlas->getPlotY(); - - SkRandom rand((intptr_t)strike); - SkColor c = rand.nextU() | 0x80808080; - paint.setColor(c); - paint.setAlpha(0x80); - - SkRect r; - r.set(x * SIZE, y * SIZE, (x + 1)*SIZE, (y+1)*SIZE); - r.inset(1, 1); - canvas->drawRect(r, paint); - - paint.setColor(0xFF660000); - SkString label; - label.printf("%d", count); - canvas->drawText(label.c_str(), label.size(), r.centerX(), - r.fTop + r.height() * 2 / 3, paint); - - atlas = atlas->nextAtlas(); - } - strike = strike->fNext; - count += 1; - } -#endif -} - -void test_patch(SkCanvas* canvas, const SkBitmap& bm, SkScalar scale); - -static void draw_mesh(SkCanvas* canvas, const SkBitmap& bm) { - GrMesh fMesh; - - SkRect r; - r.set(0, 0, SkIntToScalar(bm.width()), SkIntToScalar(bm.height())); - - // fMesh.init(bounds, fBitmap.width() / 40, fBitmap.height() / 40, texture); - fMesh.init(r, bm.width()/16, bm.height()/16, r); - - SkPaint paint; - SkShader* s = SkShader::CreateBitmapShader(bm, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode); - paint.setShader(s)->unref(); - fMesh.draw(canvas, paint); -} - -static void scale_about(SkCanvas* canvas, float sx, float sy, float px, float py) { - canvas->translate(px, py); - canvas->scale(sx, sy); - canvas->translate(-px, -py); -} - -static float grInterp(float v0, float v1, float percent) { - return v0 + percent * (v1 - v0); -} - -static void draw_device(SkCanvas* canvas, SkDevice* dev, float w, float h, float warp) { - canvas->save(); - float s = grInterp(1, 0.8, warp); - scale_about(canvas, s, s, w/2, h/2); - test_patch(canvas, dev->accessBitmap(false), warp); - canvas->restore(); -} - -- (void)drawInGL { -// printf("------ drawInGL\n"); - // This application only creates a single context which is already set current at this point. - // This call is redundant, but needed if dealing with multiple contexts. - [EAGLContext setCurrentContext:fGL.fContext]; - - // This application only creates a single default framebuffer which is already bound at this point. - // This call is redundant, but needed if dealing with multiple framebuffers. - glBindFramebufferOES(GL_FRAMEBUFFER_OES, fGL.fFramebuffer); - - GLint scissorEnable; - glGetIntegerv(GL_SCISSOR_TEST, &scissorEnable); - glDisable(GL_SCISSOR_TEST); - glClearColor(0,0,0,0); - glClear(GL_COLOR_BUFFER_BIT); - if (scissorEnable) { - glEnable(GL_SCISSOR_TEST); - } - glViewport(0, 0, fWind->width(), fWind->height()); - - GrContext* ctx = get_global_grctx(); - - //SkGpuCanvas origCanvas(ctx); - //origCanvas.setBitmapDevice(fWind->getBitmap()); - //gl->reset(); - - SkCanvas glCanvas; - SkGpuDevice* dev = new SkGpuDevice(ctx, SkGpuDevice::Current3DApiRenderTarget()); - glCanvas.setDevice(dev)->unref(); - - SkCanvas rasterCanvas; - - SkCanvas* canvas; - //SkDevice* dev = NULL; - - switch (fBackend) { - case kRaster_Backend: - canvas = &rasterCanvas; - break; - case kGL_Backend: - canvas = &glCanvas; - break; - } - -// if (fUseWarp || fWarpState.isActive()) { -// if (kGL_Backend == fBackend) { -// dev = origCanvas.createDevice(fWind->getBitmap(), true); -// canvas->setDevice(dev)->unref(); -// } else { -// canvas->setBitmapDevice(fWind->getBitmap()); -// dev = canvas->getDevice(); -// } -// } else { -// canvas->setBitmapDevice(fWind->getBitmap()); -// dev = NULL; -// } - - canvas->translate(0, TITLE_HEIGHT); - - // if we're not "retained", then we have to always redraw everything. - // This call forces us to ignore the fDirtyRgn, and draw everywhere. - // If we are "retained", we can skip this call (as the raster case does) - fWind->forceInvalAll(); - - FPS_StartDraw(); - [self drawWithCanvas:canvas]; - FPS_EndDraw(); - -// if (dev) { -// draw_device(&origCanvas, dev, fWind->width(), fWind->height(), -// fWarpState.evaluate()); -// } else { -// if (kRaster_Backend == fBackend) { -// origCanvas.drawBitmap(fWind->getBitmap(), 0, 0, NULL); -// } -// // else GL - we're already on screen -// } - - show_fontcache(ctx, canvas); - ctx->flush(false); - - // This application only creates a single color renderbuffer which is already bound at this point. - // This call is redundant, but needed if dealing with multiple renderbuffers. - glBindRenderbufferOES(GL_RENDERBUFFER_OES, fGL.fRenderbuffer); - [fGL.fContext presentRenderbuffer:GL_RENDERBUFFER_OES]; - -#if GR_COLLECT_STATS - static int frame = 0; - if (!(frame % 100)) { - get_global_grctx()->printStats(); - } - get_global_grctx()->resetStats(); - ++frame; -#endif - - FPS_Flush(fWind); - -#if 0 - gCtx->deleteAllTextures(GrTextureCache::kAbandonTexture_DeleteMode); - gCtx->unref(); - gCtx = NULL; -#endif -} - -#else // raster case - -- (void)drawRect:(CGRect)rect { - SkCanvas canvas; - canvas.setBitmapDevice(fWind->getBitmap()); - FPS_StartDraw(); - [self drawWithCanvas:&canvas]; - FPS_EndDraw(); - - CGContextRef cg = UIGraphicsGetCurrentContext(); - SkCGDrawBitmap(cg, fWind->getBitmap(), 0, TITLE_HEIGHT); - - FPS_Flush(fWind); - -} -#endif - -- (void)setWarpState:(bool)useWarp { - fWarpState.stop(); // we should reverse from where we are if active... - - const float duration = 0.5; - fUseWarp = useWarp; - if (useWarp) { - fWarpState.start(0, 1, duration); - } else { - fWarpState.start(1, 0, duration); - } -} - -/////////////////////////////////////////////////////////////////////////////// - -- (void)flushLocalMatrix { - fMatrix.postConcat(fLocalMatrix); - fLocalMatrix.reset(); - fFlingState.stop(); - fNeedGestureEnded = false; - fNeedFirstPinch = true; -} - -- (void)localMatrixWithGesture:(UIGestureRecognizer*)gesture { - fNeedGestureEnded = true; - - switch (gesture.state) { - case UIGestureRecognizerStateCancelled: - case UIGestureRecognizerStateEnded: - [self flushLocalMatrix]; - break; - case UIGestureRecognizerStateChanged: { - SkMatrix matrix; - matrix.setConcat(fLocalMatrix, fMatrix); - } break; - default: - break; - } -} - -- (void)commonHandleGesture:(UIGestureRecognizer*)sender { - if (fFlingState.isActive()) { - [self flushLocalMatrix]; - } - - switch (sender.state) { - case UIGestureRecognizerStateBegan: - [self flushLocalMatrix]; - break; - default: - break; - } -} - -- (float)limitTotalZoom:(float)scale { - // this query works 'cause we know that we're square-scale w/ no skew/rotation - const float curr = fMatrix[0]; - - if (scale > 1 && curr * scale > MAX_ZOOM_SCALE) { - scale = MAX_ZOOM_SCALE / curr; - } else if (scale < 1 && curr * scale < MIN_ZOOM_SCALE) { - scale = MIN_ZOOM_SCALE / curr; - } - return scale; -} - -- (void)handleLongPressGesture:(UILongPressGestureRecognizer*)sender { - [self commonHandleGesture:sender]; - - if ([sender numberOfTouches] == 0) { - fZoomAround = false; - return; - } - - CGPoint pt = [sender locationOfTouch:0 inView:self]; - switch (sender.state) { - case UIGestureRecognizerStateBegan: - case UIGestureRecognizerStateChanged: - fZoomAround = true; - fZoomAroundX = pt.x; - fZoomAroundY = pt.y - Y_OFFSET_FOR_ZOOM_LENS; - break; - case UIGestureRecognizerStateEnded: - case UIGestureRecognizerStateCancelled: - fZoomAround = false; - break; - default: - break; - } -} - -- (void)addAndReleaseGesture:(UIGestureRecognizer*)gesture { - [self addGestureRecognizer:gesture]; - [gesture release]; -} - - - -//Gesture Handlers -- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { - for (UITouch *touch in touches) { - CGPoint loc = [touch locationInView:self]; - fWind->handleClick(loc.x, loc.y, SkView::Click::kDown_State, touch); - } -} - -- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { - for (UITouch *touch in touches) { - CGPoint loc = [touch locationInView:self]; - fWind->handleClick(loc.x, loc.y, SkView::Click::kMoved_State, touch); - } -} - -- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { - for (UITouch *touch in touches) { - CGPoint loc = [touch locationInView:self]; - fWind->handleClick(loc.x, loc.y, SkView::Click::kUp_State, touch); - } -} - -- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { - for (UITouch *touch in touches) { - CGPoint loc = [touch locationInView:self]; - fWind->handleClick(loc.x, loc.y, SkView::Click::kUp_State, touch); - } -} - -- (void)initGestures { - UILongPressGestureRecognizer* longG = [UILongPressGestureRecognizer alloc]; - [longG initWithTarget:self action:@selector(handleLongPressGesture:)]; - [self addAndReleaseGesture:longG]; -} - -/////////////////////////////////////////////////////////////////////////////// - -static float abs(float x) { return x < 0 ? -x : x; } - -static bool normalize(UIAcceleration* acc, float xy[]) { - float mag2 = acc.x*acc.x + acc.y*acc.y + acc.z*acc.z; - if (mag2 < 0.000001) { - return false; - } - if (abs((float)acc.z) > 0.9 * sqrt(mag2)) { - return false; - } - - mag2 = acc.x*acc.x + acc.y*acc.y; - if (mag2 < 0.000001) { - return false; - } - float scale = 1 / sqrt(mag2); - xy[0] = acc.x * scale; - xy[1] = acc.y * scale; - return true; -} - -static void normalize(float xy[]) { - float scale = 1 / sqrt(xy[0]*xy[0] + xy[1]*xy[1]); - xy[0] *= scale; - xy[1] *= scale; -} - -static float weighted_average(float newv, float oldv) { - return newv * 0.25 + oldv * 0.75; -} - -- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acc { - - float norm[2]; - if (normalize(acc, norm)) { - float sinv = -norm[0]; - float cosv = -norm[1]; - // smooth - norm[0] = weighted_average(sinv, -fRotateMatrix[1]); - norm[1] = weighted_average(cosv, fRotateMatrix[0]); - normalize(norm); - fRotateMatrix.setSinCos(norm[0], norm[1], 400, 400); - } -#if 0 - NSDate *now = [NSDate date]; - NSTimeInterval intervalDate = [now timeIntervalSinceDate:now_prev]; - - velX += (acceleration.x * intervalDate); - distX += (velX * intervalDate); - //do other axis here too - - // setup for next UIAccelerometer event - now_prev = now; -#endif -} - -/////////////////////////////////////////////////////////////////////////////// - -- (void)setSkTitle:(const char *)title { - if (fTitle) { - fTitle.title = [NSString stringWithUTF8String:title]; - } -} - -- (BOOL)onHandleEvent:(const SkEvent&)evt { - if (evt.isType(kREDRAW_UIVIEW_GL)) { - [self drawInGL]; - return true; - } - return false; -} - -- (void)postInvalWithRect:(const SkIRect*)r { -#ifdef USE_GL - -#if 1 - if (!fRedrawRequestPending) { - fRedrawRequestPending = true; - /* - performSelectorOnMainThread seems to starve updating other views - (e.g. our FPS view in the titlebar), so we use the afterDelay - version - */ - if (0) { - [self performSelectorOnMainThread:@selector(drawInGL) withObject:nil waitUntilDone:NO]; - } else { - [self performSelector:@selector(drawInGL) withObject:nil afterDelay:0]; - } - } -#else - if (!fRedrawRequestPending) { - SkEvent* evt = new SkEvent(kREDRAW_UIVIEW_GL); - evt->post(fWind->getSinkID()); - fRedrawRequestPending = true; - } -#endif - -#else - if (r) { - [self setNeedsDisplayInRect:CGRectMake(r->fLeft, r->fTop, - r->width(), r->height())]; - } else { - [self setNeedsDisplay]; - } -#endif -} - -@end |