aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llrender
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llrender
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to '')
-rw-r--r--linden/indra/llrender/files.darwin.lst1
-rw-r--r--linden/indra/llrender/files.lst8
-rw-r--r--linden/indra/llrender/llagpmempool.cpp194
-rw-r--r--linden/indra/llrender/llagpmempool.h121
-rw-r--r--linden/indra/llrender/llagpmempoolapple.cpp314
-rw-r--r--linden/indra/llrender/llagpmempoolapple.h95
-rw-r--r--linden/indra/llrender/llagpmempoolarb.cpp230
-rw-r--r--linden/indra/llrender/llagpmempoolarb.h103
-rw-r--r--linden/indra/llrender/llagpmempoolati.cpp160
-rw-r--r--linden/indra/llrender/llagpmempoolati.h92
-rw-r--r--linden/indra/llrender/llagpmempoolnv.cpp320
-rw-r--r--linden/indra/llrender/llagpmempoolnv.h95
-rw-r--r--linden/indra/llrender/llfont.cpp627
-rw-r--r--linden/indra/llrender/llfont.h188
-rw-r--r--linden/indra/llrender/llfontgl.cpp1453
-rw-r--r--linden/indra/llrender/llfontgl.h252
-rw-r--r--linden/indra/llrender/llgldbg.cpp224
-rw-r--r--linden/indra/llrender/llgldbg.h35
-rw-r--r--linden/indra/llrender/llimagegl.cpp1224
-rw-r--r--linden/indra/llrender/llimagegl.h204
-rw-r--r--linden/indra/llrender/llrender.vcproj230
-rw-r--r--linden/indra/llrender/llvertexprogramgl.cpp121
-rw-r--r--linden/indra/llrender/llvertexprogramgl.h51
-rw-r--r--linden/indra/llrender/text_out.cpp115
-rw-r--r--linden/indra/llrender/text_out.h40
25 files changed, 6497 insertions, 0 deletions
diff --git a/linden/indra/llrender/files.darwin.lst b/linden/indra/llrender/files.darwin.lst
new file mode 100644
index 0000000..2d27570
--- /dev/null
+++ b/linden/indra/llrender/files.darwin.lst
@@ -0,0 +1 @@
llrender/llagpmempoolapple.cpp
diff --git a/linden/indra/llrender/files.lst b/linden/indra/llrender/files.lst
new file mode 100644
index 0000000..e7b3cec
--- /dev/null
+++ b/linden/indra/llrender/files.lst
@@ -0,0 +1,8 @@
1llrender/llagpmempoolarb.cpp
2llrender/llagpmempool.cpp
3llrender/llfont.cpp
4llrender/llfontgl.cpp
5llrender/llgldbg.cpp
6llrender/llimagegl.cpp
7llrender/llvertexprogramgl.cpp
8llrender/text_out.cpp
diff --git a/linden/indra/llrender/llagpmempool.cpp b/linden/indra/llrender/llagpmempool.cpp
new file mode 100644
index 0000000..39cd3e8
--- /dev/null
+++ b/linden/indra/llrender/llagpmempool.cpp
@@ -0,0 +1,194 @@
1/**
2 * @file llagpmempool.cpp
3 * @brief LLAGPMemPool base class
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "linden_common.h"
29
30#include "llagpmempool.h"
31#include "llgl.h"
32
33#include "llagpmempoolarb.h"
34#include "llagpmempoolnv.h"
35#include "llagpmempoolati.h"
36
37#if LL_DARWIN
38#include "llagpmempoolapple.h"
39#endif // LL_DARWIN
40
41//static
42S32 LLAGPMemPool::LLFreeBlock::sNumBlocks = 0;
43
44LLAGPMemPool::LLAGPMemPool()
45{
46 mSize = 0;
47 mTotalAllocated = 0;
48}
49
50LLAGPMemPool::~LLAGPMemPool()
51{
52 mFreeList.deleteAll();
53}
54
55LLAGPMemPool *LLAGPMemPool::createPool(const U32 size, const BOOL use_vbo)
56{
57 if (gGLManager.mHasVertexBufferObject && use_vbo)
58 {
59 return new LLAGPMemPoolARB(size);
60 }
61#if LL_WINDOWS // *FIX: linux can use these, too, with some work.
62 if (gGLManager.mHasNVFence)
63 {
64 return new LLAGPMemPoolNV(size);
65 }
66 else if (gGLManager.mHasATIVAO)
67 {
68 return new LLAGPMemPoolATI(size);
69 }
70 else
71#elif LL_DARWIN
72 if (gGLManager.mHasAPPLEFence && gGLManager.mHasAPPLEVertexArrayRange)
73 {
74 return new LLAGPMemPoolAPPLE(size);
75 }
76 else
77#endif
78 {
79 // No AGP memory allocation at all!
80 return NULL;
81 }
82}
83
84
85LLAGPMemBlock *LLAGPMemPool::allocBlock(const S32 size)
86{
87 S32 aligned_size = size;
88 if (size & 0x0f)
89 {
90 aligned_size += 16 - (size & 0x0f);
91 }
92
93 if (aligned_size > (mSize - mTotalAllocated))
94 {
95 // We're totally out of AGP memory, bail.
96 return NULL;
97 }
98
99 LLFreeBlock *free_block = mFreeList.getFirst();
100
101 while (free_block && free_block->mSize < aligned_size)
102 {
103 free_block = free_block->getNext();
104 }
105
106 U32 offset = 0;
107
108 if (free_block)
109 {
110 if (free_block->mSize == aligned_size)
111 {
112 free_block->unlink();
113 offset = free_block->mOffset;
114 delete free_block;
115 }
116 else
117 {
118 offset = free_block->mOffset + free_block->mSize - aligned_size;
119 free_block->mSize -= aligned_size;
120 if (0 == free_block->mSize)
121 {
122 free_block->unlink();
123 }
124 }
125 }
126 else
127 {
128 //llwarns << "LLAGPMemPool unable to allocate " << size << " bytes" << llendl;
129 return NULL;
130 }
131
132 mTotalAllocated += aligned_size;
133 return createBlock(offset, aligned_size);
134}
135
136
137void LLAGPMemPool::freeBlock(LLAGPMemBlock *blockp)
138{
139 if (!blockp->getSize())
140 {
141 return;
142 }
143
144 LLFreeBlock *prev_free = NULL;
145 LLFreeBlock *cur_free = mFreeList.getFirst();
146
147 while (cur_free && blockp->getOffset() > (U32)cur_free->mOffset)
148 {
149 prev_free = cur_free;
150 cur_free = cur_free->getNext();
151 }
152
153 LLFreeBlock *new_free = new LLFreeBlock(blockp->getOffset(), blockp->getSize());
154
155 if (prev_free)
156 {
157 prev_free->append(*new_free);
158 coalesce(new_free);
159 coalesce(prev_free);
160 }
161 else
162 {
163 mFreeList.append(*new_free);
164 coalesce(new_free);
165 }
166 mTotalAllocated -= blockp->getSize();
167}
168
169void LLAGPMemPool::coalesce(LLFreeBlock *free_block)
170{
171 LLFreeBlock *next = free_block->getNext();
172
173 if (next && (free_block->mOffset + free_block->mSize == next->mOffset))
174 {
175 free_block->mSize += next->mSize;
176
177 next->unlink();
178 delete next;
179
180 coalesce(free_block);
181 }
182}
183
184void LLAGPMemPool::printFreeList()
185{
186 LLFreeBlock *cur_block = mFreeList.getFirst();
187 while (cur_block)
188 {
189 llinfos << "Cur block begin: " << cur_block->mOffset << llendl;
190 llinfos << "Cur block end: " << cur_block->mOffset + cur_block->mSize << llendl;
191 cur_block = cur_block->getNext();
192 }
193}
194
diff --git a/linden/indra/llrender/llagpmempool.h b/linden/indra/llrender/llagpmempool.h
new file mode 100644
index 0000000..f992876
--- /dev/null
+++ b/linden/indra/llrender/llagpmempool.h
@@ -0,0 +1,121 @@
1/**
2 * @file llagpmempool.h
3 * @brief LLAGPMemPool base class
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LL_LLAGPMEMPOOL_H
29#define LL_LLAGPMEMPOOL_H
30
31#include "stdtypes.h"
32#include "lldlinked.h"
33
34// Raw memory handling abstraction, which handles interaction with
35// the nVidia and ATI AGP extensions.
36
37// Minimum size we allow allocation for, in order to allow AGP usage...
38const S32 MIN_AGP_SIZE = 8000000;
39
40class LLAGPMemBlock;
41
42class LLAGPMemPool
43{
44public:
45 LLAGPMemPool();
46 virtual ~LLAGPMemPool();
47
48 virtual LLAGPMemBlock *allocBlock(const S32 size);
49 virtual void freeBlock(LLAGPMemBlock *blockp);
50
51 virtual void flush() = 0;
52 virtual void dump() = 0;
53 virtual void enable() = 0;
54 virtual void disable() = 0;
55 virtual void bind() = 0;
56
57 virtual S32 getSize() { return mSize; }
58
59 S32 getTotalAllocated() const { return mTotalAllocated; }
60 static LLAGPMemPool *createPool(const U32 size, const BOOL use_vbo);
61
62 struct LLFreeBlock: public LLDLinked<LLFreeBlock>
63 {
64 S32 mOffset;
65 S32 mSize;
66 LLFreeBlock(const S32 offset, const S32 size) { mOffset = offset; mSize = size; sNumBlocks++; }
67 ~LLFreeBlock() { sNumBlocks--; }
68
69 static S32 sNumBlocks;
70 };
71
72 // Fencing (for nVidia and Apple) - default is to do nothing (ATI, ARB do not need fencing)
73 virtual U32 createFence() { return 0; }
74 virtual void deleteFence(const U32 fence) {}
75 virtual void sendFence(U32 fence) {}
76 virtual void waitFence(U32 fence) {}
77
78 void printFreeList();
79protected:
80
81 void coalesce(LLFreeBlock *free_block);
82 virtual LLAGPMemBlock *createBlock(const U32 offset, const U32 size) = 0;
83 LLDLinked<LLFreeBlock> mFreeList;
84
85 S32 mSize;
86 S32 mTotalAllocated;
87};
88
89// An AGP memory block, which contains all the info needed to
90// copy data in/out.
91class LLAGPMemBlock
92{
93public:
94 LLAGPMemBlock(LLAGPMemPool *mem_poolp) : mMemPoolp(mem_poolp) {}
95 virtual ~LLAGPMemBlock() {}
96 virtual void copy (void *source, const U32 size_bytes) = 0;
97 virtual void copyColor(void *source, const U32 size_bytes) = 0;
98
99 virtual void bindGLVertexPointer(const U32 stride, const U32 offset) = 0;
100 virtual void bindGLNormalPointer(const U32 stride, const U32 offset) = 0;
101 virtual void bindGLBinormalPointer(const S32 index, const U32 stride, const U32 offset) = 0;
102 virtual void bindGLColorPointer(const U32 stride, const U32 offset) = 0;
103 virtual void bindGLTexCoordPointer(const U32 stride, const U32 offset) = 0;
104 virtual void bindGLVertexWeightPointer(const S32 index, const U32 stride, const U32 offset) = 0;
105 virtual void bindGLVertexClothingWeightPointer(const S32 index, const U32 stride, const U32 offset) = 0;
106
107 virtual BOOL hasMappedMem() const = 0;
108 virtual U8* getMappedMem() = 0;
109
110 virtual U32 createFence() = 0;
111 virtual void deleteFence(const U32 fence) = 0;
112 virtual void sendFence(U32 fence) = 0;
113 virtual void waitFence(U32 fence) = 0;
114
115 virtual U32 getOffset() const = 0;
116 virtual U32 getSize() const = 0;
117protected:
118 LLAGPMemPool *mMemPoolp;
119};
120
121#endif // LL_LLAGPMEMPOOL_H
diff --git a/linden/indra/llrender/llagpmempoolapple.cpp b/linden/indra/llrender/llagpmempoolapple.cpp
new file mode 100644
index 0000000..9aa4993
--- /dev/null
+++ b/linden/indra/llrender/llagpmempoolapple.cpp
@@ -0,0 +1,314 @@
1/**
2 * @file llagpmempoolapple.cpp
3 * @brief LLAGPMemPoolAPPLE base class
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifdef LL_DARWIN
29
30#include "linden_common.h"
31
32#include "llagpmempoolapple.h"
33#include "llgl.h"
34
35#include "llglheaders.h"
36
37LLAGPMemPoolAPPLE::LLAGPMemPoolAPPLE(S32 request) : LLAGPMemPool()
38{
39 llinfos << "Creating LLAGPMemPoolAPPLE" << llendl;
40 stop_glerror();
41 if (!gGLManager.mHasAPPLEFence || !gGLManager.mHasAPPLEVertexArrayRange)
42 {
43 llerrs << "necessary extensions not present!" << llendl;
44 }
45
46 // No special allocation is necessary for the Apple extensions
47 mBase = (U8*)::malloc(request);
48 mSize = request;
49
50 if (mBase)
51 {
52 mFreeList.append(*(new LLFreeBlock(0,mSize)));
53 }
54 else
55 {
56 mSize = 0;
57 }
58
59 flush_glerror();
60}
61
62LLAGPMemBlockAPPLE::~LLAGPMemBlockAPPLE()
63{
64 mMemPoolp->freeBlock(this);
65}
66
67LLAGPMemBlock *LLAGPMemPoolAPPLE::createBlock(const U32 offset, const U32 size)
68{
69 return new LLAGPMemBlockAPPLE(this, mBase, offset, size);
70}
71
72LLAGPMemPoolAPPLE::~LLAGPMemPoolAPPLE()
73{
74 if (mBase)
75 {
76 // MBW -- This really belongs in a call which is the opposite of bind()...
77 glVertexArrayRangeAPPLE(0, 0);
78 ::free(mBase);
79 }
80}
81
82void LLAGPMemPoolAPPLE::bind()
83{
84 if(mBase)
85 {
86 glVertexArrayRangeAPPLE(mSize, mBase);
87 }
88}
89
90void LLAGPMemPoolAPPLE::enable()
91{
92 glEnableClientState(GL_VERTEX_ARRAY_RANGE_APPLE);
93}
94
95void LLAGPMemPoolAPPLE::disable()
96{
97 glDisableClientState(GL_VERTEX_ARRAY_RANGE_APPLE);
98}
99
100void LLAGPMemPoolAPPLE::flush()
101{
102 if(mBase)
103 {
104 glFlushVertexArrayRangeAPPLE(mSize, mBase);
105 }
106}
107
108void LLAGPMemPoolAPPLE::dump()
109{
110 LLFreeBlock *prev = 0;
111 LLFreeBlock *block = mFreeList.getFirst();
112
113 int d=0;
114
115 int i=0;
116 while (block)
117 {
118 i++;
119 if (prev)
120 {
121 d = (S32)block->mOffset - ((S32)prev->mOffset + prev->mSize);
122 }
123 else d = 0;
124
125 prev = block;
126 block = block->getNext();
127 }
128}
129
130
131U32 LLAGPMemPoolAPPLE::createFence()
132{
133 U32 fence;
134 glGenFencesAPPLE(1, (GLuint*)&fence);
135 glSetFenceAPPLE(fence);
136 glFinishFenceAPPLE(fence);
137 return fence;
138}
139
140
141void LLAGPMemPoolAPPLE::deleteFence(const U32 fence)
142{
143 glDeleteFencesAPPLE(1, (GLuint*)&fence);
144}
145
146
147void LLAGPMemPoolAPPLE::sendFence(U32 fence)
148{
149 glSetFenceAPPLE(fence);
150}
151
152
153void LLAGPMemPoolAPPLE::waitFence(U32 fence)
154{
155 if(!glTestFenceAPPLE(fence))
156 {
157 glFinishFenceAPPLE(fence);
158 }
159}
160
161
162/////////////////////////////
163//
164// LLAGPMemBlockAPPLE
165//
166// APPLE Implementation of an AGP memory block
167//
168
169LLAGPMemBlockAPPLE::LLAGPMemBlockAPPLE(LLAGPMemPool *mem_poolp, U8 *baseptr, S32 offset, const U32 size) : LLAGPMemBlock(mem_poolp)
170{
171 mMemp = baseptr + offset;
172 mOffset = offset;
173 mSize = size;
174}
175
176
177void LLAGPMemBlockAPPLE::bindGLVertexPointer(const U32 stride, const U32 offset)
178{
179 if (!mMemp)
180 {
181 llerrs << "Binding empty vertex array" << llendl;
182 }
183 glVertexPointer(3, GL_FLOAT, stride, mMemp + offset);
184}
185
186void LLAGPMemBlockAPPLE::bindGLNormalPointer(const U32 stride, const U32 offset)
187{
188 if (!mMemp)
189 {
190 llerrs << "Binding empty normal array" << llendl;
191 }
192 glNormalPointer(GL_FLOAT, stride, mMemp + offset);
193}
194
195
196void LLAGPMemBlockAPPLE::bindGLColorPointer(const U32 stride, const U32 offset)
197{
198 if (!mMemp)
199 {
200 llerrs << "Binding empty color array" << llendl;
201 }
202 glColorPointer(4, GL_UNSIGNED_BYTE, stride, mMemp + offset);
203}
204
205
206void LLAGPMemBlockAPPLE::bindGLTexCoordPointer(const U32 stride, const U32 offset)
207{
208 if (!mMemp)
209 {
210 llerrs << "Binding empty texcoord array" << llendl;
211 }
212 glTexCoordPointer(2, GL_FLOAT, stride, mMemp + offset);
213}
214
215
216void LLAGPMemBlockAPPLE::bindGLBinormalPointer(const S32 index, const U32 stride, const U32 offset)
217{
218 if (!mMemp)
219 {
220 llerrs << "Binding empty vertex weight array" << llendl;
221 }
222
223 if (index > 0) glVertexAttribPointerARB(index, 3, GL_FLOAT, FALSE, stride, (F32 *)(mMemp + offset));
224}
225
226void LLAGPMemBlockAPPLE::bindGLVertexWeightPointer(const S32 index, const U32 stride, const U32 offset)
227{
228 if (!mMemp)
229 {
230 llerrs << "Binding empty vertex weight array" << llendl;
231 }
232
233 if (index > 0) glVertexAttribPointerARB(index, 1, GL_FLOAT, FALSE, 0, (F32 *)(mMemp + offset));
234}
235
236void LLAGPMemBlockAPPLE::bindGLVertexClothingWeightPointer(const S32 index, const U32 stride, const U32 offset)
237{
238 if (!mMemp)
239 {
240 llerrs << "Binding empty vertex weight array" << llendl;
241 }
242 set_vertex_clothing_weights(index, stride, (LLVector4 *)(mMemp + offset));
243}
244
245U8* LLAGPMemBlockAPPLE::getMappedMem()
246{
247 return mMemp;
248}
249
250
251void LLAGPMemBlockAPPLE::copy(void *mem, const U32 size)
252{
253 if (!mMemp || !mem)
254 {
255 return;
256 }
257 llassert(size <= mSize);
258
259 memcpy( mMemp, mem, size );
260
261 glFlushVertexArrayRangeAPPLE(size, mMemp);
262}
263
264void LLAGPMemBlockAPPLE::copyColor(void *mem, const U32 size)
265{
266 if (!mMemp || !mem)
267 {
268 return;
269 }
270 llassert(size <= mSize);
271
272 memcpy( mMemp, mem, size );
273
274 glFlushVertexArrayRangeAPPLE(size, mMemp);
275}
276
277
278
279U32 LLAGPMemBlockAPPLE::createFence()
280{
281 U32 fence;
282 glGenFencesAPPLE(1, (GLuint*)&fence);
283 glSetFenceAPPLE(fence);
284 glFinishFenceAPPLE(fence);
285 return fence;
286}
287
288void LLAGPMemBlockAPPLE::deleteFence(const U32 fence)
289{
290 glDeleteFencesAPPLE(1, (GLuint*)&fence);
291}
292
293void LLAGPMemBlockAPPLE::sendFence(U32 fence)
294{
295 glSetFenceAPPLE(fence);
296}
297
298void LLAGPMemBlockAPPLE::waitFence(U32 fence)
299{
300 if(!glTestFenceAPPLE(fence))
301 {
302 glFinishFenceAPPLE(fence);
303 }
304}
305
306// MBW -- May want this at some point...
307#if 0
308void LLAGPMemBlockAPPLE::flush()
309{
310 glFlushVertexArrayRangeAPPLE(mSize, mMemp);
311}
312#endif
313
314#endif // LL_DARWIN
diff --git a/linden/indra/llrender/llagpmempoolapple.h b/linden/indra/llrender/llagpmempoolapple.h
new file mode 100644
index 0000000..4a72a28
--- /dev/null
+++ b/linden/indra/llrender/llagpmempoolapple.h
@@ -0,0 +1,95 @@
1/**
2 * @file llagpmempoolapple.h
3 * @brief LLAGPMemPoolAPPLE base class
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LL_LLAGPMEMPOOLAPPLE_H
29#define LL_LLAGPMEMPOOLAPPLE_H
30
31#include "llagpmempool.h"
32
33#if LL_DARWIN
34class LLAGPMemPoolAPPLE : public LLAGPMemPool
35{
36public:
37 LLAGPMemPoolAPPLE(S32 request);
38 virtual ~LLAGPMemPoolAPPLE();
39
40 /*virtual*/ void flush();
41 /*virtual*/ void dump();
42 /*virtual*/ void enable();
43 /*virtual*/ void disable();
44 /*virtual*/ void bind();
45
46 /*virtual*/ U32 createFence();
47 /*virtual*/ void deleteFence(const U32 fence);
48 /*virtual*/ void sendFence(U32 fence);
49 /*virtual*/ void waitFence(U32 fence);
50
51protected:
52 /*virtual*/ LLAGPMemBlock *createBlock(const U32 offset, const U32 size);
53
54protected:
55 U8 *mBase;
56};
57
58class LLAGPMemBlockAPPLE : public LLAGPMemBlock
59{
60public:
61 LLAGPMemBlockAPPLE(LLAGPMemPool *mem_poolp, U8 *baseptr, const S32 offset, const U32 size);
62 virtual ~LLAGPMemBlockAPPLE();
63
64 /*virtual*/ void copy (void *source, const U32 size_bytes);
65 /*virtual*/ void copyColor(void *source, const U32 size_bytes);
66 /*virtual*/ void free();
67
68 /*virtual*/ void bindGLVertexPointer(const U32 stride, const U32 offset);
69 /*virtual*/ void bindGLNormalPointer(const U32 stride, const U32 offset);
70 /*virtual*/ void bindGLBinormalPointer(const S32 index, const U32 stride, const U32 offset);
71 /*virtual*/ void bindGLColorPointer(const U32 stride, const U32 offset);
72 /*virtual*/ void bindGLTexCoordPointer(const U32 stride, const U32 offset);
73 /*virtual*/ void bindGLVertexWeightPointer(const S32 index, const U32 stride, const U32 offset);
74 /*virtual*/ void bindGLVertexClothingWeightPointer(const S32 index, const U32 stride, const U32 offset);
75
76 /*virtual*/ U32 getOffset() const { return mOffset; }
77 /*virtual*/ U32 getSize() const { return mSize; }
78
79 /*virtual*/ BOOL hasMappedMem() const { return TRUE; }
80 /*virtual*/ U8* getMappedMem();
81 /*virtual*/ U32 createFence();
82 /*virtual*/ void deleteFence(const U32 fence);
83 /*virtual*/ void sendFence(U32 fence);
84 /*virtual*/ void waitFence(U32 fence);
85
86private:
87 U8 *mMemp;
88 U32 mOffset; // Offset from base
89 U32 mSize;
90 friend class LLAGPMemPoolAPPLE;
91};
92
93#endif // LL_DARWIN
94
95#endif // LL_LLAGPMEMPOOLAPPLE_H
diff --git a/linden/indra/llrender/llagpmempoolarb.cpp b/linden/indra/llrender/llagpmempoolarb.cpp
new file mode 100644
index 0000000..ab97c97
--- /dev/null
+++ b/linden/indra/llrender/llagpmempoolarb.cpp
@@ -0,0 +1,230 @@
1/**
2 * @file llagpmempoolarb.cpp
3 * @brief LLAGPMemPoolARB base class
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "linden_common.h"
29#include "llagpmempoolarb.h"
30#include "llgl.h"
31
32#include "llglheaders.h"
33
34LLAGPMemPoolARB::LLAGPMemPoolARB(S32 request) : LLAGPMemPool()
35{
36 llinfos << "Creating LLAGPMemPoolARB" << llendl;
37 stop_glerror();
38 if (!gGLManager.mHasVertexBufferObject)
39 {
40 llerrs << "No ARB vertex buffer object extension!" << llendl;
41 }
42
43 mName = 0;
44
45 mSize = request;
46 flush_glerror();
47}
48
49
50LLAGPMemPoolARB::~LLAGPMemPoolARB()
51{
52}
53
54
55LLAGPMemBlock* LLAGPMemPoolARB::allocBlock(const S32 size)
56{
57 return allocBlock(size, GL_ARRAY_BUFFER_ARB);
58}
59
60LLAGPMemBlock *LLAGPMemPoolARB::allocBlock(const S32 size, U32 target)
61{
62 S32 aligned_size = size;
63 if (size & 0x0f)
64 {
65 aligned_size += 16 - (size & 0x0f);
66 }
67
68 if (aligned_size > (mSize - mTotalAllocated))
69 {
70 // We're totally out of AGP memory, bail.
71 return (LLAGPMemBlock *)0;
72 }
73
74 mTotalAllocated += aligned_size;
75 return createBlock(0, aligned_size, target);
76}
77
78
79void LLAGPMemPoolARB::freeBlock(LLAGPMemBlock *blockp)
80{
81 if (!blockp->getSize())
82 {
83 return;
84 }
85 LLAGPMemBlockARB *arb_blockp = (LLAGPMemBlockARB*)blockp;
86 U32 name[1];
87 name[0] = arb_blockp->getName();
88 stop_glerror();
89 glDeleteBuffersARB(1, (GLuint*)name);
90 stop_glerror();
91 mTotalAllocated -= blockp->getSize();
92}
93
94LLAGPMemBlock *LLAGPMemPoolARB::createBlock(const U32 offset, const U32 size)
95{
96 return createBlock(offset, size, GL_ARRAY_BUFFER_ARB);
97}
98
99LLAGPMemBlock *LLAGPMemPoolARB::createBlock(const U32 offset, const U32 size, const U32 target)
100{
101 U32 name[1];
102 stop_glerror();
103 glGenBuffersARB(1, (GLuint*)name);
104 stop_glerror();
105 return new LLAGPMemBlockARB(this, name[0], offset, size, target);
106}
107
108void LLAGPMemPoolARB::disable()
109{
110}
111
112void LLAGPMemPoolARB::dump()
113{
114}
115
116
117/////////////////////////////
118//
119// LLAGPMemBlockARB
120//
121// ARB ImplementARBon of an AGP memory block
122//
123
124LLAGPMemBlockARB::LLAGPMemBlockARB(LLAGPMemPool *mem_poolp, const U32 name, const U32 offset, const U32 size, U32 target) :
125 LLAGPMemBlock(mem_poolp), mTarget(target)
126{
127 llassert(name > 0);
128 mName = name;
129 stop_glerror();
130 glBindBufferARB(mTarget, mName);
131 stop_glerror();
132
133 glBufferDataARB(mTarget, size, NULL, GL_DYNAMIC_DRAW_ARB);
134
135 stop_glerror();
136 glBindBufferARB(mTarget, 0);
137 stop_glerror();
138 mSize = size;
139}
140
141
142void LLAGPMemBlockARB::bindGLVertexPointer(const U32 stride, const U32 offset)
143{
144 stop_glerror();
145 glBindBufferARB(mTarget, mName);
146 glVertexPointer(3, GL_FLOAT, stride, (GLvoid*)((intptr_t)offset));
147 glBindBufferARB(mTarget, 0);
148}
149
150
151void LLAGPMemBlockARB::bindGLNormalPointer(const U32 stride, const U32 offset)
152{
153 stop_glerror();
154 glBindBufferARB(mTarget, mName);
155 glNormalPointer(GL_FLOAT, stride, (GLvoid*)((intptr_t)offset));
156 glBindBufferARB(mTarget, 0);
157 stop_glerror();
158}
159
160
161void LLAGPMemBlockARB::bindGLColorPointer(const U32 stride, const U32 offset)
162{
163 stop_glerror();
164 glBindBufferARB(mTarget, mName);
165 glColorPointer(4, GL_UNSIGNED_BYTE, stride, (GLvoid*)((intptr_t)offset));
166 glBindBufferARB(mTarget, 0);
167 stop_glerror();
168}
169
170
171void LLAGPMemBlockARB::bindGLTexCoordPointer(const U32 stride, const U32 offset)
172{
173 stop_glerror();
174 glBindBufferARB(mTarget, mName);
175 glTexCoordPointer(2, GL_FLOAT, stride, (GLvoid*)((intptr_t)offset));
176 glBindBufferARB(mTarget, 0);
177 stop_glerror();
178}
179
180
181void LLAGPMemBlockARB::bindGLVertexWeightPointer(const S32 index, const U32 stride, const U32 offset)
182{
183 stop_glerror();
184 glBindBufferARB(mTarget, mName);
185 set_vertex_weights(index, (F32*)(intptr_t)offset);
186 glBindBufferARB(mTarget, 0);
187 stop_glerror();
188}
189
190void LLAGPMemBlockARB::bindGLBinormalPointer(const S32 index, const U32 stride, const U32 offset)
191{
192 stop_glerror();
193 glBindBufferARB(mTarget, mName);
194 set_binormals(index, stride, (LLVector3*)(intptr_t)offset);
195 glBindBufferARB(mTarget, 0);
196 stop_glerror();
197}
198
199
200void LLAGPMemBlockARB::bindGLVertexClothingWeightPointer(const S32 index, const U32 stride, const U32 offset)
201{
202 return;
203}
204
205
206void LLAGPMemBlockARB::copy(void *mem, const U32 size)
207{
208 stop_glerror();
209 llassert(size <= mSize);
210 glBindBufferARB(mTarget, mName);
211 glBufferSubDataARB(mTarget, 0, size, mem);
212 glBindBufferARB(mTarget, 0);
213 stop_glerror();
214}
215
216void LLAGPMemBlockARB::copyColor(void *mem, const U32 size)
217{
218 stop_glerror();
219 llassert(size <= mSize);
220 glBindBufferARB(mTarget, mName);
221 glBufferSubDataARB(mTarget, 0, size, mem);
222 glBindBufferARB(mTarget, 0);
223 stop_glerror();
224}
225
226
227U8* LLAGPMemBlockARB::getMappedMem()
228{
229 return NULL;
230}
diff --git a/linden/indra/llrender/llagpmempoolarb.h b/linden/indra/llrender/llagpmempoolarb.h
new file mode 100644
index 0000000..7358862
--- /dev/null
+++ b/linden/indra/llrender/llagpmempoolarb.h
@@ -0,0 +1,103 @@
1/**
2 * @file llagpmempoolarb.h
3 * @brief LLAGPMemPoolARB base class
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LL_LLAGPMEMPOOLARB_H
29#define LL_LLAGPMEMPOOLARB_H
30
31#include "llagpmempool.h"
32
33class LLAGPMemPoolARB : public LLAGPMemPool
34{
35public:
36 LLAGPMemPoolARB(S32 request);
37 virtual ~LLAGPMemPoolARB();
38
39 /*virtual*/ LLAGPMemBlock* allocBlock(const S32 size);
40 LLAGPMemBlock *allocBlock(const S32 size, U32 target);
41 /*virtual*/ void freeBlock(LLAGPMemBlock *blockp);
42
43 void bind() {}
44
45 void enable() {}
46
47 /*virtual*/ void disable();
48
49 void flush() {}
50
51 // No point in these being inline, is there? They're virtual functions anyway...
52 /*virtual*/ inline LLAGPMemBlock *alloc(S32 size);
53 /*virtual*/ inline void free(LLAGPMemBlock *block);
54 /*virtual*/ inline void dump();
55protected:
56 /*virtual*/ LLAGPMemBlock *createBlock(const U32 offset, const U32 size);
57 LLAGPMemBlock *createBlock(const U32 offset, const U32 size, const U32 target);
58
59protected:
60 U32 mName;
61};
62
63class LLAGPMemBlockARB : public LLAGPMemBlock
64{
65public:
66 LLAGPMemBlockARB(LLAGPMemPool *mem_poolp, const U32 name, const U32 offset, const U32 size, U32 target);
67 virtual ~LLAGPMemBlockARB() { mMemPoolp->freeBlock(this); };
68
69 /*virtual*/ void copy (void *source, const U32 size_bytes);
70 /*virtual*/ void copyColor(void *source, const U32 size_bytes);
71 /*virtual*/ void free();
72
73 /*virtual*/ void bind();
74 /*virtual*/ void unbind();
75
76 /*virtual*/ void bindGLVertexPointer(const U32 stride, const U32 offset);
77 /*virtual*/ void bindGLNormalPointer(const U32 stride, const U32 offset);
78 /*virtual*/ void bindGLBinormalPointer(const S32 index, const U32 stride, const U32 offset);
79 /*virtual*/ void bindGLColorPointer(const U32 stride, const U32 offset);
80 /*virtual*/ void bindGLTexCoordPointer(const U32 stride, const U32 offset);
81 /*virtual*/ void bindGLVertexWeightPointer(const S32 index, const U32 stride, const U32 offset);
82 /*virtual*/ void bindGLVertexClothingWeightPointer(const S32 index, const U32 stride, const U32 offset);
83
84 /*virtual*/ U32 getOffset() const { return 0; }
85 /*virtual*/ U32 getSize() const { return mSize; }
86
87 /*virtual*/ BOOL hasMappedMem() const { return FALSE; }
88 /*virtual*/ U8* getMappedMem();
89 /*virtual*/ U32 createFence() { return 0; }
90 /*virtual*/ void deleteFence(const U32 fence) {}
91 /*virtual*/ void sendFence(U32 fence) { }
92 /*virtual*/ void waitFence(U32 fence) { }
93
94 U32 getName() const { return mName; }
95private:
96 U32 mName;
97 U32 mSize;
98 U32 mTarget;
99
100 friend class LLAGPMemPoolARB;
101};
102
103#endif // LL_LLAGPMEMPOOLARB_H
diff --git a/linden/indra/llrender/llagpmempoolati.cpp b/linden/indra/llrender/llagpmempoolati.cpp
new file mode 100644
index 0000000..f29db95
--- /dev/null
+++ b/linden/indra/llrender/llagpmempoolati.cpp
@@ -0,0 +1,160 @@
1/**
2 * @file llagpmempoolati.cpp
3 * @brief LLAGPMemPoolATI base class
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "linden_common.h"
29
30#include "llagpmempoolati.h"
31#include "llgl.h"
32
33#include "llglheaders.h"
34
35LLAGPMemPoolATI::LLAGPMemPoolATI(S32 request) : LLAGPMemPool()
36{
37 llinfos << "Creating LLAGPMemPoolATI" << llendl;
38 stop_glerror();
39 if (!gGLManager.mHasATIVAO)
40 {
41 llerrs << "No ATI AGI memory extension!" << llendl;
42 }
43
44 mName = 0;
45
46 // More than 4MB of agp available
47 while (!mName && (request > 0))
48 {
49 mName = glNewObjectBufferATI(request, NULL, GL_DYNAMIC_ATI);
50 mSize = request;
51 request >>= 1;
52 }
53
54 if (mName)
55 {
56 mFreeList.append(*(new LLFreeBlock(0, mSize)));
57 }
58 else
59 {
60 llinfos << "Unable to allocate AGP memory!" << llendl;
61 mSize = 0;
62 }
63 flush_glerror();
64}
65
66
67LLAGPMemPoolATI::~LLAGPMemPoolATI()
68{
69 if (mName)
70 {
71 glFreeObjectBufferATI(mName);
72 }
73}
74
75
76LLAGPMemBlock *LLAGPMemPoolATI::createBlock(const U32 offset, const U32 size)
77{
78 return new LLAGPMemBlockATI(this, mName, offset, size);
79}
80
81
82void LLAGPMemPoolATI::dump()
83{
84}
85
86
87/////////////////////////////
88//
89// LLAGPMemBlockATI
90//
91// ATI Implementation of an AGP memory block
92//
93
94LLAGPMemBlockATI::LLAGPMemBlockATI(LLAGPMemPool *mem_poolp, const U32 name, const U32 offset, const U32 size) :
95 LLAGPMemBlock(mem_poolp)
96{
97 mName = name;
98 mOffset = offset;
99 mSize = size;
100}
101
102
103void LLAGPMemBlockATI::bindGLVertexPointer(const U32 stride, const U32 offset)
104{
105 glArrayObjectATI(GL_VERTEX_ARRAY, 3, GL_FLOAT, stride, mName, mOffset + offset);
106}
107
108
109void LLAGPMemBlockATI::bindGLNormalPointer(const U32 stride, const U32 offset)
110{
111 glArrayObjectATI(GL_NORMAL_ARRAY, 3, GL_FLOAT, stride, mName, mOffset + offset);
112}
113
114
115void LLAGPMemBlockATI::bindGLColorPointer(const U32 stride, const U32 offset)
116{
117 glArrayObjectATI(GL_COLOR_ARRAY, 4, GL_UNSIGNED_BYTE, stride, mName, mOffset + offset);
118}
119
120
121void LLAGPMemBlockATI::bindGLTexCoordPointer(const U32 stride, const U32 offset)
122{
123 glArrayObjectATI(GL_TEXTURE_COORD_ARRAY, 2, GL_FLOAT, stride, mName, mOffset + offset);
124}
125
126
127void LLAGPMemBlockATI::bindGLBinormalPointer(const S32 index, const U32 stride, const U32 offset)
128{
129 glVertexAttribArrayObjectATI(index, 3, GL_FLOAT, FALSE, stride, mName, mOffset + offset);
130}
131
132
133void LLAGPMemBlockATI::bindGLVertexWeightPointer(const S32 index, const U32 stride, const U32 offset)
134{
135 //glArrayObjectATI(GL_WEIGHT_ARRAY_ARB, 1, GL_FLOAT, stride, mName, mOffset + offset);
136 glVertexAttribArrayObjectATI(index, 1, GL_FLOAT, FALSE, stride, mName, mOffset + offset);
137}
138
139void LLAGPMemBlockATI::bindGLVertexClothingWeightPointer(const S32 index, const U32 stride, const U32 offset)
140{
141 glVertexAttribArrayObjectATI(index, 4, GL_FLOAT, FALSE, stride, mName, mOffset + offset);
142}
143
144U8* LLAGPMemBlockATI::getMappedMem()
145{
146 return NULL;
147}
148
149void LLAGPMemBlockATI::copy(void *mem, const U32 size)
150{
151 llassert(size <= mSize);
152 glUpdateObjectBufferATI(mName, mOffset, size, mem, GL_PRESERVE_ATI);
153}
154
155void LLAGPMemBlockATI::copyColor(void *mem, const U32 size)
156{
157 llassert(size <= mSize);
158 glUpdateObjectBufferATI(mName, mOffset, size, mem, GL_PRESERVE_ATI);
159}
160
diff --git a/linden/indra/llrender/llagpmempoolati.h b/linden/indra/llrender/llagpmempoolati.h
new file mode 100644
index 0000000..67803f6
--- /dev/null
+++ b/linden/indra/llrender/llagpmempoolati.h
@@ -0,0 +1,92 @@
1/**
2 * @file llagpmempoolati.h
3 * @brief LLAGPMemPoolATI base class
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LL_LLAGPMEMPOOLATI_H
29#define LL_LLAGPMEMPOOLATI_H
30
31#include "llagpmempool.h"
32
33class LLAGPMemPoolATI : public LLAGPMemPool
34{
35public:
36 LLAGPMemPoolATI(S32 request);
37 virtual ~LLAGPMemPoolATI();
38
39 void bind() {}
40
41 void enable() {}
42
43 void disable() {}
44
45 void flush() {}
46
47 // No point in these being inline, is there? They're virtual functions anyway...
48 /*virtual*/ inline LLAGPMemBlock *alloc(S32 size);
49 /*virtual*/ inline void free(LLAGPMemBlock *block);
50 /*virtual*/ inline void dump();
51protected:
52 /*virtual*/ LLAGPMemBlock *createBlock(const U32 offset, const U32 size);
53
54protected:
55 U32 mName;
56};
57
58class LLAGPMemBlockATI : public LLAGPMemBlock
59{
60public:
61 LLAGPMemBlockATI(LLAGPMemPool *mem_poolp, const U32 name, const U32 offset, const U32 size);
62 virtual ~LLAGPMemBlockATI() { mMemPoolp->freeBlock(this); };
63
64 /*virtual*/ void copy (void *source, const U32 size_bytes);
65 /*virtual*/ void copyColor(void *source, const U32 size_bytes);
66 /*virtual*/ void free();
67 /*virtual*/ void bindGLVertexPointer(const U32 stride, const U32 offset);
68 /*virtual*/ void bindGLNormalPointer(const U32 stride, const U32 offset);
69 /*virtual*/ void bindGLBinormalPointer(const S32 index, const U32 stride,const U32 offset);
70 /*virtual*/ void bindGLColorPointer(const U32 stride, const U32 offset);
71 /*virtual*/ void bindGLTexCoordPointer(const U32 stride, const U32 offset);
72 /*virtual*/ void bindGLVertexWeightPointer(const S32 index, const U32 stride, const U32 offset);
73 /*virtual*/ void bindGLVertexClothingWeightPointer(const S32 index, const U32 stride, const U32 offset);
74
75 /*virtual*/ U32 getOffset() const { return mOffset; }
76 /*virtual*/ U32 getSize() const { return mSize; }
77
78 /*virtual*/ BOOL hasMappedMem() const { return TRUE; }
79 /*virtual*/ U8* getMappedMem();
80 /*virtual*/ U32 createFence() { return 0; }
81 /*virtual*/ void deleteFence(const U32 fence) {}
82 /*virtual*/ void sendFence(U32 fence) { }
83 /*virtual*/ void waitFence(U32 fence) { }
84private:
85 U32 mName;
86 U32 mOffset;
87 U32 mSize;
88
89 friend class LLAGPMemPoolATI;
90};
91
92#endif // LL_LLAGPMEMPOOLATI_H
diff --git a/linden/indra/llrender/llagpmempoolnv.cpp b/linden/indra/llrender/llagpmempoolnv.cpp
new file mode 100644
index 0000000..8bbaef9
--- /dev/null
+++ b/linden/indra/llrender/llagpmempoolnv.cpp
@@ -0,0 +1,320 @@
1/**
2 * @file llagpmempoolnv.cpp
3 * @brief LLAGPMemPoolNV base class
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "linden_common.h"
29
30#ifndef LL_LINUX
31
32#include "llagpmempoolnv.h"
33#include "llgl.h"
34
35#include "llglheaders.h"
36
37#if LL_WINDOWS
38//#define LL_USE_NEW_MEM_OPS 1
39#endif
40#if LL_USE_NEW_MEM_OPS
41#include "new_mem_ops.h"
42#endif
43
44BOOL LLAGPMemPoolNV::sWriteOK = TRUE;
45
46LLAGPMemPoolNV::LLAGPMemPoolNV(int request) : LLAGPMemPool()
47{
48 llinfos << "Creating LLAGPMemPoolNV" << llendl;
49 stop_glerror();
50 if (!gGLManager.mHasNVFence)
51 {
52 llerrs << "wglAllocateMemoryNV not defined!" << llendl;
53 }
54
55 mBase = 0;
56
57 if (!mBase)
58 {
59 // More than 4MB of AGP available
60 while (!mBase && (request > 0))
61 {
62 // Stupid arbitrary nVidia magic numbers.
63 // read freq, write freq, priority
64 // AGP: 0.0, 0.1, 0.5
65 // Video: 0.0, 0.1, 1.0
66 mBase = (U8*)wglAllocateMemoryNV(request, 0.0f, 0.1f, 0.5f);
67 mSize = request;
68 request >>= 1;
69 }
70 }
71
72 if (mBase)
73 {
74 mFreeList.append(*(new LLFreeBlock(0,mSize)));
75 }
76 else
77 {
78 mSize = 0;
79 }
80
81 sWriteOK = TRUE;
82 flush_glerror();
83}
84
85
86LLAGPMemBlock *LLAGPMemPoolNV::createBlock(const U32 offset, const U32 size)
87{
88 return new LLAGPMemBlockNV(this, mBase, offset, size);
89}
90
91LLAGPMemPoolNV::~LLAGPMemPoolNV()
92{
93 if (mBase)
94 {
95 wglFreeMemoryNV(mBase);
96 }
97}
98
99void LLAGPMemPoolNV::bind()
100{
101 glVertexArrayRangeNV(mSize, mBase);
102}
103
104void LLAGPMemPoolNV::enable()
105{
106 glEnableClientState(GL_VERTEX_ARRAY_RANGE_NV);
107 sWriteOK = FALSE;
108}
109
110void LLAGPMemPoolNV::disable()
111{
112 glDisableClientState(GL_VERTEX_ARRAY_RANGE_NV);
113 sWriteOK = TRUE;
114}
115
116void LLAGPMemPoolNV::flush()
117{
118 glFlushVertexArrayRangeNV();
119}
120
121U32 LLAGPMemPoolNV::createFence()
122{
123 U32 fence;
124 glGenFencesNV(1, &fence);
125 glSetFenceNV(fence, GL_ALL_COMPLETED_NV);
126 glFinishFenceNV(fence);
127 return fence;
128}
129
130void LLAGPMemPoolNV::deleteFence(const U32 fence)
131{
132 glDeleteFencesNV(1, &fence);
133}
134
135void LLAGPMemPoolNV::sendFence(U32 fence)
136{
137 glSetFenceNV(fence, GL_ALL_COMPLETED_NV);
138}
139
140void LLAGPMemPoolNV::waitFence(U32 fence)
141{
142 if(!glTestFenceNV(fence))
143 {
144 glFinishFenceNV(fence);
145 }
146}
147
148
149//static
150BOOL LLAGPMemPoolNV::isWriteOK()
151{
152 return sWriteOK;
153}
154
155void LLAGPMemPoolNV::dump()
156{
157 LLFreeBlock *prev = 0;
158 LLFreeBlock *block = mFreeList.getFirst();
159
160 int d=0;
161
162 int i=0;
163 while (block)
164 {
165 i++;
166 if (prev)
167 {
168 d = (S32)block->mOffset - ((S32)prev->mOffset + prev->mSize);
169 }
170 else d = 0;
171
172 prev = block;
173 block = block->getNext();
174 }
175}
176
177
178LLAGPMemBlockNV::LLAGPMemBlockNV(LLAGPMemPool *mem_poolp, U8 *baseptr, S32 offset, const U32 size) : LLAGPMemBlock(mem_poolp)
179{
180 mMemp = baseptr + offset;
181 mOffset = offset;
182 mSize = size;
183}
184
185extern U8* gAGPVertices;
186
187void LLAGPMemBlockNV::bindGLVertexPointer(const U32 stride, const U32 offset)
188{
189 if (!mMemp)
190 {
191 llerrs << "Binding empty vertex array" << llendl;
192 }
193 glVertexPointer(3, GL_FLOAT, stride, mMemp + offset);
194}
195
196void LLAGPMemBlockNV::bindGLNormalPointer(const U32 stride, const U32 offset)
197{
198 if (!mMemp)
199 {
200 llerrs << "Binding empty normal array" << llendl;
201 }
202 glNormalPointer(GL_FLOAT, stride, mMemp + offset);
203}
204
205
206void LLAGPMemBlockNV::bindGLColorPointer(const U32 stride, const U32 offset)
207{
208 if (!mMemp)
209 {
210 llerrs << "Binding empty color array" << llendl;
211 }
212 glColorPointer(4, GL_UNSIGNED_BYTE, stride, mMemp + offset);
213}
214
215
216void LLAGPMemBlockNV::bindGLTexCoordPointer(const U32 stride, const U32 offset)
217{
218 if (!mMemp)
219 {
220 llerrs << "Binding empty texcoord array" << llendl;
221 }
222 glTexCoordPointer(2, GL_FLOAT, stride, mMemp + offset);
223}
224
225
226void LLAGPMemBlockNV::bindGLBinormalPointer(const S32 index, const U32 stride, const U32 offset)
227{
228 if (!mMemp)
229 {
230 llerrs << "Binding empty vertex weight array" << llendl;
231 }
232
233 glVertexAttribPointerARB(index, 3, GL_FLOAT, FALSE, stride, (F32 *)(mMemp + offset));
234}
235
236void LLAGPMemBlockNV::bindGLVertexWeightPointer(const S32 index, const U32 stride, const U32 offset)
237{
238 if (!mMemp)
239 {
240 llerrs << "Binding empty vertex weight array" << llendl;
241 }
242
243 glVertexAttribPointerARB(index, 1, GL_FLOAT, FALSE, 0, (F32 *)(mMemp + offset));
244}
245
246void LLAGPMemBlockNV::bindGLVertexClothingWeightPointer(const S32 index, const U32 stride, const U32 offset)
247{
248 if (!mMemp)
249 {
250 llerrs << "Binding empty vertex weight array" << llendl;
251 }
252 set_vertex_clothing_weights(index, stride, (LLVector4 *)(mMemp + offset));
253}
254
255U8* LLAGPMemBlockNV::getMappedMem()
256{
257 return mMemp;
258}
259
260void LLAGPMemBlockNV::copy(void *mem, const U32 size)
261{
262 if (!mMemp || !mem)
263 {
264 return;
265 }
266 llassert(LLAGPMemPoolNV::isWriteOK());
267 llassert(size <= mSize);
268
269#if LL_USE_NEW_MEM_OPS
270 inline_new_memcpy( mMemp, mem, size );
271#else
272 memcpy( mMemp, mem, size );
273#endif
274}
275
276void LLAGPMemBlockNV::copyColor(void *mem, const U32 size)
277{
278 if (!mMemp || !mem)
279 {
280 return;
281 }
282 llassert(LLAGPMemPoolNV::isWriteOK());
283 llassert(size <= mSize);
284
285#if LL_USE_NEW_MEM_OPS
286 inline_new_memcpy( mMemp, mem, size );
287#else
288 memcpy( mMemp, mem, size );
289#endif
290}
291
292
293U32 LLAGPMemBlockNV::createFence()
294{
295 U32 fence;
296 glGenFencesNV(1, &fence);
297 glSetFenceNV(fence, GL_ALL_COMPLETED_NV);
298 glFinishFenceNV(fence);
299 return fence;
300}
301
302void LLAGPMemBlockNV::deleteFence(const U32 fence)
303{
304 glDeleteFencesNV(1, &fence);
305}
306
307void LLAGPMemBlockNV::sendFence(U32 fence)
308{
309 glSetFenceNV(fence, GL_ALL_COMPLETED_NV);
310}
311
312void LLAGPMemBlockNV::waitFence(U32 fence)
313{
314 if(!glTestFenceNV(fence))
315 {
316 glFinishFenceNV(fence);
317 }
318}
319
320#endif //LL_LINUX
diff --git a/linden/indra/llrender/llagpmempoolnv.h b/linden/indra/llrender/llagpmempoolnv.h
new file mode 100644
index 0000000..cffe397
--- /dev/null
+++ b/linden/indra/llrender/llagpmempoolnv.h
@@ -0,0 +1,95 @@
1/**
2 * @file llagpmempoolnv.h
3 * @brief LLAGPMemPoolNV base class
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LL_LLAGPMEMPOOLNV_H
29#define LL_LLAGPMEMPOOLNV_H
30
31#include "llagpmempool.h"
32
33class LLAGPMemPoolNV : public LLAGPMemPool
34{
35public:
36 LLAGPMemPoolNV(int request);
37 virtual ~LLAGPMemPoolNV();
38
39 /*virtual*/ void flush();
40 /*virtual*/ void dump();
41 /*virtual*/ void enable();
42 /*virtual*/ void disable();
43 /*virtual*/ void bind();
44
45 static BOOL isWriteOK();
46
47 /*virtual*/ U32 createFence();
48 /*virtual*/ void deleteFence(const U32 fence);
49 /*virtual*/ void sendFence(U32 fence);
50 /*virtual*/ void waitFence(U32 fence);
51protected:
52 /*virtual*/ LLAGPMemBlock *createBlock(const U32 offset, const U32 size);
53
54protected:
55 U8 *mBase;
56
57 static BOOL sWriteOK;
58};
59
60class LLAGPMemBlockNV : public LLAGPMemBlock
61{
62public:
63 LLAGPMemBlockNV(LLAGPMemPool *mem_poolp, U8 *baseptr, const S32 offset, const U32 size);
64 virtual ~LLAGPMemBlockNV() { mMemPoolp->freeBlock(this); };
65
66 /*virtual*/ void copy (void *source, const U32 size_bytes);
67 /*virtual*/ void copyColor(void *source, const U32 size_bytes);
68 /*virtual*/ void free();
69
70 /*virtual*/ void bindGLVertexPointer(const U32 stride, const U32 offset);
71 /*virtual*/ void bindGLNormalPointer(const U32 stride, const U32 offset);
72 /*virtual*/ void bindGLBinormalPointer(const S32 index, const U32 stride, const U32 offset);
73 /*virtual*/ void bindGLColorPointer(const U32 stride, const U32 offset);
74 /*virtual*/ void bindGLTexCoordPointer(const U32 stride, const U32 offset);
75 /*virtual*/ void bindGLVertexWeightPointer(const S32 index, const U32 stride, const U32 offset);
76 /*virtual*/ void bindGLVertexClothingWeightPointer(const S32 index, const U32 stride, const U32 offset);
77
78 /*virtual*/ U32 getOffset() const { return mOffset; }
79 /*virtual*/ U32 getSize() const { return mSize; }
80
81 /*virtual*/ BOOL hasMappedMem() const { return TRUE; }
82 /*virtual*/ U8* getMappedMem();
83 /*virtual*/ U32 createFence();
84 /*virtual*/ void deleteFence(const U32 fence);
85 /*virtual*/ void sendFence(U32 fence);
86 /*virtual*/ void waitFence(U32 fence);
87
88private:
89 U8 *mMemp;
90 U32 mOffset; // Offset from base
91 U32 mSize;
92 friend class LLAGPMemPoolNV;
93};
94
95#endif // LL_LLAGPMEMPOOLNV_H
diff --git a/linden/indra/llrender/llfont.cpp b/linden/indra/llrender/llfont.cpp
new file mode 100644
index 0000000..c64744e
--- /dev/null
+++ b/linden/indra/llrender/llfont.cpp
@@ -0,0 +1,627 @@
1/**
2 * @file llfont.cpp
3 * @brief Font library wrapper
4 *
5 * Copyright (c) 2002-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "linden_common.h"
29
30#include "llfont.h"
31
32// Freetype stuff
33#if LL_LINUX // I had to do some work to avoid the system-installed FreeType headers... --ryan.
34#include "llfreetype2/freetype/ft2build.h"
35#else
36#include <ft2build.h>
37#endif
38
39// For some reason, this won't work if it's not wrapped in the ifdef
40#ifdef FT_FREETYPE_H
41#include FT_FREETYPE_H
42#endif
43
44#include "llerror.h"
45#include "llimage.h"
46//#include "llimagej2c.h"
47#include "llmath.h" // Linden math
48#include "llstring.h"
49//#include "imdebug.h"
50
51FT_Render_Mode gFontRenderMode = FT_RENDER_MODE_NORMAL;
52
53LLFontManager *gFontManagerp = NULL;
54
55FT_Library gFTLibrary = NULL;
56
57//static
58void LLFontManager::initClass()
59{
60 gFontManagerp = new LLFontManager;
61}
62
63//static
64void LLFontManager::cleanupClass()
65{
66 delete gFontManagerp;
67 gFontManagerp = NULL;
68}
69
70LLFontManager::LLFontManager()
71{
72 int error;
73 error = FT_Init_FreeType(&gFTLibrary);
74 if (error)
75 {
76 // Clean up freetype libs.
77 llerrs << "Freetype initialization failure!" << llendl;
78 FT_Done_FreeType(gFTLibrary);
79 }
80}
81
82
83LLFontManager::~LLFontManager()
84{
85 FT_Done_FreeType(gFTLibrary);
86}
87
88
89LLFontGlyphInfo::LLFontGlyphInfo(U32 index)
90{
91 mGlyphIndex = index;
92 mXBitmapOffset = 0; // Offset to the origin in the bitmap
93 mYBitmapOffset = 0; // Offset to the origin in the bitmap
94 mXBearing = 0; // Distance from baseline to left in pixels
95 mYBearing = 0; // Distance from baseline to top in pixels
96 mWidth = 0; // In pixels
97 mHeight = 0; // In pixels
98 mXAdvance = 0.f; // In pixels
99 mYAdvance = 0.f; // In pixels
100 mIsRendered = FALSE;
101}
102
103LLFontList::LLFontList()
104{
105}
106
107LLFontList::~LLFontList()
108{
109 LLFontList::iterator iter;
110 for(iter = this->begin(); iter != this->end(); iter++)
111 {
112 delete *iter;
113 // The (now dangling) pointers in the vector will be cleaned up when the vector is deleted by the superclass destructor.
114 }
115}
116void LLFontList::addAtEnd(LLFont *font)
117{
118 // Purely a convenience function
119 this->push_back(font);
120}
121
122LLFont::LLFont(LLImageRaw *imagep)
123 : mRawImagep(imagep)
124{
125 mValid = FALSE;
126 mAscender = 0.f;
127 mDescender = 0.f;
128 mLineHeight = 0.f;
129 mBitmapWidth = 0;
130 mBitmapHeight = 0;
131 mCurrentOffsetX = 1;
132 mCurrentOffsetY = 1;
133 mMaxCharWidth = 0;
134 mMaxCharHeight = 0;
135 mNumComponents = 0;
136 mFallbackFontp = NULL;
137 mIsFallback = FALSE;
138}
139
140
141LLFont::~LLFont()
142{
143 mRawImagep = NULL; // dereferences or deletes image
144
145 // Clean up freetype libs.
146 FT_Done_Face(mFTFace);
147 mFTFace = NULL;
148
149 // Delete glyph info
150 std::for_each(mCharGlyphInfoMap.begin(), mCharGlyphInfoMap.end(), DeletePairedPointer());
151}
152
153void LLFont::setRawImage(LLImageRaw *imagep)
154{
155 mRawImagep = imagep; // will delete old raw image if we have one and created it
156}
157
158// virtual
159F32 LLFont::getLineHeight() const
160{
161 return mLineHeight;
162}
163
164// virtual
165F32 LLFont::getAscenderHeight() const
166{
167 return mAscender;
168}
169
170// virtual
171F32 LLFont::getDescenderHeight() const
172{
173 return mDescender;
174}
175
176BOOL LLFont::loadFace(const std::string& filename, const F32 point_size, const F32 vert_dpi, const F32 horz_dpi, const S32 components, BOOL is_fallback)
177{
178 int error;
179 error = FT_New_Face( gFTLibrary,
180 filename.c_str(),
181 0,
182 &mFTFace );
183
184 if (error)
185 {
186 return FALSE;
187 }
188
189 mIsFallback = is_fallback;
190 mNumComponents = components;
191 F32 pixels_per_em = (point_size / 72.f)*vert_dpi; // Size in inches * dpi
192
193 error = FT_Set_Char_Size(mFTFace, /* handle to face object */
194 0, /* char_width in 1/64th of points */
195 (S32)(point_size*64), /* char_height in 1/64th of points */
196 (U32)horz_dpi, /* horizontal device resolution */
197 (U32)vert_dpi); /* vertical device resolution */
198
199 if (error)
200 {
201 // Clean up freetype libs.
202 FT_Done_Face(mFTFace);
203 return FALSE;
204 }
205
206 F32 y_max, y_min, x_max, x_min;
207 F32 ems_per_unit = 1.f/ mFTFace->units_per_EM;
208 F32 pixels_per_unit = pixels_per_em * ems_per_unit;
209
210 // Get size of bbox in pixels
211 y_max = mFTFace->bbox.yMax * pixels_per_unit;
212 y_min = mFTFace->bbox.yMin * pixels_per_unit;
213 x_max = mFTFace->bbox.xMax * pixels_per_unit;
214 x_min = mFTFace->bbox.xMin * pixels_per_unit;
215 mAscender = mFTFace->ascender * pixels_per_unit;
216 mDescender = -mFTFace->descender * pixels_per_unit;
217 mLineHeight = mFTFace->height * pixels_per_unit;
218
219 mMaxCharWidth = llround(0.5f + (x_max - x_min));
220 mMaxCharHeight = llround(0.5f + (y_max - y_min));
221
222 if (!mFTFace->charmap)
223 {
224 //llinfos << " no unicode encoding, set whatever encoding there is..." << llendl;
225 FT_Set_Charmap(mFTFace, mFTFace->charmaps[0]);
226 }
227
228 if (mRawImagep.isNull() && !mIsFallback)
229 {
230 mRawImagep = new LLImageRaw();
231 }
232
233 if (!mIsFallback)
234 {
235 // Place text into bitmap, and generate all necessary positions/
236 // offsets for the individual characters.
237
238 // calc width and height for mRawImagep (holds all characters)
239 // Guess for approximately 20*20 characters
240 S32 image_width = mMaxCharWidth * 20;
241 S32 pow_iw = 2;
242 while (pow_iw < image_width)
243 {
244 pow_iw *= 2;
245 }
246 image_width = pow_iw;
247 image_width = llmin(512, image_width); // Don't make bigger than 512x512, ever.
248 S32 image_height = image_width;
249
250 //llinfos << "Guessing texture size of " << image_width << " pixels square" << llendl;
251
252 mRawImagep->resize(image_width, image_height, components);
253
254 mBitmapWidth = image_width;
255 mBitmapHeight = image_height;
256
257 switch (components)
258 {
259 case 1:
260 mRawImagep->clear();
261 break;
262 case 2:
263 mRawImagep->clear(255, 0);
264 break;
265 }
266
267 mCurrentOffsetX = 1;
268 mCurrentOffsetY = 1;
269
270 // Add the default glyph
271 addGlyph(0, 0);
272 }
273
274 mName = filename;
275
276 return TRUE;
277}
278
279
280void LLFont::resetBitmap()
281{
282 llinfos << "Rebuilding bitmap for glyph" << llendl;
283
284 // Iterate through glyphs and clear the mIsRendered flag
285 for (char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.begin();
286 iter != mCharGlyphInfoMap.end(); ++iter)
287 {
288 iter->second->mIsRendered = FALSE;
289 }
290
291 mCurrentOffsetX = 1;
292 mCurrentOffsetY = 1;
293
294 // Add the empty glyph
295 addGlyph(0, 0);
296}
297
298LLFontGlyphInfo* LLFont::getGlyphInfo(const llwchar wch) const
299{
300 char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch);
301 if (iter != mCharGlyphInfoMap.end())
302 {
303 return iter->second;
304 }
305 return NULL;
306}
307
308
309BOOL LLFont::hasGlyph(const llwchar wch) const
310{
311 llassert(!mIsFallback);
312 const LLFontGlyphInfo* gi = getGlyphInfo(wch);
313 if (gi && gi->mIsRendered)
314 {
315 return TRUE;
316 }
317 else
318 {
319 return FALSE;
320 }
321}
322
323BOOL LLFont::addChar(const llwchar wch)
324{
325 llassert(!mIsFallback);
326 //lldebugs << "Adding new glyph for " << wch << " to font" << llendl;
327
328 FT_UInt glyph_index;
329
330 // Initialize char to glyph map
331 glyph_index = FT_Get_Char_Index(mFTFace, wch);
332 if (glyph_index == 0)
333 {
334 // Try looking it up in the backup Unicode font
335 if (mFallbackFontp)
336 {
337 //llinfos << "Trying to add glyph from fallback font!" << llendl
338 LLFontList::iterator iter;
339 for(iter = mFallbackFontp->begin(); iter != mFallbackFontp->end(); iter++)
340 {
341 glyph_index = FT_Get_Char_Index((*iter)->mFTFace, wch);
342 if (glyph_index)
343 {
344 addGlyphFromFont(*iter, wch, glyph_index);
345 return TRUE;
346 }
347 }
348 }
349 }
350
351 char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch);
352 if (iter == mCharGlyphInfoMap.end() || !(iter->second->mIsRendered))
353 {
354 BOOL result = addGlyph(wch, glyph_index);
355 //imdebug("luma b=8 w=%d h=%d t=%s %p", mRawImagep->getWidth(), mRawImagep->getHeight(), mName.c_str(), mRawImagep->getData());
356 return result;
357 }
358 return FALSE;
359}
360
361void LLFont::insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const
362{
363 char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch);
364 if (iter != mCharGlyphInfoMap.end())
365 {
366 delete iter->second;
367 iter->second = gi;
368 }
369 else
370 {
371 mCharGlyphInfoMap[wch] = gi;
372 }
373}
374
375BOOL LLFont::addGlyphFromFont(LLFont *fontp, const llwchar wch, const U32 glyph_index)
376{
377 llassert(!mIsFallback);
378 fontp->renderGlyph(glyph_index);
379 S32 width = fontp->mFTFace->glyph->bitmap.width;
380 S32 height = fontp->mFTFace->glyph->bitmap.rows;
381
382 if ((mCurrentOffsetX + width + 1) > mRawImagep->getWidth())
383 {
384 if ((mCurrentOffsetY + 2*mMaxCharHeight + 2) > mBitmapHeight)
385 {
386 // We're out of space in this texture - clear it an all of the glyphs
387 // and start over again. Easier than LRU and should work just as well
388 // (just slightly slower on the rebuild). As long as the texture has
389 // enough room to hold all glyphs needed for a particular frame this
390 // shouldn't be too slow.
391
392 resetBitmap();
393
394 // Need to rerender the glyph, as it's been overwritten by the default glyph.
395 fontp->renderGlyph(glyph_index);
396 width = fontp->mFTFace->glyph->bitmap.width;
397 height = fontp->mFTFace->glyph->bitmap.rows;
398
399 // We should have a reasonable offset for x and y, no need to check that it's in range
400 }
401 else
402 {
403 mCurrentOffsetX = 1;
404 mCurrentOffsetY += mMaxCharHeight + 1;
405 }
406 }
407
408 LLFontGlyphInfo* gi = new LLFontGlyphInfo(glyph_index);
409 gi->mXBitmapOffset = mCurrentOffsetX;
410 gi->mYBitmapOffset = mCurrentOffsetY;
411 gi->mWidth = width;
412 gi->mHeight = height;
413 gi->mXBearing = fontp->mFTFace->glyph->bitmap_left;
414 gi->mYBearing = fontp->mFTFace->glyph->bitmap_top;
415 // Convert these from 26.6 units to float pixels.
416 gi->mXAdvance = fontp->mFTFace->glyph->advance.x / 64.f;
417 gi->mYAdvance = fontp->mFTFace->glyph->advance.y / 64.f;
418 gi->mIsRendered = TRUE;
419
420 insertGlyphInfo(wch, gi);
421
422 llassert(fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO
423 || fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
424
425 if (fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO
426 || fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY)
427 {
428 U8 *buffer_data = fontp->mFTFace->glyph->bitmap.buffer;
429 S32 buffer_row_stride = fontp->mFTFace->glyph->bitmap.pitch;
430 U8 *tmp_graydata = NULL;
431
432 if (fontp->mFTFace->glyph->bitmap.pixel_mode
433 == FT_PIXEL_MODE_MONO)
434 {
435 // need to expand 1-bit bitmap to 8-bit graymap.
436 tmp_graydata = new U8[width * height];
437 S32 xpos, ypos;
438 for (ypos = 0; ypos < height; ++ypos)
439 {
440 S32 bm_row_offset = buffer_row_stride * ypos;
441 for (xpos = 0; xpos < width; ++xpos)
442 {
443 U32 bm_col_offsetbyte = xpos / 8;
444 U32 bm_col_offsetbit = 7 - (xpos % 8);
445 U32 bit =
446 !!(buffer_data[bm_row_offset
447 + bm_col_offsetbyte
448 ] & (1 << bm_col_offsetbit) );
449 tmp_graydata[width*ypos + xpos] =
450 255 * bit;
451 }
452 }
453 // use newly-built graymap.
454 buffer_data = tmp_graydata;
455 buffer_row_stride = width;
456 }
457
458 switch (mNumComponents)
459 {
460 case 1:
461 mRawImagep->setSubImage(mCurrentOffsetX,
462 mCurrentOffsetY,
463 width,
464 height,
465 buffer_data,
466 buffer_row_stride,
467 TRUE);
468 break;
469 case 2:
470 setSubImageLuminanceAlpha(mCurrentOffsetX,
471 mCurrentOffsetY,
472 width,
473 height,
474 buffer_data,
475 buffer_row_stride);
476 break;
477 default:
478 break;
479 }
480
481 if (tmp_graydata)
482 delete[] tmp_graydata;
483 } else {
484 // we don't know how to handle this pixel format from FreeType;
485 // omit it from the font-image.
486 }
487
488 mCurrentOffsetX += width + 1;
489 return TRUE;
490}
491
492BOOL LLFont::addGlyph(const llwchar wch, const U32 glyph_index)
493{
494 return addGlyphFromFont(this, wch, glyph_index);
495}
496
497
498F32 LLFont::getXAdvance(const llwchar wch) const
499{
500 llassert(!mIsFallback);
501 U32 glyph_index;
502
503 // Return existing info only if it is current
504 LLFontGlyphInfo* gi = getGlyphInfo(wch);
505 if (gi && gi->mIsRendered)
506 {
507 return gi->mXAdvance;
508 }
509
510 const LLFont* fontp = this;
511
512 // Initialize char to glyph map
513 glyph_index = FT_Get_Char_Index(mFTFace, wch);
514 if (glyph_index == 0 && mFallbackFontp)
515 {
516 LLFontList::iterator iter;
517 for(iter = mFallbackFontp->begin(); (iter != mFallbackFontp->end()) && (glyph_index == 0); iter++)
518 {
519 glyph_index = FT_Get_Char_Index((*iter)->mFTFace, wch);
520 if(glyph_index)
521 {
522 fontp = *iter;
523 }
524 }
525 }
526
527 if (glyph_index)
528 {
529 // This font has this glyph
530 (const_cast<LLFont *>(fontp))->renderGlyph(glyph_index);
531
532 // Create the entry if it's not there
533 char_glyph_info_map_t::iterator iter2 = mCharGlyphInfoMap.find(wch);
534 if (iter2 == mCharGlyphInfoMap.end())
535 {
536 gi = new LLFontGlyphInfo(glyph_index);
537 insertGlyphInfo(wch, gi);
538 }
539 else
540 {
541 gi = iter2->second;
542 }
543
544 gi->mWidth = fontp->mFTFace->glyph->bitmap.width;
545 gi->mHeight = fontp->mFTFace->glyph->bitmap.rows;
546
547 // Convert these from 26.6 units to float pixels.
548 gi->mXAdvance = fontp->mFTFace->glyph->advance.x / 64.f;
549 gi->mYAdvance = fontp->mFTFace->glyph->advance.y / 64.f;
550 return gi->mXAdvance;
551 }
552 else
553 {
554 gi = get_if_there(mCharGlyphInfoMap, (llwchar)0, (LLFontGlyphInfo*)NULL);
555 if (gi)
556 {
557 return gi->mXAdvance;
558 }
559 }
560
561 // Last ditch fallback - no glyphs defined at all.
562 return (F32)mMaxCharWidth;
563}
564
565
566void LLFont::renderGlyph(const U32 glyph_index)
567{
568 int error = FT_Load_Glyph(mFTFace, glyph_index, FT_LOAD_DEFAULT );
569 llassert(!error);
570
571 error = FT_Render_Glyph(mFTFace->glyph, gFontRenderMode);
572 llassert(!error);
573}
574
575
576F32 LLFont::getXKerning(const llwchar char_left, const llwchar char_right) const
577{
578 llassert(!mIsFallback);
579 LLFontGlyphInfo* left_glyph_info = get_if_there(mCharGlyphInfoMap, char_left, (LLFontGlyphInfo*)NULL);
580 U32 left_glyph = left_glyph_info ? left_glyph_info->mGlyphIndex : 0;
581 // Kern this puppy.
582 LLFontGlyphInfo* right_glyph_info = get_if_there(mCharGlyphInfoMap, char_right, (LLFontGlyphInfo*)NULL);
583 U32 right_glyph = right_glyph_info ? right_glyph_info->mGlyphIndex : 0;
584
585 FT_Vector delta;
586
587 llverify(!FT_Get_Kerning(mFTFace, left_glyph, right_glyph, ft_kerning_unfitted, &delta));
588
589 return delta.x*(1.f/64.f);
590}
591
592void LLFont::setSubImageLuminanceAlpha(const U32 x,
593 const U32 y,
594 const U32 width,
595 const U32 height,
596 const U8 *data,
597 S32 stride)
598{
599 llassert(!mIsFallback);
600 llassert(mRawImagep->getComponents() == 2);
601
602 U8 *target = mRawImagep->getData();
603
604 if (!data)
605 {
606 return;
607 }
608
609 if (0 == stride)
610 stride = width;
611
612 U32 i, j;
613 U32 to_offset;
614 U32 from_offset;
615 U32 target_width = mRawImagep->getWidth();
616 for (i = 0; i < height; i++)
617 {
618 to_offset = (y + i)*target_width + x;
619 from_offset = (height - 1 - i)*stride;
620 for (j = 0; j < width; j++)
621 {
622 *(target + to_offset*2 + 1) = *(data + from_offset);
623 to_offset++;
624 from_offset++;
625 }
626 }
627}
diff --git a/linden/indra/llrender/llfont.h b/linden/indra/llrender/llfont.h
new file mode 100644
index 0000000..dadeafd
--- /dev/null
+++ b/linden/indra/llrender/llfont.h
@@ -0,0 +1,188 @@
1/**
2 * @file llfont.h
3 * @brief Font library wrapper
4 *
5 * Copyright (c) 2002-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LL_LLFONT_H
29#define LL_LLFONT_H
30
31#include <map>
32//#include "lllocalidhashmap.h"
33#include "llmemory.h"
34
35class LLImageRaw;
36class LLFontManager;
37class LLFont;
38
39// Hack. FT_Face is just a typedef for a pointer to a struct,
40// but there's no simple forward declarations file for FreeType,
41// and the main include file is 200K.
42// We'll forward declare the struct here. JC
43struct FT_FaceRec_;
44typedef struct FT_FaceRec_* LLFT_Face;
45
46extern LLFontManager *gFontManagerp;
47
48class LLFontManager
49{
50public:
51 static void initClass();
52 static void cleanupClass();
53
54public:
55 LLFontManager();
56 virtual ~LLFontManager();
57};
58
59class LLFontGlyphInfo
60{
61public:
62 LLFontGlyphInfo(U32 index);
63public:
64 U32 mGlyphIndex;
65 // Metrics
66 S32 mWidth; // In pixels
67 S32 mHeight; // In pixels
68 F32 mXAdvance; // In pixels
69 F32 mYAdvance; // In pixels
70
71 // Information for actually rendering
72 BOOL mIsRendered; // We actually have rendered this glyph
73 S32 mXBitmapOffset; // Offset to the origin in the bitmap
74 S32 mYBitmapOffset; // Offset to the origin in the bitmap
75 S32 mXBearing; // Distance from baseline to left in pixels
76 S32 mYBearing; // Distance from baseline to top in pixels
77};
78
79// Used for lists of fallback fonts
80class LLFontList : public std::vector<LLFont*>
81{
82public:
83 LLFontList();
84 ~LLFontList();
85 void addAtEnd(LLFont *font);
86};
87
88
89class LLFont
90{
91public:
92 LLFont(LLImageRaw *imagep = NULL);
93 virtual ~LLFont();
94
95 // is_fallback should be true for fallback fonts that aren't used to render directly (Unicode backup, primarily)
96 virtual BOOL loadFace(const std::string& filename,
97 const F32 point_size,
98 const F32 vert_dpi,
99 const F32 horz_dpi,
100 const S32 components,
101 BOOL is_fallback);
102 void setFallbackFont(LLFontList *fontp) { mFallbackFontp = fontp; }
103
104 void setCharToGlyphMap(llwchar wch, U32 glyph_index) const;
105 void setRawImage( LLImageRaw *imagep );
106
107 // Global font metrics - in units of pixels
108 virtual F32 getLineHeight() const;
109 virtual F32 getAscenderHeight() const;
110 virtual F32 getDescenderHeight() const;
111
112
113// For a lowercase "g":
114//
115// ------------------------------
116// ^ ^
117// | |
118// xxx x |Ascender
119// x x | |
120// --------- xxxx-------------- Baseline
121// ^ x | |
122// | descender x | |
123// v xxxx v |LineHeight
124// ----------------------- |
125// v
126// ------------------------------
127
128 enum
129 {
130 FIRST_CHAR = 32,
131 NUM_CHARS = 127 - 32,
132 LAST_CHAR_BASIC = 127,
133
134 // Need full 8-bit ascii range for spanish
135 NUM_CHARS_FULL = 255 - 32,
136 LAST_CHAR_FULL = 255
137 };
138
139 const LLFontGlyphInfo &getMetrics(const llwchar wc) const;
140 F32 getXAdvance(const llwchar wc) const;
141 F32 getXKerning(const llwchar char_left, const llwchar char_right) const; // Get the kerning between the two characters
142protected:
143 virtual BOOL hasGlyph(const llwchar wch) const; // Has a glyph for this character
144 virtual BOOL addChar(const llwchar wch); // Add a new character to the font if necessary
145 virtual BOOL addGlyph(const llwchar wch, const U32 glyph_index); // Add a new glyph to the existing font
146 virtual BOOL addGlyphFromFont(LLFont *fontp, const llwchar wch, const U32 glyph_index); // Add a glyph from this font to the other (returns the glyph_index, 0 if not found)
147
148 virtual LLFontGlyphInfo* getGlyphInfo(const llwchar wch) const;
149
150 void insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const;
151 void renderGlyph(const U32 glyph_index);
152
153 void resetBitmap(); // Reset bitmap to contain only the null glyph
154protected:
155 std::string mName;
156 F32 mAscender;
157 F32 mDescender;
158 F32 mLineHeight;
159
160 S32 mNumComponents;
161 S32 mBitmapWidth;
162 S32 mBitmapHeight;
163 S32 mMaxCharWidth;
164 S32 mMaxCharHeight;
165 S32 mCurrentOffsetX;
166 S32 mCurrentOffsetY;
167
168 LLFT_Face mFTFace;
169
170 BOOL mIsFallback;
171 LLFontList *mFallbackFontp; // A list of fallback fonts to look for glyphs in (for Unicode chars)
172
173 typedef std::map<llwchar, LLFontGlyphInfo*> char_glyph_info_map_t;
174 mutable char_glyph_info_map_t mCharGlyphInfoMap; // Information about glyph location in bitmap
175
176 BOOL mValid;
177 void setSubImageLuminanceAlpha(const U32 x,
178 const U32 y,
179 const U32 width,
180 const U32 height,
181 const U8 *data,
182 S32 stride = 0);
183
184private:
185 LLPointer<LLImageRaw> mRawImagep; // Bitmaps of glyphs are stored here.
186};
187
188#endif // LL_FONT_
diff --git a/linden/indra/llrender/llfontgl.cpp b/linden/indra/llrender/llfontgl.cpp
new file mode 100644
index 0000000..2774e8d
--- /dev/null
+++ b/linden/indra/llrender/llfontgl.cpp
@@ -0,0 +1,1453 @@
1/**
2 * @file llfontgl.cpp
3 * @brief Wrapper around FreeType
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "linden_common.h"
29
30#include <boost/tokenizer.hpp>
31
32#include "llfont.h"
33#include "llfontgl.h"
34#include "llgl.h"
35#include "v4color.h"
36
37const S32 BOLD_OFFSET = 1;
38
39// static class members
40F32 LLFontGL::sVertDPI = 96.f;
41F32 LLFontGL::sHorizDPI = 96.f;
42F32 LLFontGL::sScaleX = 1.f;
43F32 LLFontGL::sScaleY = 1.f;
44LLString LLFontGL::sAppDir;
45
46LLFontGL* LLFontGL::sMonospace = NULL;
47LLFontGL* LLFontGL::sSansSerifSmall = NULL;
48LLFontGL* LLFontGL::sSansSerif = NULL;
49LLFontGL* LLFontGL::sSansSerifBig = NULL;
50LLFontGL* LLFontGL::sSansSerifHuge = NULL;
51LLFontGL* LLFontGL::sSansSerifBold = NULL;
52LLFontList* LLFontGL::sSSFallback = NULL;
53LLFontList* LLFontGL::sSSSmallFallback = NULL;
54LLFontList* LLFontGL::sSSBigFallback = NULL;
55LLFontList* LLFontGL::sSSHugeFallback = NULL;
56LLFontList* LLFontGL::sSSBoldFallback = NULL;
57LLColor4 LLFontGL::sShadowColor(0.f, 0.f, 0.f, 1.f);
58
59LLCoordFont LLFontGL::sCurOrigin;
60std::vector<LLCoordFont> LLFontGL::sOriginStack;
61
62LLFontGL*& gExtCharFont = LLFontGL::sSansSerif;
63
64const F32 EXT_X_BEARING = 1.f;
65const F32 EXT_Y_BEARING = 0.f;
66const F32 EXT_KERNING = 1.f;
67const F32 PIXEL_BORDER_THRESHOLD = 0.0001f;
68const F32 PIXEL_CORRECTION_DISTANCE = 0.01f;
69
70const F32 PAD_AMT = 0.5f;
71
72F32 llfont_round_x(F32 x)
73{
74 //return llfloor((x-LLFontGL::sCurOrigin.mX)/LLFontGL::sScaleX+0.5f)*LLFontGL::sScaleX+LLFontGL::sCurOrigin.mX;
75 //return llfloor(x/LLFontGL::sScaleX+0.5f)*LLFontGL::sScaleY;
76 return x;
77}
78
79F32 llfont_round_y(F32 y)
80{
81 //return llfloor((y-LLFontGL::sCurOrigin.mY)/LLFontGL::sScaleY+0.5f)*LLFontGL::sScaleY+LLFontGL::sCurOrigin.mY;
82 //return llfloor(y+0.5f);
83 return y;
84}
85
86// static
87U8 LLFontGL::getStyleFromString(const LLString &style)
88{
89 S32 ret = 0;
90 if (style.find("NORMAL") != style.npos)
91 {
92 ret |= NORMAL;
93 }
94 if (style.find("BOLD") != style.npos)
95 {
96 ret |= BOLD;
97 }
98 if (style.find("ITALIC") != style.npos)
99 {
100 ret |= ITALIC;
101 }
102 if (style.find("UNDERLINE") != style.npos)
103 {
104 ret |= UNDERLINE;
105 }
106 return ret;
107}
108
109LLFontGL::LLFontGL()
110 : LLFont()
111{
112 init();
113 clearEmbeddedChars();
114}
115
116LLFontGL::LLFontGL(const LLFontGL &source)
117{
118 llerrs << "Not implemented!" << llendl;
119}
120
121LLFontGL::~LLFontGL()
122{
123 mImageGLp = NULL;
124 mRawImageGLp = NULL;
125 clearEmbeddedChars();
126}
127
128void LLFontGL::init()
129{
130 if (mImageGLp.isNull())
131 {
132 mImageGLp = new LLImageGL(FALSE);
133 //RN: use nearest mipmap filtering to obviate the need to do pixel-accurate positioning
134 mImageGLp->bind();
135 mImageGLp->setMipFilterNearest(TRUE, TRUE);
136 }
137 if (mRawImageGLp.isNull())
138 {
139 mRawImageGLp = new LLImageRaw; // Note LLFontGL owns the image, not LLFont.
140 }
141 setRawImage( mRawImageGLp );
142}
143
144void LLFontGL::reset()
145{
146 init();
147 resetBitmap();
148}
149
150// static
151LLString LLFontGL::getFontPathSystem()
152{
153 LLString system_path;
154
155 // Try to figure out where the system's font files are stored.
156 char *system_root = NULL;
157#if LL_WINDOWS
158 system_root = getenv("SystemRoot");
159 if (!system_root)
160 {
161 llwarns << "SystemRoot not found, attempting to load fonts from default path." << llendl;
162 }
163#endif
164
165 if (system_root)
166 {
167 system_path = llformat("%s/fonts/", system_root);
168 }
169 else
170 {
171#if LL_WINDOWS
172 // HACK for windows 98/Me
173 system_path = "/WINDOWS/FONTS/";
174#elif LL_DARWIN
175 // HACK for Mac OS X
176 system_path = "/System/Library/Fonts/";
177#endif
178 }
179 return system_path;
180}
181
182
183// static
184LLString LLFontGL::getFontPathLocal()
185{
186 LLString local_path;
187
188 // Backup files if we can't load from system fonts directory.
189 // We could store this in an end-user writable directory to allow
190 // end users to switch fonts.
191 if (LLFontGL::sAppDir.length())
192 {
193 // use specified application dir to look for fonts
194 local_path = LLFontGL::sAppDir + "/fonts/";
195 }
196 else
197 {
198 // assume working directory is executable directory
199 local_path = "./fonts/";
200 }
201 return local_path;
202}
203
204//static
205bool LLFontGL::loadFaceFallback(LLFontList *fontlistp, const LLString& fontname, const F32 point_size)
206{
207 LLString local_path = getFontPathLocal();
208 LLString sys_path = getFontPathSystem();
209
210 // The fontname string may contain multiple font file names separated by semicolons.
211 // Break it apart and try loading each one, in order.
212 typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
213 boost::char_separator<char> sep(";");
214 tokenizer tokens(fontname, sep);
215 tokenizer::iterator token_iter;
216
217 for(token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter)
218 {
219 LLFont *fontp = new LLFont();
220 LLString font_path = local_path + *token_iter;
221 if (!fontp->loadFace(font_path.c_str(), point_size, sVertDPI, sHorizDPI, 2, TRUE))
222 {
223 font_path = sys_path + *token_iter;
224 if (!fontp->loadFace(font_path.c_str(), point_size, sVertDPI, sHorizDPI, 2, TRUE))
225 {
226 llwarns << "Couldn't load font " << *token_iter << llendl;
227 delete fontp;
228 fontp = NULL;
229 }
230 }
231
232 if(fontp)
233 {
234 fontlistp->addAtEnd(fontp);
235 }
236 }
237
238 // We want to return true if at least one fallback font loaded correctly.
239 return (fontlistp->size() > 0);
240}
241
242//static
243bool LLFontGL::loadFace(LLFontGL *fontp, const LLString& fontname, const F32 point_size, LLFontList *fallback_fontp)
244{
245 LLString local_path = getFontPathLocal();
246 LLString font_path = local_path + fontname;
247 if (!fontp->loadFace(font_path.c_str(), point_size, sVertDPI, sHorizDPI))
248 {
249 LLString sys_path = getFontPathSystem();
250 font_path = sys_path + fontname;
251 if (!fontp->loadFace(font_path.c_str(), point_size, sVertDPI, sHorizDPI))
252 {
253 llwarns << "Couldn't load font " << fontname << llendl;
254 return false;
255 }
256 }
257
258 fontp->setFallbackFont(fallback_fontp);
259 return true;
260}
261
262
263// static
264BOOL LLFontGL::initDefaultFonts(F32 screen_dpi, F32 x_scale, F32 y_scale,
265 const LLString& monospace_file, F32 monospace_size,
266 const LLString& sansserif_file,
267 const LLString& sanserif_fallback_file, F32 ss_fallback_scale,
268 F32 small_size, F32 medium_size, F32 big_size, F32 huge_size,
269 const LLString& sansserif_bold_file, F32 bold_size,
270 const LLString& app_dir)
271{
272 BOOL failed = FALSE;
273 sVertDPI = (F32)llfloor(screen_dpi * y_scale);
274 sHorizDPI = (F32)llfloor(screen_dpi * x_scale);
275 sScaleX = x_scale;
276 sScaleY = y_scale;
277 sAppDir = app_dir;
278
279 //
280 // Monospace font
281 //
282
283 if (!sMonospace)
284 {
285 sMonospace = new LLFontGL();
286 }
287 else
288 {
289 sMonospace->reset();
290 }
291
292 failed |= !loadFace(sMonospace, monospace_file, monospace_size, NULL);
293
294 //
295 // Sans-serif fonts
296 //
297 if(!sSansSerifHuge)
298 {
299 sSansSerifHuge = new LLFontGL();
300 }
301 else
302 {
303 sSansSerifHuge->reset();
304 }
305
306 if (!sSSHugeFallback)
307 {
308 sSSHugeFallback = new LLFontList();
309 if (!loadFaceFallback(sSSHugeFallback, sanserif_fallback_file, huge_size*ss_fallback_scale))
310 {
311 delete sSSHugeFallback;
312 sSSHugeFallback = NULL;
313 }
314 }
315
316 failed |= !loadFace(sSansSerifHuge, sansserif_file, huge_size, sSSHugeFallback);
317
318
319 if(!sSansSerifBig)
320 {
321 sSansSerifBig = new LLFontGL();
322 }
323 else
324 {
325 sSansSerifBig->reset();
326 }
327
328 if (!sSSBigFallback)
329 {
330 sSSBigFallback = new LLFontList();
331 if (!loadFaceFallback(sSSBigFallback, sanserif_fallback_file, big_size*ss_fallback_scale))
332 {
333 delete sSSBigFallback;
334 sSSBigFallback = NULL;
335 }
336 }
337
338 failed |= !loadFace(sSansSerifBig, sansserif_file, big_size, sSSBigFallback);
339
340
341 if(!sSansSerif)
342 {
343 sSansSerif = new LLFontGL();
344 }
345 else
346 {
347 sSansSerif->reset();
348 }
349
350 if (!sSSFallback)
351 {
352 sSSFallback = new LLFontList();
353 if (!loadFaceFallback(sSSFallback, sanserif_fallback_file, medium_size*ss_fallback_scale))
354 {
355 delete sSSFallback;
356 sSSFallback = NULL;
357 }
358 }
359 failed |= !loadFace(sSansSerif, sansserif_file, medium_size, sSSFallback);
360
361
362 if(!sSansSerifSmall)
363 {
364 sSansSerifSmall = new LLFontGL();
365 }
366 else
367 {
368 sSansSerifSmall->reset();
369 }
370
371 if (!sSSSmallFallback)
372 {
373 sSSSmallFallback = new LLFontList();
374 if (!loadFaceFallback(sSSSmallFallback, sanserif_fallback_file, small_size*ss_fallback_scale))
375 {
376 delete sSSSmallFallback;
377 sSSSmallFallback = NULL;
378 }
379 }
380 failed |= !loadFace(sSansSerifSmall, sansserif_file, small_size, sSSSmallFallback);
381
382
383 //
384 // Sans-serif bold
385 //
386 if(!sSansSerifBold)
387 {
388 sSansSerifBold = new LLFontGL();
389 }
390 else
391 {
392 sSansSerifBold->reset();
393 }
394
395 if (!sSSBoldFallback)
396 {
397 sSSBoldFallback = new LLFontList();
398 if (!loadFaceFallback(sSSBoldFallback, sanserif_fallback_file, medium_size*ss_fallback_scale))
399 {
400 delete sSSBoldFallback;
401 sSSBoldFallback = NULL;
402 }
403 }
404 failed |= !loadFace(sSansSerifBold, sansserif_bold_file, medium_size, sSSBoldFallback);
405
406 return !failed;
407}
408
409
410
411// static
412void LLFontGL::destroyDefaultFonts()
413{
414 delete sMonospace;
415 sMonospace = NULL;
416
417 delete sSansSerifHuge;
418 sSansSerifHuge = NULL;
419
420 delete sSansSerifBig;
421 sSansSerifBig = NULL;
422
423 delete sSansSerif;
424 sSansSerif = NULL;
425
426 delete sSansSerifSmall;
427 sSansSerifSmall = NULL;
428
429 delete sSansSerifBold;
430 sSansSerifBold = NULL;
431
432 delete sSSHugeFallback;
433 sSSHugeFallback = NULL;
434
435 delete sSSBigFallback;
436 sSSBigFallback = NULL;
437
438 delete sSSFallback;
439 sSSFallback = NULL;
440
441 delete sSSSmallFallback;
442 sSSSmallFallback = NULL;
443
444 delete sSSBoldFallback;
445 sSSBoldFallback = NULL;
446}
447
448//static
449void LLFontGL::destroyGL()
450{
451 if (!sMonospace)
452 {
453 // Already all destroyed.
454 return;
455 }
456 sMonospace->mImageGLp->destroyGLTexture();
457 sSansSerifHuge->mImageGLp->destroyGLTexture();
458 sSansSerifSmall->mImageGLp->destroyGLTexture();
459 sSansSerif->mImageGLp->destroyGLTexture();
460 sSansSerifBig->mImageGLp->destroyGLTexture();
461 sSansSerifBold->mImageGLp->destroyGLTexture();
462}
463
464
465
466LLFontGL &LLFontGL::operator=(const LLFontGL &source)
467{
468 llerrs << "Not implemented" << llendl;
469 return *this;
470}
471
472BOOL LLFontGL::loadFace(const LLString& filename, const F32 point_size, const F32 vert_dpi, const F32 horz_dpi)
473{
474 if (!LLFont::loadFace(filename, point_size, vert_dpi, horz_dpi, 2, FALSE))
475 {
476 return FALSE;
477 }
478 mImageGLp->createGLTexture(0, mRawImageGLp);
479 mImageGLp->bind();
480 mImageGLp->setMipFilterNearest(TRUE, TRUE);
481 return TRUE;
482}
483
484BOOL LLFontGL::addChar(const llwchar wch)
485{
486 if (!LLFont::addChar(wch))
487 {
488 return FALSE;
489 }
490
491 stop_glerror();
492 mImageGLp->setSubImage(mRawImageGLp, 0, 0, mImageGLp->getWidth(), mImageGLp->getHeight());
493 mImageGLp->bind();
494 mImageGLp->setMipFilterNearest(TRUE, TRUE);
495 stop_glerror();
496 return TRUE;
497}
498
499
500S32 LLFontGL::renderUTF8(const LLString &text, const S32 offset,
501 const F32 x, const F32 y,
502 const LLColor4 &color,
503 const HAlign halign, const VAlign valign,
504 U8 style,
505 const S32 max_chars, const S32 max_pixels,
506 F32* right_x,
507 BOOL use_ellipses) const
508{
509 LLWString wstr = utf8str_to_wstring(text);
510 return render(wstr, offset, x, y, color, halign, valign, style, max_chars, max_pixels, right_x, use_ellipses);
511}
512
513S32 LLFontGL::render(const LLWString &wstr,
514 const S32 begin_offset,
515 const F32 x, const F32 y,
516 const LLColor4 &color,
517 const HAlign halign, const VAlign valign,
518 U8 style,
519 const S32 max_chars, S32 max_pixels,
520 F32* right_x,
521 BOOL use_embedded,
522 BOOL use_ellipses) const
523{
524 LLGLEnable texture_2d(GL_TEXTURE_2D);
525
526 if (wstr.empty())
527 {
528 return 0;
529 }
530
531 if (style & DROP_SHADOW)
532 {
533 LLColor4 shadow_color = sShadowColor;
534 shadow_color[3] = color[3];
535 render(wstr, begin_offset,
536 x + 1.f / sScaleX,
537 y - 1.f / sScaleY,
538 shadow_color,
539 halign,
540 valign,
541 style & (~DROP_SHADOW),
542 max_chars,
543 max_pixels,
544 right_x,
545 use_embedded,
546 use_ellipses);
547 }
548
549 S32 scaled_max_pixels = max_pixels == S32_MAX ? S32_MAX : llceil((F32)max_pixels * sScaleX);
550
551 BOOL render_bold = FALSE;
552
553 // HACK for better bolding
554 if (style & BOLD)
555 {
556 if (this == LLFontGL::sSansSerif)
557 {
558 return LLFontGL::sSansSerifBold->render(
559 wstr, begin_offset,
560 x, y,
561 color,
562 halign, valign,
563 (style & ~BOLD),
564 max_chars, max_pixels,
565 right_x, use_embedded);
566 }
567 else
568 {
569 render_bold = TRUE;
570 }
571 }
572
573 glPushMatrix();
574 glLoadIdentity();
575 glTranslatef(floorf(sCurOrigin.mX*sScaleX), floorf(sCurOrigin.mY*sScaleY), sCurOrigin.mZ);
576 //glScalef(sScaleX, sScaleY, 1.0f);
577
578 // avoid half pixels
579 // RN: if we're going to this trouble, might as well snap to nearest pixel all the time
580 // but the plan is to get rid of this so that fonts "just work"
581 //F32 half_pixel_distance = llabs(fmodf(sCurOrigin.mX * sScaleX, 1.f) - 0.5f);
582 //if (half_pixel_distance < PIXEL_BORDER_THRESHOLD)
583 //{
584 glTranslatef(PIXEL_CORRECTION_DISTANCE*sScaleX, 0.f, 0.f);
585 //}
586
587 // this code would just snap to pixel grid, although it seems to introduce more jitter
588 //F32 pixel_offset_x = llround(sCurOrigin.mX * sScaleX) - (sCurOrigin.mX * sScaleX);
589 //F32 pixel_offset_y = llround(sCurOrigin.mY * sScaleY) - (sCurOrigin.mY * sScaleY);
590 //glTranslatef(-pixel_offset_x, -pixel_offset_y, 0.f);
591
592 // scale back to native pixel size
593 //glScalef(1.f / sScaleX, 1.f / sScaleY, 1.f);
594 //glScaled(1.0 / (F64) sScaleX, 1.0 / (F64) sScaleY, 1.0f);
595 LLFastTimer t(LLFastTimer::FTM_RENDER_FONTS);
596
597 glColor4fv( color.mV );
598
599 S32 chars_drawn = 0;
600 S32 i;
601 S32 length;
602
603 if (-1 == max_chars)
604 {
605 length = (S32)wstr.length() - begin_offset;
606 }
607 else
608 {
609 length = llmin((S32)wstr.length() - begin_offset, max_chars );
610 }
611
612 F32 cur_x, cur_y, cur_render_x, cur_render_y;
613 F32 slant_offset;
614
615 slant_offset = ((style & ITALIC) ? ( -mAscender * 0.25f) : 0.f);
616
617 // Bind the font texture
618
619 mImageGLp->bind(0);
620
621 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Not guaranteed to be set correctly
622
623 cur_x = ((F32)x * sScaleX);
624 cur_y = ((F32)y * sScaleY);
625
626 // Offset y by vertical alignment.
627 switch (valign)
628 {
629 case TOP:
630 cur_y -= mAscender;
631 break;
632 case BOTTOM:
633 cur_y += mDescender;
634 break;
635 case VCENTER:
636 cur_y -= ((mAscender - mDescender)/2.f);
637 break;
638 case BASELINE:
639 // Baseline, do nothing.
640 break;
641 default:
642 break;
643 }
644
645 switch (halign)
646 {
647 case LEFT:
648 break;
649 case RIGHT:
650 cur_x -= (F32)getWidth(wstr.c_str(), 0, length) * sScaleX;
651 break;
652 case HCENTER:
653 cur_x -= llmin(scaled_max_pixels, llround(getWidthF32(wstr.c_str(), 0, length) * sScaleX)) / 2;
654 break;
655 default:
656 break;
657 }
658
659 // Round properly.
660 //cur_render_y = (F32)llfloor(cur_y/sScaleY + 0.5f)*sScaleY;
661 //cur_render_x = (F32)llfloor(cur_x/sScaleX + 0.5f)*sScaleX;
662
663 cur_render_y = cur_y;
664 cur_render_x = cur_x;
665
666 F32 start_x = cur_x;
667
668 F32 inv_width = 1.f / mImageGLp->getWidth();
669 F32 inv_height = 1.f / mImageGLp->getHeight();
670
671 const S32 LAST_CHARACTER = LLFont::LAST_CHAR_FULL;
672
673
674 BOOL draw_ellipses = FALSE;
675 if (use_ellipses)
676 {
677 // check for too long of a string
678 if (getWidthF32(wstr.c_str(), 0, max_chars) > scaled_max_pixels)
679 {
680 const LLWString dots(utf8str_to_wstring(LLString("...")));
681 scaled_max_pixels = llmax(0, scaled_max_pixels - llround(getWidthF32(dots.c_str())));
682 draw_ellipses = TRUE;
683 }
684 }
685
686
687 glBegin(GL_QUADS);
688 for (i = begin_offset; i < begin_offset + length; i++)
689 {
690 llwchar wch = wstr[i];
691
692 // Handle embedded characters first, if they're enabled.
693 // Embedded characters are a hack for notecards
694 const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL;
695 if (ext_data)
696 {
697 LLImageGL* ext_image = ext_data->mImage;
698 const LLWString& label = ext_data->mLabel;
699
700 F32 ext_height = (F32)ext_image->getHeight() * sScaleY;
701
702 F32 ext_width = (F32)ext_image->getWidth() * sScaleX;
703 F32 ext_advance = (EXT_X_BEARING * sScaleX) + ext_width;
704
705 if (!label.empty())
706 {
707 ext_advance += (EXT_X_BEARING + gExtCharFont->getWidthF32( label.c_str() )) * sScaleX;
708 }
709
710 if (start_x + scaled_max_pixels < cur_x + ext_advance)
711 {
712 // Not enough room for this character.
713 break;
714 }
715
716 glEnd();
717
718 glColor3f(1.f, 1.f, 1.f);
719
720 ext_image->bind();
721 const F32 ext_x = cur_render_x + (EXT_X_BEARING * sScaleX);
722 const F32 ext_y = cur_render_y + (EXT_Y_BEARING * sScaleY + mAscender - mLineHeight);
723
724 glBegin(GL_QUADS);
725 {
726 S32 num_passes = render_bold ? 2 : 1;
727 for (S32 pass = 0; pass < num_passes; pass++)
728 {
729 glTexCoord2f(1.f, 1.f);
730 glVertex2f(llfont_round_x(ext_x + ext_width + (F32)(pass * BOLD_OFFSET)),
731 llfont_round_y(ext_y + ext_height));
732
733 glTexCoord2f(0.f, 1.f);
734 glVertex2f(llfont_round_x(ext_x + (F32)(pass * BOLD_OFFSET)),
735 llfont_round_y(ext_y + ext_height));
736
737 glTexCoord2f(0.f, 0.f);
738 glVertex2f(llfont_round_x(ext_x + (F32)(pass * BOLD_OFFSET)), llfont_round_y(ext_y));
739
740 glTexCoord2f(1.f, 0.f);
741 glVertex2f(llfont_round_x(ext_x + ext_width + (F32)(pass * BOLD_OFFSET)),
742 llfont_round_y(ext_y));
743 }
744 }
745 glEnd();
746
747 if (!label.empty())
748 {
749 glPushMatrix();
750 //glLoadIdentity();
751 //glTranslatef(sCurOrigin.mX, sCurOrigin.mY, 0.0f);
752 //glScalef(sScaleX, sScaleY, 1.f);
753 gExtCharFont->render(label, 0,
754 /*llfloor*/((ext_x + (F32)ext_image->getWidth() + EXT_X_BEARING) / sScaleX),
755 /*llfloor*/(cur_y / sScaleY),
756 color,
757 halign, BASELINE, NORMAL, S32_MAX, S32_MAX, NULL,
758 TRUE );
759 glPopMatrix();
760 }
761
762 glColor4fv(color.mV);
763
764 chars_drawn++;
765 cur_x += ext_advance;
766 if (((i + 1) < length) && wstr[i+1])
767 {
768 cur_x += EXT_KERNING * sScaleX;
769 }
770 cur_render_x = cur_x;
771
772 // Bind the font texture
773 mImageGLp->bind();
774 glBegin(GL_QUADS);
775 }
776 else
777 {
778 if (!hasGlyph(wch))
779 {
780 glEnd();
781 (const_cast<LLFontGL*>(this))->addChar(wch);
782 glBegin(GL_QUADS);
783 }
784
785 const LLFontGlyphInfo* fgi= getGlyphInfo(wch);
786 if (!fgi)
787 {
788 llerrs << "Missing Glyph Info" << llendl;
789 }
790 if ((start_x + scaled_max_pixels) < (cur_x + fgi->mXBearing + fgi->mWidth))
791 {
792 // Not enough room for this character.
793 break;
794 }
795
796 // Draw the text at the appropriate location
797 //Specify vertices and texture coordinates
798 S32 num_passes = render_bold ? 2 : 1;
799 for (S32 pass = 0; pass < num_passes; pass++)
800 {
801 glTexCoord2f((fgi->mXBitmapOffset - PAD_AMT) * inv_width,
802 (fgi->mYBitmapOffset + fgi->mHeight + PAD_AMT) * inv_height);
803 glVertex2f(llfont_round_x(cur_render_x + (F32)fgi->mXBearing + (F32)(pass * BOLD_OFFSET) - PAD_AMT),
804 llfont_round_y(cur_render_y + (F32)fgi->mYBearing + PAD_AMT));
805 glTexCoord2f((fgi->mXBitmapOffset - PAD_AMT) * inv_width,
806 (fgi->mYBitmapOffset - PAD_AMT) * inv_height);
807 glVertex2f(llfont_round_x(cur_render_x + (F32)fgi->mXBearing + slant_offset + (F32)(pass * BOLD_OFFSET) - PAD_AMT),
808 llfont_round_y(cur_render_y + (F32)fgi->mYBearing - (F32)fgi->mHeight - PAD_AMT));
809 glTexCoord2f((fgi->mXBitmapOffset + fgi->mWidth + PAD_AMT) * inv_width,
810 (fgi->mYBitmapOffset - PAD_AMT) * inv_height);
811 glVertex2f(llfont_round_x(cur_render_x + (F32)fgi->mXBearing + slant_offset + (F32)fgi->mWidth + (F32)(pass * BOLD_OFFSET) + PAD_AMT),
812 llfont_round_y(cur_render_y + (F32)fgi->mYBearing - (F32)fgi->mHeight - PAD_AMT));
813 glTexCoord2f((fgi->mXBitmapOffset + fgi->mWidth + PAD_AMT) * inv_width,
814 (fgi->mYBitmapOffset + fgi->mHeight + PAD_AMT) * inv_height);
815 glVertex2f(llfont_round_x(cur_render_x + (F32)fgi->mXBearing + (F32)fgi->mWidth + (F32)(pass * BOLD_OFFSET) + PAD_AMT),
816 llfont_round_y(cur_render_y + (F32)fgi->mYBearing + PAD_AMT));
817 }
818
819 chars_drawn++;
820
821 cur_x += fgi->mXAdvance;
822 cur_y += fgi->mYAdvance;
823 llwchar next_char = wstr[i+1];
824 if (next_char && (next_char < LAST_CHARACTER))
825 {
826 // Kern this puppy.
827 if (!hasGlyph(next_char))
828 {
829 glEnd();
830 (const_cast<LLFontGL*>(this))->addChar(next_char);
831 glBegin(GL_QUADS);
832 }
833 cur_x += getXKerning(wch, next_char);
834 }
835
836 // Round after kerning.
837 // Must do this to cur_x, not just to cur_render_x, otherwise you
838 // will squish sub-pixel kerned characters too close together.
839 // For example, "CCCCC" looks bad.
840 cur_x = (F32)llfloor(cur_x + 0.5f);
841 //cur_y = (F32)llfloor(cur_y + 0.5f);
842
843 cur_render_x = cur_x;
844 cur_render_y = cur_y;
845 }
846 }
847
848 glEnd();
849
850 if (right_x)
851 {
852 *right_x = cur_x / sScaleX;
853 }
854
855 if (style & UNDERLINE)
856 {
857 LLGLSNoTexture no_texture;
858 glBegin(GL_LINES);
859 glVertex2f(start_x, cur_y - (mDescender));
860 glVertex2f(cur_x, cur_y - (mDescender));
861 glEnd();
862 }
863
864 // *FIX: get this working in all alignment cases, etc.
865 if (draw_ellipses)
866 {
867 // recursively render ellipses at end of string
868 // we've already reserved enough room
869 glPushMatrix();
870 //glLoadIdentity();
871 //glTranslatef(sCurOrigin.mX, sCurOrigin.mY, 0.0f);
872 //glScalef(sScaleX, sScaleY, 1.f);
873 renderUTF8("...",
874 0,
875 cur_x / sScaleX, (F32)y,
876 color,
877 LEFT, valign,
878 style,
879 S32_MAX, max_pixels,
880 right_x,
881 FALSE);
882 glPopMatrix();
883 }
884
885 glPopMatrix();
886
887 return chars_drawn;
888}
889
890
891LLImageGL *LLFontGL::getImageGL() const
892{
893 return mImageGLp;
894}
895
896S32 LLFontGL::getWidth(const LLString& utf8text) const
897{
898 LLWString wtext = utf8str_to_wstring(utf8text);
899 return getWidth(wtext.c_str(), 0, S32_MAX);
900}
901
902S32 LLFontGL::getWidth(const llwchar* wchars) const
903{
904 return getWidth(wchars, 0, S32_MAX);
905}
906
907S32 LLFontGL::getWidth(const LLString& utf8text, const S32 begin_offset, const S32 max_chars) const
908{
909 LLWString wtext = utf8str_to_wstring(utf8text);
910 return getWidth(wtext.c_str(), begin_offset, max_chars);
911}
912
913S32 LLFontGL::getWidth(const llwchar* wchars, const S32 begin_offset, const S32 max_chars, BOOL use_embedded) const
914{
915 F32 width = getWidthF32(wchars, begin_offset, max_chars, use_embedded);
916 return llround(width);
917}
918
919F32 LLFontGL::getWidthF32(const LLString& utf8text) const
920{
921 LLWString wtext = utf8str_to_wstring(utf8text);
922 return getWidthF32(wtext.c_str(), 0, S32_MAX);
923}
924
925F32 LLFontGL::getWidthF32(const llwchar* wchars) const
926{
927 return getWidthF32(wchars, 0, S32_MAX);
928}
929
930F32 LLFontGL::getWidthF32(const LLString& utf8text, const S32 begin_offset, const S32 max_chars ) const
931{
932 LLWString wtext = utf8str_to_wstring(utf8text);
933 return getWidthF32(wtext.c_str(), begin_offset, max_chars);
934}
935
936F32 LLFontGL::getWidthF32(const llwchar* wchars, const S32 begin_offset, const S32 max_chars, BOOL use_embedded) const
937{
938 const S32 LAST_CHARACTER = LLFont::LAST_CHAR_FULL;
939
940 F32 cur_x = 0;
941 const S32 max_index = begin_offset + max_chars;
942 for (S32 i = begin_offset; i < max_index; i++)
943 {
944 const llwchar wch = wchars[i];
945 if (wch == 0)
946 {
947 break; // done
948 }
949 const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL;
950 if (ext_data)
951 {
952 // Handle crappy embedded hack
953 cur_x += getEmbeddedCharAdvance(ext_data);
954
955 if( ((i+1) < max_chars) && (i+1 < max_index))
956 {
957 cur_x += EXT_KERNING * sScaleX;
958 }
959 }
960 else
961 {
962 cur_x += getXAdvance(wch);
963 llwchar next_char = wchars[i+1];
964
965 if (((i + 1) < max_chars)
966 && next_char
967 && (next_char < LAST_CHARACTER))
968 {
969 // Kern this puppy.
970 cur_x += getXKerning(wch, next_char);
971 }
972 }
973 // Round after kerning.
974 cur_x = (F32)llfloor(cur_x + 0.5f);
975 }
976
977 return cur_x / sScaleX;
978}
979
980
981
982// Returns the max number of complete characters from text (up to max_chars) that can be drawn in max_pixels
983S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_chars,
984 BOOL end_on_word_boundary, const BOOL use_embedded,
985 F32* drawn_pixels) const
986{
987 if (!wchars || !wchars[0] || max_chars == 0)
988 {
989 return 0;
990 }
991
992 llassert(max_pixels >= 0.f);
993 llassert(max_chars >= 0);
994
995 BOOL clip = FALSE;
996 F32 cur_x = 0;
997 F32 drawn_x = 0;
998
999 S32 start_of_last_word = 0;
1000 BOOL in_word = FALSE;
1001
1002 F32 scaled_max_pixels = (F32)llceil(max_pixels * sScaleX);
1003
1004 S32 i;
1005 for (i=0; (i < max_chars); i++)
1006 {
1007 llwchar wch = wchars[i];
1008
1009 if(wch == 0)
1010 {
1011 // Null terminator. We're done.
1012 break;
1013 }
1014
1015 const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL;
1016 if (ext_data)
1017 {
1018 if (in_word)
1019 {
1020 in_word = FALSE;
1021 }
1022 else
1023 {
1024 start_of_last_word = i;
1025 }
1026 cur_x += getEmbeddedCharAdvance(ext_data);
1027
1028 if (scaled_max_pixels < cur_x)
1029 {
1030 clip = TRUE;
1031 break;
1032 }
1033
1034 if (((i+1) < max_chars) && wchars[i+1])
1035 {
1036 cur_x += EXT_KERNING * sScaleX;
1037 }
1038
1039 if( scaled_max_pixels < cur_x )
1040 {
1041 clip = TRUE;
1042 break;
1043 }
1044 }
1045 else
1046 {
1047 if (in_word)
1048 {
1049 if (iswspace(wch))
1050 {
1051 in_word = FALSE;
1052 }
1053 }
1054 else
1055 {
1056 start_of_last_word = i;
1057 if (!iswspace(wch))
1058 {
1059 in_word = TRUE;
1060 }
1061 }
1062
1063 cur_x += getXAdvance(wch);
1064
1065 if (scaled_max_pixels < cur_x)
1066 {
1067 clip = TRUE;
1068 break;
1069 }
1070
1071 if (((i+1) < max_chars) && wchars[i+1])
1072 {
1073 // Kern this puppy.
1074 cur_x += getXKerning(wch, wchars[i+1]);
1075 }
1076 }
1077 // Round after kerning.
1078 cur_x = (F32)llfloor(cur_x + 0.5f);
1079 drawn_x = cur_x;
1080 }
1081
1082 if( clip && end_on_word_boundary && (start_of_last_word != 0) )
1083 {
1084 i = start_of_last_word;
1085 }
1086 if (drawn_pixels)
1087 {
1088 *drawn_pixels = drawn_x;
1089 }
1090 return i;
1091}
1092
1093
1094S32 LLFontGL::firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_len, S32 start_pos, S32 max_chars) const
1095{
1096 if (!wchars || !wchars[0] || max_chars == 0)
1097 {
1098 return 0;
1099 }
1100
1101 F32 total_width = 0.0;
1102 S32 drawable_chars = 0;
1103
1104 F32 scaled_max_pixels = max_pixels * sScaleX;
1105
1106 S32 start = llmin(start_pos, text_len - 1);
1107 for (S32 i = start; i >= 0; i--)
1108 {
1109 llwchar wch = wchars[i];
1110
1111 const embedded_data_t* ext_data = getEmbeddedCharData(wch);
1112 if (ext_data)
1113 {
1114 F32 char_width = getEmbeddedCharAdvance(ext_data);
1115
1116 if( scaled_max_pixels < (total_width + char_width) )
1117 {
1118 break;
1119 }
1120
1121 total_width += char_width;
1122
1123 drawable_chars++;
1124 if( max_chars >= 0 && drawable_chars >= max_chars )
1125 {
1126 break;
1127 }
1128
1129 if ( i > 0 )
1130 {
1131 total_width += EXT_KERNING * sScaleX;
1132 }
1133
1134 // Round after kerning.
1135 total_width = (F32)llfloor(total_width + 0.5f);
1136 }
1137 else
1138 {
1139 F32 char_width = getXAdvance(wch);
1140 if( scaled_max_pixels < (total_width + char_width) )
1141 {
1142 break;
1143 }
1144
1145 total_width += char_width;
1146
1147 drawable_chars++;
1148 if( max_chars >= 0 && drawable_chars >= max_chars )
1149 {
1150 break;
1151 }
1152
1153 if ( i > 0 )
1154 {
1155 // Kerning
1156 total_width += getXKerning(wchars[i-1], wch);
1157 }
1158
1159 // Round after kerning.
1160 total_width = (F32)llfloor(total_width + 0.5f);
1161 }
1162 }
1163
1164 return text_len - drawable_chars;
1165}
1166
1167
1168S32 LLFontGL::charFromPixelOffset(const llwchar* wchars, const S32 begin_offset, F32 target_x, F32 max_pixels, S32 max_chars, BOOL round, BOOL use_embedded) const
1169{
1170 if (!wchars || !wchars[0] || max_chars == 0)
1171 {
1172 return 0;
1173 }
1174
1175 F32 cur_x = 0;
1176 S32 pos = 0;
1177
1178 target_x *= sScaleX;
1179
1180 // max_chars is S32_MAX by default, so make sure we don't get overflow
1181 const S32 max_index = begin_offset + llmin(S32_MAX - begin_offset, max_chars);
1182
1183 F32 scaled_max_pixels = max_pixels * sScaleX;
1184
1185 for (S32 i = begin_offset; (i < max_index); i++)
1186 {
1187 llwchar wch = wchars[i];
1188 if (!wch)
1189 {
1190 break; // done
1191 }
1192 const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL;
1193 if (ext_data)
1194 {
1195 F32 ext_advance = getEmbeddedCharAdvance(ext_data);
1196
1197 if (round)
1198 {
1199 // Note: if the mouse is on the left half of the character, the pick is to the character's left
1200 // If it's on the right half, the pick is to the right.
1201 if (target_x < cur_x + ext_advance/2)
1202 {
1203 break;
1204 }
1205 }
1206 else
1207 {
1208 if (target_x < cur_x + ext_advance)
1209 {
1210 break;
1211 }
1212 }
1213
1214 if (scaled_max_pixels < cur_x + ext_advance)
1215 {
1216 break;
1217 }
1218
1219 pos++;
1220 cur_x += ext_advance;
1221
1222 if (((i + 1) < max_index)
1223 && (wchars[(i + 1)]))
1224 {
1225 cur_x += EXT_KERNING * sScaleX;
1226 }
1227 // Round after kerning.
1228 cur_x = (F32)llfloor(cur_x + 0.5f);
1229 }
1230 else
1231 {
1232 F32 char_width = getXAdvance(wch);
1233
1234 if (round)
1235 {
1236 // Note: if the mouse is on the left half of the character, the pick is to the character's left
1237 // If it's on the right half, the pick is to the right.
1238 if (target_x < cur_x + char_width*0.5f)
1239 {
1240 break;
1241 }
1242 }
1243 else if (target_x < cur_x + char_width)
1244 {
1245 break;
1246 }
1247
1248 if (scaled_max_pixels < cur_x + char_width)
1249 {
1250 break;
1251 }
1252
1253 pos++;
1254 cur_x += char_width;
1255
1256 if (((i + 1) < max_index)
1257 && (wchars[(i + 1)]))
1258 {
1259 llwchar next_char = wchars[i + 1];
1260 // Kern this puppy.
1261 cur_x += getXKerning(wch, next_char);
1262 }
1263
1264 // Round after kerning.
1265 cur_x = (F32)llfloor(cur_x + 0.5f);
1266 }
1267 }
1268
1269 return pos;
1270}
1271
1272
1273const LLFontGL::embedded_data_t* LLFontGL::getEmbeddedCharData(const llwchar wch) const
1274{
1275 // Handle crappy embedded hack
1276 embedded_map_t::const_iterator iter = mEmbeddedChars.find(wch);
1277 if (iter != mEmbeddedChars.end())
1278 {
1279 return iter->second;
1280 }
1281 return NULL;
1282}
1283
1284
1285F32 LLFontGL::getEmbeddedCharAdvance(const embedded_data_t* ext_data) const
1286{
1287 const LLWString& label = ext_data->mLabel;
1288 LLImageGL* ext_image = ext_data->mImage;
1289
1290 F32 ext_width = (F32)ext_image->getWidth();
1291 if( !label.empty() )
1292 {
1293 ext_width += (EXT_X_BEARING + gExtCharFont->getWidthF32(label.c_str())) * sScaleX;
1294 }
1295
1296 return (EXT_X_BEARING * sScaleX) + ext_width;
1297}
1298
1299
1300void LLFontGL::clearEmbeddedChars()
1301{
1302 for_each(mEmbeddedChars.begin(), mEmbeddedChars.end(), DeletePairedPointer());
1303 mEmbeddedChars.clear();
1304}
1305
1306void LLFontGL::addEmbeddedChar( llwchar wc, LLImageGL* image, const LLString& label )
1307{
1308 LLWString wlabel = utf8str_to_wstring(label);
1309 addEmbeddedChar(wc, image, wlabel);
1310}
1311
1312void LLFontGL::addEmbeddedChar( llwchar wc, LLImageGL* image, const LLWString& wlabel )
1313{
1314 embedded_data_t* ext_data = new embedded_data_t(image, wlabel);
1315 mEmbeddedChars[wc] = ext_data;
1316}
1317
1318void LLFontGL::removeEmbeddedChar( llwchar wc )
1319{
1320 embedded_map_t::iterator iter = mEmbeddedChars.find(wc);
1321 if (iter != mEmbeddedChars.end())
1322 {
1323 delete iter->second;
1324 mEmbeddedChars.erase(wc);
1325 }
1326}
1327
1328// static
1329LLString LLFontGL::nameFromFont(const LLFontGL* fontp)
1330{
1331 if (fontp == sSansSerifHuge)
1332 {
1333 return LLString("SansSerifHude");
1334 }
1335 else if (fontp == sSansSerifSmall)
1336 {
1337 return LLString("SansSerifSmall");
1338 }
1339 else if (fontp == sSansSerif)
1340 {
1341 return LLString("SansSerif");
1342 }
1343 else if (fontp == sSansSerifBig)
1344 {
1345 return LLString("SansSerifBig");
1346 }
1347 else if (fontp == sSansSerifBold)
1348 {
1349 return LLString("SansSerifBold");
1350 }
1351 else if (fontp == sMonospace)
1352 {
1353 return LLString("Monospace");
1354 }
1355 else
1356 {
1357 return LLString();
1358 }
1359}
1360
1361// static
1362LLFontGL* LLFontGL::fontFromName(const LLString& font_name)
1363{
1364 LLFontGL* gl_font = NULL;
1365 if (font_name == "SansSerifHuge")
1366 {
1367 gl_font = LLFontGL::sSansSerifHuge;
1368 }
1369 else if (font_name == "SansSerifSmall")
1370 {
1371 gl_font = LLFontGL::sSansSerifSmall;
1372 }
1373 else if (font_name == "SansSerif")
1374 {
1375 gl_font = LLFontGL::sSansSerif;
1376 }
1377 else if (font_name == "SansSerifBig")
1378 {
1379 gl_font = LLFontGL::sSansSerifBig;
1380 }
1381 else if (font_name == "SansSerifBold")
1382 {
1383 gl_font = LLFontGL::sSansSerifBold;
1384 }
1385 else if (font_name == "Monospace")
1386 {
1387 gl_font = LLFontGL::sMonospace;
1388 }
1389 return gl_font;
1390}
1391
1392// static
1393LLString LLFontGL::nameFromHAlign(LLFontGL::HAlign align)
1394{
1395 if (align == LEFT) return LLString("left");
1396 else if (align == RIGHT) return LLString("right");
1397 else if (align == HCENTER) return LLString("center");
1398 else return LLString();
1399}
1400
1401// static
1402LLFontGL::HAlign LLFontGL::hAlignFromName(const LLString& name)
1403{
1404 LLFontGL::HAlign gl_hfont_align = LLFontGL::LEFT;
1405 if (name == "left")
1406 {
1407 gl_hfont_align = LLFontGL::LEFT;
1408 }
1409 else if (name == "right")
1410 {
1411 gl_hfont_align = LLFontGL::RIGHT;
1412 }
1413 else if (name == "center")
1414 {
1415 gl_hfont_align = LLFontGL::HCENTER;
1416 }
1417 //else leave left
1418 return gl_hfont_align;
1419}
1420
1421// static
1422LLString LLFontGL::nameFromVAlign(LLFontGL::VAlign align)
1423{
1424 if (align == TOP) return LLString("top");
1425 else if (align == VCENTER) return LLString("center");
1426 else if (align == BASELINE) return LLString("baseline");
1427 else if (align == BOTTOM) return LLString("bottom");
1428 else return LLString();
1429}
1430
1431// static
1432LLFontGL::VAlign LLFontGL::vAlignFromName(const LLString& name)
1433{
1434 LLFontGL::VAlign gl_vfont_align = LLFontGL::BASELINE;
1435 if (name == "top")
1436 {
1437 gl_vfont_align = LLFontGL::TOP;
1438 }
1439 else if (name == "center")
1440 {
1441 gl_vfont_align = LLFontGL::VCENTER;
1442 }
1443 else if (name == "baseline")
1444 {
1445 gl_vfont_align = LLFontGL::BASELINE;
1446 }
1447 else if (name == "bottom")
1448 {
1449 gl_vfont_align = LLFontGL::BOTTOM;
1450 }
1451 //else leave baseline
1452 return gl_vfont_align;
1453}
diff --git a/linden/indra/llrender/llfontgl.h b/linden/indra/llrender/llfontgl.h
new file mode 100644
index 0000000..bcb8dfb
--- /dev/null
+++ b/linden/indra/llrender/llfontgl.h
@@ -0,0 +1,252 @@
1/**
2 * @file llfontgl.h
3 * @author Doug Soo
4 * @brief Wrapper around FreeType
5 *
6 * Copyright (c) 2001-2007, Linden Research, Inc.
7 *
8 * The source code in this file ("Source Code") is provided by Linden Lab
9 * to you under the terms of the GNU General Public License, version 2.0
10 * ("GPL"), unless you have obtained a separate licensing agreement
11 * ("Other License"), formally executed by you and Linden Lab. Terms of
12 * the GPL can be found in doc/GPL-license.txt in this distribution, or
13 * online at http://secondlife.com/developers/opensource/gplv2
14 *
15 * There are special exceptions to the terms and conditions of the GPL as
16 * it is applied to this Source Code. View the full text of the exception
17 * in the file doc/FLOSS-exception.txt in this software distribution, or
18 * online at http://secondlife.com/developers/opensource/flossexception
19 *
20 * By copying, modifying or distributing this software, you acknowledge
21 * that you have read and understood your obligations described above,
22 * and agree to abide by those obligations.
23 *
24 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
25 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
26 * COMPLETENESS OR PERFORMANCE.
27 */
28
29#ifndef LL_LLFONTGL_H
30#define LL_LLFONTGL_H
31
32#include "llfont.h"
33#include "llimagegl.h"
34#include "v2math.h"
35#include "llcoord.h"
36
37class LLColor4;
38
39class LLFontGL : public LLFont
40{
41public:
42 enum HAlign
43 {
44 // Horizontal location of x,y coord to render.
45 LEFT = 0, // Left align
46 RIGHT = 1, // Right align
47 HCENTER = 2, // Center
48 };
49
50 enum VAlign
51 {
52 // Vertical location of x,y coord to render.
53 TOP = 3, // Top align
54 VCENTER = 4, // Center
55 BASELINE = 5, // Baseline
56 BOTTOM = 6 // Bottom
57 };
58
59 enum StyleFlags
60 {
61 // text style to render. May be combined (these are bit flags)
62 NORMAL = 0,
63 BOLD = 1,
64 ITALIC = 2,
65 UNDERLINE = 4,
66 DROP_SHADOW = 8
67 };
68
69 // Takes a string with potentially several flags, i.e. "NORMAL|BOLD|ITALIC"
70 static U8 getStyleFromString(const LLString &style);
71
72 LLFontGL();
73 LLFontGL(const LLFontGL &source);
74 ~LLFontGL();
75
76 void init(); // Internal init, or reinitialization
77 void reset(); // Reset a font after GL cleanup. ONLY works on an already loaded font.
78
79 LLFontGL &operator=(const LLFontGL &source);
80
81 static BOOL initDefaultFonts(F32 screen_dpi, F32 x_scale, F32 y_scale,
82 const LLString& monospace_file, F32 monospace_size,
83 const LLString& sansserif_file,
84 const LLString& sansserif_fallback_file, F32 ss_fallback_scale,
85 F32 small_size, F32 medium_size, F32 large_size, F32 huge_size,
86 const LLString& sansserif_bold_file, F32 bold_size,
87 const LLString& app_dir = LLString::null);
88
89 static void destroyDefaultFonts();
90 static void destroyGL();
91
92 static bool loadFaceFallback(LLFontList *fontp, const LLString& fontname, const F32 point_size);
93 static bool loadFace(LLFontGL *fontp, const LLString& fontname, const F32 point_size, LLFontList *fallback_fontp);
94 BOOL loadFace(const LLString& filename, const F32 point_size, const F32 vert_dpi, const F32 horz_dpi);
95
96
97 S32 renderUTF8(const LLString &text, const S32 begin_offset,
98 S32 x, S32 y,
99 const LLColor4 &color) const
100 {
101 return renderUTF8(text, begin_offset, (F32)x, (F32)y, color,
102 LEFT, BASELINE, NORMAL,
103 S32_MAX, S32_MAX, NULL, FALSE);
104 }
105
106 S32 renderUTF8(const LLString &text, const S32 begin_offset,
107 S32 x, S32 y,
108 const LLColor4 &color,
109 HAlign halign, VAlign valign, U8 style = NORMAL) const
110 {
111 return renderUTF8(text, begin_offset, (F32)x, (F32)y, color,
112 halign, valign, style,
113 S32_MAX, S32_MAX, NULL, FALSE);
114 }
115
116 // renderUTF8 does a conversion, so is slower!
117 S32 renderUTF8(const LLString &text,
118 S32 begin_offset,
119 F32 x, F32 y,
120 const LLColor4 &color,
121 HAlign halign,
122 VAlign valign,
123 U8 style,
124 S32 max_chars,
125 S32 max_pixels,
126 F32* right_x,
127 BOOL use_ellipses) const;
128
129 S32 render(const LLWString &text, const S32 begin_offset,
130 F32 x, F32 y,
131 const LLColor4 &color) const
132 {
133 return render(text, begin_offset, x, y, color,
134 LEFT, BASELINE, NORMAL,
135 S32_MAX, S32_MAX, NULL, FALSE, FALSE);
136 }
137
138
139 S32 render(const LLWString &text,
140 S32 begin_offset,
141 F32 x, F32 y,
142 const LLColor4 &color,
143 HAlign halign = LEFT,
144 VAlign valign = BASELINE,
145 U8 style = NORMAL,
146 S32 max_chars = S32_MAX,
147 S32 max_pixels = S32_MAX,
148 F32* right_x=NULL,
149 BOOL use_embedded = FALSE,
150 BOOL use_ellipses = FALSE) const;
151
152 // font metrics - override for LLFont that returns units of virtual pixels
153 /*virtual*/ F32 getLineHeight() const { return (F32)llround(mLineHeight / sScaleY); }
154 /*virtual*/ F32 getAscenderHeight() const { return (F32)llround(mAscender / sScaleY); }
155 /*virtual*/ F32 getDescenderHeight() const { return (F32)llround(mDescender / sScaleY); }
156
157 virtual S32 getWidth(const LLString& utf8text) const;
158 virtual S32 getWidth(const llwchar* wchars) const;
159 virtual S32 getWidth(const LLString& utf8text, const S32 offset, const S32 max_chars ) const;
160 virtual S32 getWidth(const llwchar* wchars, const S32 offset, const S32 max_chars, BOOL use_embedded = FALSE) const;
161
162 virtual F32 getWidthF32(const LLString& utf8text) const;
163 virtual F32 getWidthF32(const llwchar* wchars) const;
164 virtual F32 getWidthF32(const LLString& text, const S32 offset, const S32 max_chars ) const;
165 virtual F32 getWidthF32(const llwchar* wchars, const S32 offset, const S32 max_chars, BOOL use_embedded = FALSE ) const;
166
167 // The following are called often, frequently with large buffers, so do not use a string interface
168
169 // Returns the max number of complete characters from text (up to max_chars) that can be drawn in max_pixels
170 virtual S32 maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_chars = S32_MAX,
171 BOOL end_on_word_boundary = FALSE, const BOOL use_embedded = FALSE,
172 F32* drawn_pixels = NULL) const;
173
174 // Returns the index of the first complete characters from text that can be drawn in max_pixels
175 // starting on the right side (at character start_pos).
176 virtual S32 firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_len, S32 start_pos=S32_MAX, S32 max_chars = S32_MAX) const;
177
178 // Returns the index of the character closest to pixel position x (ignoring text to the right of max_pixels and max_chars)
179 virtual S32 charFromPixelOffset(const llwchar* wchars, const S32 char_offset,
180 F32 x, F32 max_pixels=F32_MAX, S32 max_chars = S32_MAX,
181 BOOL round = TRUE, BOOL use_embedded = FALSE) const;
182
183
184 LLImageGL *getImageGL() const;
185
186 void addEmbeddedChar( llwchar wc, LLImageGL* image, const LLString& label);
187 void addEmbeddedChar( llwchar wc, LLImageGL* image, const LLWString& label);
188 void removeEmbeddedChar( llwchar wc );
189
190 static LLString nameFromFont(const LLFontGL* fontp);
191 static LLFontGL* fontFromName(const LLString& name);
192
193 static LLString nameFromHAlign(LLFontGL::HAlign align);
194 static LLFontGL::HAlign hAlignFromName(const LLString& name);
195
196 static LLString nameFromVAlign(LLFontGL::VAlign align);
197 static LLFontGL::VAlign vAlignFromName(const LLString& name);
198
199protected:
200 struct embedded_data_t
201 {
202 embedded_data_t(LLImageGL* image, const LLWString& label) : mImage(image), mLabel(label) {}
203 LLPointer<LLImageGL> mImage;
204 LLWString mLabel;
205 };
206 const embedded_data_t* getEmbeddedCharData(const llwchar wch) const;
207 F32 getEmbeddedCharAdvance(const embedded_data_t* ext_data) const;
208 void clearEmbeddedChars();
209
210public:
211 static F32 sVertDPI;
212 static F32 sHorizDPI;
213 static F32 sScaleX;
214 static F32 sScaleY;
215 static LLString sAppDir; // For loading fonts
216
217 static LLFontGL* sMonospace; // medium
218
219 static LLFontGL* sSansSerifSmall; // small
220 static LLFontList* sSSSmallFallback;
221 static LLFontGL* sSansSerif; // medium
222 static LLFontList* sSSFallback;
223 static LLFontGL* sSansSerifBig; // large
224 static LLFontList* sSSBigFallback;
225 static LLFontGL* sSansSerifHuge; // very large
226 static LLFontList* sSSHugeFallback;
227
228 static LLFontGL* sSansSerifBold; // medium, bolded
229 static LLFontList* sSSBoldFallback;
230
231 static LLColor4 sShadowColor;
232
233 friend class LLTextBillboard;
234 friend class LLHUDText;
235
236protected:
237 /*virtual*/ BOOL addChar(const llwchar wch);
238 static LLString getFontPathLocal();
239 static LLString getFontPathSystem();
240
241protected:
242 LLPointer<LLImageRaw> mRawImageGLp;
243 LLPointer<LLImageGL> mImageGLp;
244 typedef std::map<llwchar,embedded_data_t*> embedded_map_t;
245 embedded_map_t mEmbeddedChars;
246
247public:
248 static LLCoordFont sCurOrigin;
249 static std::vector<LLCoordFont> sOriginStack;
250};
251
252#endif
diff --git a/linden/indra/llrender/llgldbg.cpp b/linden/indra/llrender/llgldbg.cpp
new file mode 100644
index 0000000..4d9f5f9
--- /dev/null
+++ b/linden/indra/llrender/llgldbg.cpp
@@ -0,0 +1,224 @@
1/**
2 * @file llgldbg.cpp
3 * @brief Definitions for OpenGL debugging support
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28// This file sets some global GL parameters, and implements some
29// useful functions for GL operations.
30
31#include "linden_common.h"
32
33#include "llgldbg.h"
34
35#include "llgl.h"
36#include "llglheaders.h"
37
38
39//------------------------------------------------------------------------
40// cmstr()
41//------------------------------------------------------------------------
42char *cmstr(int i)
43{
44 switch( i )
45 {
46 case GL_EMISSION: return "GL_EMISSION";
47 case GL_AMBIENT: return "GL_AMBIENT";
48 case GL_DIFFUSE: return "GL_DIFFUSE";
49 case GL_SPECULAR: return "GL_SPECULAR";
50 case GL_AMBIENT_AND_DIFFUSE: return "GL_AMBIENT_AND_DIFFUSE";
51 }
52 return "UNKNOWN";
53}
54
55//------------------------------------------------------------------------
56// facestr()
57//------------------------------------------------------------------------
58char *facestr(int i)
59{
60 switch( i )
61 {
62 case GL_FRONT: return "GL_FRONT";
63 case GL_BACK: return "GL_BACK";
64 case GL_FRONT_AND_BACK: return "GL_FRONT_AND_BACK";
65 }
66 return "UNKNOWN";
67}
68
69//------------------------------------------------------------------------
70// boolstr()
71//------------------------------------------------------------------------
72const char *boolstr(int b)
73{
74 return b ? "GL_TRUE" : "GL_FALSE";
75}
76
77//------------------------------------------------------------------------
78// fv4()
79//------------------------------------------------------------------------
80char *fv4(F32 *f)
81{
82 static char str[128];
83 sprintf(str, "%8.3f %8.3f %8.3f %8.3f", f[0], f[1], f[2], f[3]);
84 return str;
85}
86
87//------------------------------------------------------------------------
88// fv3()
89//------------------------------------------------------------------------
90char *fv3(F32 *f)
91{
92 static char str[128];
93 sprintf(str, "%8.3f, %8.3f, %8.3f", f[0], f[1], f[2]);
94 return str;
95}
96
97//------------------------------------------------------------------------
98// fv1()
99//------------------------------------------------------------------------
100char *fv1(F32 *f)
101{
102 static char str[128];
103 sprintf(str, "%8.3f", f[0]);
104 return str;
105}
106
107//------------------------------------------------------------------------
108// llgl_dump()
109//------------------------------------------------------------------------
110void llgl_dump()
111{
112 int i;
113 F32 fv[16];
114 GLboolean b;
115
116 llinfos << "==========================" << llendl;
117 llinfos << "OpenGL State" << llendl;
118 llinfos << "==========================" << llendl;
119
120 llinfos << "-----------------------------------" << llendl;
121 llinfos << "Current Values" << llendl;
122 llinfos << "-----------------------------------" << llendl;
123
124 glGetFloatv(GL_CURRENT_COLOR, fv);
125 llinfos << "GL_CURRENT_COLOR : " << fv4(fv) << llendl;
126
127 glGetFloatv(GL_CURRENT_NORMAL, fv);
128 llinfos << "GL_CURRENT_NORMAL : " << fv3(fv) << llendl;
129
130 llinfos << "-----------------------------------" << llendl;
131 llinfos << "Lighting" << llendl;
132 llinfos << "-----------------------------------" << llendl;
133
134 llinfos << "GL_LIGHTING : " << boolstr(glIsEnabled(GL_LIGHTING)) << llendl;
135
136 llinfos << "GL_COLOR_MATERIAL : " << boolstr(glIsEnabled(GL_COLOR_MATERIAL)) << llendl;
137
138 glGetIntegerv(GL_COLOR_MATERIAL_PARAMETER, (GLint*)&i);
139 llinfos << "GL_COLOR_MATERIAL_PARAMETER: " << cmstr(i) << llendl;
140
141 glGetIntegerv(GL_COLOR_MATERIAL_FACE, (GLint*)&i);
142 llinfos << "GL_COLOR_MATERIAL_FACE : " << facestr(i) << llendl;
143
144 fv[0] = fv[1] = fv[2] = fv[3] = 12345.6789f;
145 glGetMaterialfv(GL_FRONT, GL_AMBIENT, fv);
146 llinfos << "GL_AMBIENT material : " << fv4(fv) << llendl;
147
148 fv[0] = fv[1] = fv[2] = fv[3] = 12345.6789f;
149 glGetMaterialfv(GL_FRONT, GL_DIFFUSE, fv);
150 llinfos << "GL_DIFFUSE material : " << fv4(fv) << llendl;
151
152 fv[0] = fv[1] = fv[2] = fv[3] = 12345.6789f;
153 glGetMaterialfv(GL_FRONT, GL_SPECULAR, fv);
154 llinfos << "GL_SPECULAR material : " << fv4(fv) << llendl;
155
156 fv[0] = fv[1] = fv[2] = fv[3] = 12345.6789f;
157 glGetMaterialfv(GL_FRONT, GL_EMISSION, fv);
158 llinfos << "GL_EMISSION material : " << fv4(fv) << llendl;
159
160 fv[0] = fv[1] = fv[2] = fv[3] = 12345.6789f;
161 glGetMaterialfv(GL_FRONT, GL_SHININESS, fv);
162 llinfos << "GL_SHININESS material : " << fv1(fv) << llendl;
163
164 fv[0] = fv[1] = fv[2] = fv[3] = 12345.6789f;
165 glGetFloatv(GL_LIGHT_MODEL_AMBIENT, fv);
166 llinfos << "GL_LIGHT_MODEL_AMBIENT : " << fv4(fv) << llendl;
167
168 glGetBooleanv(GL_LIGHT_MODEL_LOCAL_VIEWER, &b);
169 llinfos << "GL_LIGHT_MODEL_LOCAL_VIEWER: " << boolstr(b) << llendl;
170
171 glGetBooleanv(GL_LIGHT_MODEL_TWO_SIDE, &b);
172 llinfos << "GL_LIGHT_MODEL_TWO_SIDE : " << boolstr(b) << llendl;
173
174 for (int l=0; l<8; l++)
175 {
176 b = glIsEnabled(GL_LIGHT0+l);
177 llinfos << "GL_LIGHT" << l << " : " << boolstr(b) << llendl;
178
179 if (!b)
180 continue;
181
182 glGetLightfv(GL_LIGHT0+l, GL_AMBIENT, fv);
183 llinfos << " GL_AMBIENT light : " << fv4(fv) << llendl;
184
185 glGetLightfv(GL_LIGHT0+l, GL_DIFFUSE, fv);
186 llinfos << " GL_DIFFUSE light : " << fv4(fv) << llendl;
187
188 glGetLightfv(GL_LIGHT0+l, GL_SPECULAR, fv);
189 llinfos << " GL_SPECULAR light : " << fv4(fv) << llendl;
190
191 glGetLightfv(GL_LIGHT0+l, GL_POSITION, fv);
192 llinfos << " GL_POSITION light : " << fv4(fv) << llendl;
193
194 glGetLightfv(GL_LIGHT0+l, GL_CONSTANT_ATTENUATION, fv);
195 llinfos << " GL_CONSTANT_ATTENUATION : " << fv1(fv) << llendl;
196
197 glGetLightfv(GL_LIGHT0+l, GL_QUADRATIC_ATTENUATION, fv);
198 llinfos << " GL_QUADRATIC_ATTENUATION : " << fv1(fv) << llendl;
199
200 glGetLightfv(GL_LIGHT0+l, GL_SPOT_DIRECTION, fv);
201 llinfos << " GL_SPOT_DIRECTION : " << fv4(fv) << llendl;
202
203 glGetLightfv(GL_LIGHT0+l, GL_SPOT_EXPONENT, fv);
204 llinfos << " GL_SPOT_EXPONENT : " << fv1(fv) << llendl;
205
206 glGetLightfv(GL_LIGHT0+l, GL_SPOT_CUTOFF, fv);
207 llinfos << " GL_SPOT_CUTOFF : " << fv1(fv) << llendl;
208 }
209
210 llinfos << "-----------------------------------" << llendl;
211 llinfos << "Pixel Operations" << llendl;
212 llinfos << "-----------------------------------" << llendl;
213
214 llinfos << "GL_ALPHA_TEST : " << boolstr(glIsEnabled(GL_ALPHA_TEST)) << llendl;
215 llinfos << "GL_DEPTH_TEST : " << boolstr(glIsEnabled(GL_DEPTH_TEST)) << llendl;
216
217 glGetBooleanv(GL_DEPTH_WRITEMASK, &b);
218 llinfos << "GL_DEPTH_WRITEMASK : " << boolstr(b) << llendl;
219
220 llinfos << "GL_BLEND : " << boolstr(glIsEnabled(GL_BLEND)) << llendl;
221 llinfos << "GL_DITHER : " << boolstr(glIsEnabled(GL_DITHER)) << llendl;
222}
223
224// End
diff --git a/linden/indra/llrender/llgldbg.h b/linden/indra/llrender/llgldbg.h
new file mode 100644
index 0000000..39be147
--- /dev/null
+++ b/linden/indra/llrender/llgldbg.h
@@ -0,0 +1,35 @@
1/**
2 * @file llgldbg.h
3 * @brief Definitions for OpenGL debugging support
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LL_LLGLDBG_H
29#define LL_LLGLDBG_H
30
31// Dumps the current OpenGL state to the console.
32void llgl_dump();
33
34
35#endif // LL_LLGLDBG_H
diff --git a/linden/indra/llrender/llimagegl.cpp b/linden/indra/llrender/llimagegl.cpp
new file mode 100644
index 0000000..5ea7322
--- /dev/null
+++ b/linden/indra/llrender/llimagegl.cpp
@@ -0,0 +1,1224 @@
1/**
2 * @file llimagegl.cpp
3 * @brief Generic GL image handler
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28
29// TODO: create 2 classes for images w/ and w/o discard levels?
30
31#include "linden_common.h"
32
33#include "llimagegl.h"
34
35#include "llerror.h"
36#include "llimage.h"
37
38#include "llmath.h"
39#include "llgl.h"
40
41//----------------------------------------------------------------------------
42
43const F32 MIN_TEXTURE_LIFETIME = 10.f;
44
45//statics
46LLGLuint LLImageGL::sCurrentBoundTextures[MAX_GL_TEXTURE_UNITS] = { 0 };
47
48S32 LLImageGL::sGlobalTextureMemory = 0;
49S32 LLImageGL::sBoundTextureMemory = 0;
50S32 LLImageGL::sCurBoundTextureMemory = 0;
51S32 LLImageGL::sCount = 0;
52
53BOOL LLImageGL::sGlobalUseAnisotropic = FALSE;
54F32 LLImageGL::sLastFrameTime = 0.f;
55
56std::set<LLImageGL*> LLImageGL::sImageList;
57
58//----------------------------------------------------------------------------
59
60//static
61S32 LLImageGL::dataFormatBits(S32 dataformat)
62{
63 switch (dataformat)
64 {
65 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return 4;
66 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: return 8;
67 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: return 8;
68 case GL_LUMINANCE: return 8;
69 case GL_ALPHA: return 8;
70 case GL_COLOR_INDEX: return 8;
71 case GL_LUMINANCE_ALPHA: return 16;
72 case GL_RGB: return 24;
73 case GL_RGB8: return 24;
74 case GL_RGBA: return 32;
75 case GL_BGRA: return 32; // Used for QuickTime media textures on the Mac
76 default:
77 llerrs << "LLImageGL::Unknown format: " << dataformat << llendl;
78 return 0;
79 }
80}
81
82//static
83S32 LLImageGL::dataFormatBytes(S32 dataformat, S32 width, S32 height)
84{
85 if (dataformat >= GL_COMPRESSED_RGB_S3TC_DXT1_EXT &&
86 dataformat <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
87 {
88 if (width < 4) width = 4;
89 if (height < 4) height = 4;
90 }
91 S32 bytes ((width*height*dataFormatBits(dataformat)+7)>>3);
92 S32 aligned = (bytes+3)&~3;
93 return aligned;
94}
95
96//static
97S32 LLImageGL::dataFormatComponents(S32 dataformat)
98{
99 switch (dataformat)
100 {
101 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return 3;
102 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: return 4;
103 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: return 4;
104 case GL_LUMINANCE: return 1;
105 case GL_ALPHA: return 1;
106 case GL_COLOR_INDEX: return 1;
107 case GL_LUMINANCE_ALPHA: return 2;
108 case GL_RGB: return 3;
109 case GL_RGBA: return 4;
110 case GL_BGRA: return 4; // Used for QuickTime media textures on the Mac
111 default:
112 llerrs << "LLImageGL::Unknown format: " << dataformat << llendl;
113 return 0;
114 }
115}
116
117//----------------------------------------------------------------------------
118
119// static
120void LLImageGL::bindExternalTexture(LLGLuint gl_name, S32 stage, LLGLenum bind_target )
121{
122 glActiveTextureARB(GL_TEXTURE0_ARB + stage);
123 glClientActiveTextureARB(GL_TEXTURE0_ARB + stage);
124 glBindTexture(bind_target, gl_name);
125 sCurrentBoundTextures[stage] = gl_name;
126}
127
128// static
129void LLImageGL::unbindTexture(S32 stage, LLGLenum bind_target)
130{
131 glActiveTextureARB(GL_TEXTURE0_ARB + stage);
132 glClientActiveTextureARB(GL_TEXTURE0_ARB + stage);
133 glBindTexture(bind_target, 0);
134 sCurrentBoundTextures[stage] = 0;
135}
136
137// static
138void LLImageGL::updateStats(F32 current_time)
139{
140 sLastFrameTime = current_time;
141 sBoundTextureMemory = sCurBoundTextureMemory;
142 sCurBoundTextureMemory = 0;
143}
144
145//static
146S32 LLImageGL::updateBoundTexMem(const S32 delta)
147{
148 LLImageGL::sCurBoundTextureMemory += delta;
149 return LLImageGL::sCurBoundTextureMemory;
150}
151
152//----------------------------------------------------------------------------
153
154//static
155void LLImageGL::destroyGL(BOOL save_state)
156{
157 for (S32 stage = 0; stage < gGLManager.mNumTextureUnits; stage++)
158 {
159 LLImageGL::unbindTexture(stage, GL_TEXTURE_2D);
160 }
161 for (std::set<LLImageGL*>::iterator iter = sImageList.begin();
162 iter != sImageList.end(); iter++)
163 {
164 LLImageGL* glimage = *iter;
165 if (glimage->mTexName && glimage->mComponents)
166 {
167 if (save_state)
168 {
169 glimage->mSaveData = new LLImageRaw;
170 glimage->readBackRaw(glimage->mCurrentDiscardLevel, glimage->mSaveData);
171 }
172 glimage->destroyGLTexture();
173 stop_glerror();
174 }
175 }
176}
177
178//static
179void LLImageGL::restoreGL()
180{
181 for (std::set<LLImageGL*>::iterator iter = sImageList.begin();
182 iter != sImageList.end(); iter++)
183 {
184 LLImageGL* glimage = *iter;
185 if (glimage->mSaveData.notNull() && glimage->mSaveData->getComponents())
186 {
187 if (glimage->getComponents())
188 {
189 glimage->createGLTexture(glimage->mCurrentDiscardLevel, glimage->mSaveData);
190 stop_glerror();
191 }
192 glimage->mSaveData = NULL; // deletes data
193 }
194 }
195}
196
197//----------------------------------------------------------------------------
198
199//static
200BOOL LLImageGL::create(LLPointer<LLImageGL>& dest, BOOL usemipmaps)
201{
202 dest = new LLImageGL(usemipmaps);
203 return TRUE;
204}
205
206BOOL LLImageGL::create(LLPointer<LLImageGL>& dest, U32 width, U32 height, U8 components, BOOL usemipmaps)
207{
208 dest = new LLImageGL(width, height, components, usemipmaps);
209 return TRUE;
210}
211
212BOOL LLImageGL::create(LLPointer<LLImageGL>& dest, const LLImageRaw* imageraw, BOOL usemipmaps)
213{
214 dest = new LLImageGL(imageraw, usemipmaps);
215 return TRUE;
216}
217
218//----------------------------------------------------------------------------
219
220LLImageGL::LLImageGL(BOOL usemipmaps)
221 : mSaveData(0)
222{
223 init(usemipmaps);
224 setSize(0, 0, 0);
225 sImageList.insert(this);
226 sCount++;
227}
228
229LLImageGL::LLImageGL(U32 width, U32 height, U8 components, BOOL usemipmaps)
230 : mSaveData(0)
231{
232 llassert( components <= 4 );
233 init(usemipmaps);
234 setSize(width, height, components);
235 sImageList.insert(this);
236 sCount++;
237}
238
239LLImageGL::LLImageGL(const LLImageRaw* imageraw, BOOL usemipmaps)
240 : mSaveData(0)
241{
242 init(usemipmaps);
243 setSize(0, 0, 0);
244 sImageList.insert(this);
245 sCount++;
246 createGLTexture(0, imageraw);
247}
248
249LLImageGL::~LLImageGL()
250{
251 LLImageGL::cleanup();
252 sImageList.erase(this);
253 sCount--;
254}
255
256void LLImageGL::init(BOOL usemipmaps)
257{
258#ifdef DEBUG_MISS
259 mMissed = FALSE;
260#endif
261
262 mTextureMemory = 0;
263 mLastBindTime = 0.f;
264
265 mTarget = GL_TEXTURE_2D;
266 mBindTarget = GL_TEXTURE_2D;
267 mUseMipMaps = usemipmaps;
268 mHasMipMaps = FALSE;
269 mAutoGenMips = FALSE;
270 mTexName = 0;
271 mIsResident = 0;
272 mClampS = FALSE;
273 mClampT = FALSE;
274 mMipFilterNearest = FALSE;
275 mWidth = 0;
276 mHeight = 0;
277 mComponents = 0;
278
279 mMaxDiscardLevel = MAX_DISCARD_LEVEL;
280 mCurrentDiscardLevel = -1;
281 mDontDiscard = FALSE;
282
283 mFormatInternal = -1;
284 mFormatPrimary = (LLGLenum) 0;
285 mFormatType = GL_UNSIGNED_BYTE;
286 mFormatSwapBytes = FALSE;
287 mHasExplicitFormat = FALSE;
288}
289
290void LLImageGL::cleanup()
291{
292 if (!gGLManager.mIsDisabled)
293 {
294 destroyGLTexture();
295 }
296 mSaveData = NULL; // deletes data
297}
298
299//----------------------------------------------------------------------------
300
301static bool check_power_of_two(S32 dim)
302{
303 while(dim > 1)
304 {
305 if (dim & 1)
306 {
307 return false;
308 }
309 dim >>= 1;
310 }
311 return true;
312}
313
314//static
315bool LLImageGL::checkSize(S32 width, S32 height)
316{
317 return check_power_of_two(width) && check_power_of_two(height);
318}
319
320void LLImageGL::setSize(S32 width, S32 height, S32 ncomponents)
321{
322 if (width != mWidth || height != mHeight || ncomponents != mComponents)
323 {
324 // Check if dimensions are a power of two!
325 if (!checkSize(width,height))
326 {
327 llerrs << llformat("Texture has non power of two dimention: %dx%d",width,height) << llendl;
328 }
329
330 if (mTexName)
331 {
332// llwarns << "Setting Size of LLImageGL with existing mTexName = " << mTexName << llendl;
333 destroyGLTexture();
334 }
335
336 mWidth = width;
337 mHeight = height;
338 mComponents = ncomponents;
339 if (ncomponents > 0)
340 {
341 mMaxDiscardLevel = 0;
342 while (width > 1 && height > 1 && mMaxDiscardLevel < MAX_DISCARD_LEVEL)
343 {
344 mMaxDiscardLevel++;
345 width >>= 1;
346 height >>= 1;
347 }
348 }
349 else
350 {
351 mMaxDiscardLevel = MAX_DISCARD_LEVEL;
352 }
353 }
354}
355
356//----------------------------------------------------------------------------
357
358// virtual
359void LLImageGL::dump()
360{
361 llinfos << "mMaxDiscardLevel " << S32(mMaxDiscardLevel)
362 << " mLastBindTime " << mLastBindTime
363 << " mTarget " << S32(mTarget)
364 << " mBindTarget " << S32(mBindTarget)
365 << " mUseMipMaps " << S32(mUseMipMaps)
366 << " mHasMipMaps " << S32(mHasMipMaps)
367 << " mCurrentDiscardLevel " << S32(mCurrentDiscardLevel)
368 << " mFormatInternal " << S32(mFormatInternal)
369 << " mFormatPrimary " << S32(mFormatPrimary)
370 << " mFormatType " << S32(mFormatType)
371 << " mFormatSwapBytes " << S32(mFormatSwapBytes)
372 << " mHasExplicitFormat " << S32(mHasExplicitFormat)
373#if DEBUG_MISS
374 << " mMissed " << mMissed
375#endif
376 << llendl;
377
378 llinfos << " mTextureMemory " << mTextureMemory
379 << " mTexNames " << mTexName
380 << " mIsResident " << S32(mIsResident)
381 << llendl;
382}
383
384//----------------------------------------------------------------------------
385
386BOOL LLImageGL::bindTextureInternal(const S32 stage) const
387{
388 if (gGLManager.mIsDisabled)
389 {
390 llwarns << "Trying to bind a texture while GL is disabled!" << llendl;
391 }
392
393 stop_glerror();
394
395 glActiveTextureARB(GL_TEXTURE0_ARB + stage);
396 //glClientActiveTextureARB(GL_TEXTURE0_ARB + stage);
397
398 stop_glerror();
399
400 if (sCurrentBoundTextures[stage] && sCurrentBoundTextures[stage] == mTexName)
401 {
402 // already set!
403 return TRUE;
404 }
405
406 if (mTexName != 0)
407 {
408#ifdef DEBUG_MISS
409 mMissed = ! getIsResident(TRUE);
410#endif
411
412 glBindTexture(mBindTarget, mTexName);
413 sCurrentBoundTextures[stage] = mTexName;
414 stop_glerror();
415
416 if (mLastBindTime != sLastFrameTime)
417 {
418 // we haven't accounted for this texture yet this frame
419 updateBoundTexMem(mTextureMemory);
420 mLastBindTime = sLastFrameTime;
421 }
422
423 return TRUE;
424 }
425 else
426 {
427 glBindTexture(mBindTarget, 0);
428 sCurrentBoundTextures[stage] = 0;
429 return FALSE;
430 }
431}
432
433//virtual
434BOOL LLImageGL::bind(const S32 stage) const
435{
436 if (stage == -1)
437 {
438 return FALSE;
439 }
440 BOOL res = bindTextureInternal(stage);
441 //llassert(res);
442 return res;
443}
444
445void LLImageGL::setExplicitFormat( LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format, BOOL swap_bytes )
446{
447 // Note: must be called before createTexture()
448 // Note: it's up to the caller to ensure that the format matches the number of components.
449 mHasExplicitFormat = TRUE;
450 mFormatInternal = internal_format;
451 mFormatPrimary = primary_format;
452 if(type_format == 0)
453 mFormatType = GL_UNSIGNED_BYTE;
454 else
455 mFormatType = type_format;
456 mFormatSwapBytes = swap_bytes;
457}
458
459//----------------------------------------------------------------------------
460
461void LLImageGL::setImage(const LLImageRaw* imageraw)
462{
463 llassert((imageraw->getWidth() == getWidth(mCurrentDiscardLevel)) &&
464 (imageraw->getHeight() == getHeight(mCurrentDiscardLevel)) &&
465 (imageraw->getComponents() == getComponents()));
466 const U8* rawdata = imageraw->getData();
467 setImage(rawdata, FALSE);
468}
469
470void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
471{
472// LLFastTimer t1(LLFastTimer::FTM_TEMP1);
473
474 bool is_compressed = false;
475 if (mFormatPrimary >= GL_COMPRESSED_RGBA_S3TC_DXT1_EXT && mFormatPrimary <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
476 {
477 is_compressed = true;
478 }
479
480 {
481// LLFastTimer t2(LLFastTimer::FTM_TEMP2);
482 llverify(bindTextureInternal(0));
483 }
484
485 if (mUseMipMaps)
486 {
487// LLFastTimer t2(LLFastTimer::FTM_TEMP3);
488 if (data_hasmips)
489 {
490 // NOTE: data_in points to largest image; smaller images
491 // are stored BEFORE the largest image
492 for (S32 d=mCurrentDiscardLevel; d<=mMaxDiscardLevel; d++)
493 {
494 S32 w = getWidth(d);
495 S32 h = getHeight(d);
496 S32 gl_level = d-mCurrentDiscardLevel;
497 if (d > mCurrentDiscardLevel)
498 {
499 data_in -= dataFormatBytes(mFormatPrimary, w, h); // see above comment
500 }
501 if (is_compressed)
502 {
503// LLFastTimer t2(LLFastTimer::FTM_TEMP4);
504 S32 tex_size = dataFormatBytes(mFormatPrimary, w, h);
505 glCompressedTexImage2DARB(mTarget, gl_level, mFormatPrimary, w, h, 0, tex_size, (GLvoid *)data_in);
506 stop_glerror();
507 }
508 else
509 {
510// LLFastTimer t2(LLFastTimer::FTM_TEMP4);
511
512 if(mFormatSwapBytes)
513 {
514 glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
515 stop_glerror();
516 }
517
518 glTexImage2D(mTarget, gl_level, mFormatInternal, w, h, 0, mFormatPrimary, GL_UNSIGNED_BYTE, (GLvoid*)data_in);
519
520 if(mFormatSwapBytes)
521 {
522 glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
523 stop_glerror();
524 }
525
526 stop_glerror();
527 }
528 stop_glerror();
529 }
530 }
531 else if (!is_compressed)
532 {
533 if (mAutoGenMips)
534 {
535 glTexParameteri(mBindTarget, GL_GENERATE_MIPMAP_SGIS, TRUE);
536 stop_glerror();
537 {
538// LLFastTimer t2(LLFastTimer::FTM_TEMP4);
539
540 if(mFormatSwapBytes)
541 {
542 glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
543 stop_glerror();
544 }
545
546 glTexImage2D(mTarget, 0, mFormatInternal,
547 getWidth(mCurrentDiscardLevel), getHeight(mCurrentDiscardLevel), 0,
548 mFormatPrimary, mFormatType,
549 data_in);
550 stop_glerror();
551
552 if(mFormatSwapBytes)
553 {
554 glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
555 stop_glerror();
556 }
557 }
558 }
559 else
560 {
561 // Create mips by hand
562 // about 30% faster than autogen on ATI 9800, 50% slower on nVidia 4800
563 // ~4x faster than gluBuild2DMipmaps
564 S32 width = getWidth(mCurrentDiscardLevel);
565 S32 height = getHeight(mCurrentDiscardLevel);
566 S32 nummips = mMaxDiscardLevel - mCurrentDiscardLevel + 1;
567 S32 w = width, h = height;
568 const U8* prev_mip_data = 0;
569 const U8* cur_mip_data = 0;
570 for (int m=0; m<nummips; m++)
571 {
572 if (m==0)
573 {
574 cur_mip_data = data_in;
575 }
576 else
577 {
578 S32 bytes = w * h * mComponents;
579 U8* new_data = new U8[bytes];
580 LLImageBase::generateMip(prev_mip_data, new_data, w, h, mComponents);
581 cur_mip_data = new_data;
582 }
583 llassert(w > 0 && h > 0 && cur_mip_data);
584 {
585// LLFastTimer t1(LLFastTimer::FTM_TEMP4);
586 if(mFormatSwapBytes)
587 {
588 glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
589 stop_glerror();
590 }
591
592 glTexImage2D(mTarget, m, mFormatInternal, w, h, 0, mFormatPrimary, mFormatType, cur_mip_data);
593 stop_glerror();
594
595 if(mFormatSwapBytes)
596 {
597 glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
598 stop_glerror();
599 }
600 }
601 if (prev_mip_data && prev_mip_data != data_in)
602 {
603 delete[] prev_mip_data;
604 }
605 prev_mip_data = cur_mip_data;
606 w >>= 1;
607 h >>= 1;
608 }
609 if (prev_mip_data && prev_mip_data != data_in)
610 {
611 delete[] prev_mip_data;
612 }
613 }
614 }
615 else
616 {
617 llerrs << "Compressed Image has mipmaps but data does not (can not auto generate compressed mips)" << llendl;
618 }
619 mHasMipMaps = TRUE;
620 }
621 else
622 {
623// LLFastTimer t2(LLFastTimer::FTM_TEMP5);
624 S32 w = getWidth();
625 S32 h = getHeight();
626 if (is_compressed)
627 {
628 S32 tex_size = dataFormatBytes(mFormatPrimary, w, h);
629 glCompressedTexImage2DARB(mTarget, 0, mFormatPrimary, w, h, 0, tex_size, (GLvoid *)data_in);
630 stop_glerror();
631 }
632 else
633 {
634 if(mFormatSwapBytes)
635 {
636 glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
637 stop_glerror();
638 }
639
640 glTexImage2D(mTarget, 0, mFormatInternal, w, h, 0,
641 mFormatPrimary, mFormatType, (GLvoid *)data_in);
642 stop_glerror();
643
644 if(mFormatSwapBytes)
645 {
646 glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
647 stop_glerror();
648 }
649
650 }
651 mHasMipMaps = FALSE;
652 }
653 stop_glerror();
654}
655
656BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height)
657{
658 if (!width || !height)
659 {
660 return TRUE;
661 }
662 if (mTexName == 0)
663 {
664 llwarns << "Setting subimage on image without GL texture" << llendl;
665 return FALSE;
666 }
667
668 if (x_pos == 0 && y_pos == 0 && width == getWidth() && height == getHeight())
669 {
670 setImage(datap, FALSE);
671 }
672 else
673 {
674 if (mUseMipMaps)
675 {
676 dump();
677 llerrs << "setSubImage called with mipmapped image (not supported)" << llendl;
678 }
679 llassert(mCurrentDiscardLevel == 0);
680 if (((x_pos + width) > getWidth()) ||
681 (y_pos + height) > getHeight())
682 {
683 dump();
684 llerrs << "Subimage not wholly in target image!"
685 << " x_pos " << x_pos
686 << " y_pos " << y_pos
687 << " width " << width
688 << " height " << height
689 << " getWidth() " << getWidth()
690 << " getHeight() " << getHeight()
691 << llendl;
692 }
693
694 if ((x_pos + width) > data_width ||
695 (y_pos + height) > data_height)
696 {
697 dump();
698 llerrs << "Subimage not wholly in source image!"
699 << " x_pos " << x_pos
700 << " y_pos " << y_pos
701 << " width " << width
702 << " height " << height
703 << " source_width " << data_width
704 << " source_height " << data_height
705 << llendl;
706 }
707
708
709 glPixelStorei(GL_UNPACK_ROW_LENGTH, data_width);
710 stop_glerror();
711
712 if(mFormatSwapBytes)
713 {
714 glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
715 stop_glerror();
716 }
717
718 datap += (y_pos * data_width + x_pos) * getComponents();
719 // Update the GL texture
720 llverify(bindTextureInternal(0));
721 stop_glerror();
722
723 glTexSubImage2D(mTarget, 0, x_pos, y_pos,
724 width, height, mFormatPrimary, mFormatType, datap);
725 stop_glerror();
726
727 if(mFormatSwapBytes)
728 {
729 glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
730 stop_glerror();
731 }
732
733 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
734 stop_glerror();
735 }
736
737 return TRUE;
738}
739
740BOOL LLImageGL::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height)
741{
742 return setSubImage(imageraw->getData(), imageraw->getWidth(), imageraw->getHeight(), x_pos, y_pos, width, height);
743}
744
745// Copy sub image from frame buffer
746BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height)
747{
748 if (bindTextureInternal(0))
749 {
750 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, fb_x, fb_y, x_pos, y_pos, width, height);
751 stop_glerror();
752 return TRUE;
753 }
754 else
755 {
756 return FALSE;
757 }
758}
759
760BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/)
761{
762 if (gGLManager.mIsDisabled)
763 {
764 llwarns << "Trying to create a texture while GL is disabled!" << llendl;
765 return FALSE;
766 }
767 llassert(gGLManager.mInited || gNoRender);
768 stop_glerror();
769
770 if (discard_level < 0)
771 {
772 llassert(mCurrentDiscardLevel >= 0);
773 discard_level = mCurrentDiscardLevel;
774 }
775 discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel);
776
777 // Actual image width/height = raw image width/height * 2^discard_level
778 S32 w = imageraw->getWidth() << discard_level;
779 S32 h = imageraw->getHeight() << discard_level;
780
781 // setSize may call destroyGLTexture if the size does not match
782 setSize(w, h, imageraw->getComponents());
783
784 if( !mHasExplicitFormat )
785 {
786 switch (mComponents)
787 {
788 case 1:
789 // Use luminance alpha (for fonts)
790 mFormatInternal = GL_LUMINANCE8;
791 mFormatPrimary = GL_LUMINANCE;
792 mFormatType = GL_UNSIGNED_BYTE;
793 break;
794 case 2:
795 // Use luminance alpha (for fonts)
796 mFormatInternal = GL_LUMINANCE8_ALPHA8;
797 mFormatPrimary = GL_LUMINANCE_ALPHA;
798 mFormatType = GL_UNSIGNED_BYTE;
799 break;
800 case 3:
801 mFormatInternal = GL_RGB8;
802 mFormatPrimary = GL_RGB;
803 mFormatType = GL_UNSIGNED_BYTE;
804 break;
805 case 4:
806 mFormatInternal = GL_RGBA8;
807 mFormatPrimary = GL_RGBA;
808 mFormatType = GL_UNSIGNED_BYTE;
809 break;
810 default:
811 llerrs << "Bad number of components for texture: " << (U32)getComponents() << llendl;
812 }
813 }
814
815 const U8* rawdata = imageraw->getData();
816 return createGLTexture(discard_level, rawdata, FALSE, usename);
817}
818
819BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename)
820{
821 llassert(data_in);
822
823 if (discard_level < 0)
824 {
825 llassert(mCurrentDiscardLevel >= 0);
826 discard_level = mCurrentDiscardLevel;
827 }
828 discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel);
829
830 if (mTexName != 0 && discard_level == mCurrentDiscardLevel)
831 {
832 // This will only be true if the size has not changed
833 setImage(data_in, data_hasmips);
834 return TRUE;
835 }
836
837 GLuint old_name = mTexName;
838// S32 old_discard = mCurrentDiscardLevel;
839
840 if (usename != 0)
841 {
842 mTexName = usename;
843 }
844 else
845 {
846 glGenTextures(1, (GLuint*)&mTexName);
847 stop_glerror();
848 {
849// LLFastTimer t1(LLFastTimer::FTM_TEMP6);
850 llverify(bindTextureInternal(0));
851 glTexParameteri(mBindTarget, GL_TEXTURE_BASE_LEVEL, 0);
852 glTexParameteri(mBindTarget, GL_TEXTURE_MAX_LEVEL, mMaxDiscardLevel-discard_level);
853 }
854 }
855 if (!mTexName)
856 {
857 llerrs << "LLImageGL::createGLTexture failed to make texture" << llendl;
858 }
859
860 if (mUseMipMaps)
861 {
862 mAutoGenMips = gGLManager.mHasMipMapGeneration;
863#if LL_DARWIN
864 // On the Mac GF2 and GF4MX drivers, auto mipmap generation doesn't work right with alpha-only textures.
865 if(gGLManager.mIsGF2or4MX && (mFormatInternal == GL_ALPHA8) && (mFormatPrimary == GL_ALPHA))
866 {
867 mAutoGenMips = FALSE;
868 }
869#endif
870 }
871
872 mCurrentDiscardLevel = discard_level;
873
874 setImage(data_in, data_hasmips);
875
876 setClamp(mClampS, mClampT);
877 setMipFilterNearest(mMipFilterNearest);
878
879 // things will break if we don't unbind after creation
880 unbindTexture(0, mBindTarget);
881 stop_glerror();
882
883 if (old_name != 0)
884 {
885 sGlobalTextureMemory -= mTextureMemory;
886 glDeleteTextures(1, &old_name);
887 stop_glerror();
888 }
889
890 mTextureMemory = getMipBytes(discard_level);
891 sGlobalTextureMemory += mTextureMemory;
892
893 // mark this as bound at this point, so we don't throw it out immediately
894 mLastBindTime = sLastFrameTime;
895
896 return TRUE;
897}
898
899BOOL LLImageGL::setDiscardLevel(S32 discard_level)
900{
901 llassert(discard_level >= 0);
902 llassert(mCurrentDiscardLevel >= 0);
903
904 discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel);
905
906 if (mDontDiscard)
907 {
908 // don't discard!
909 return FALSE;
910 }
911 else if (discard_level == mCurrentDiscardLevel)
912 {
913 // nothing to do
914 return FALSE;
915 }
916 else if (discard_level < mCurrentDiscardLevel)
917 {
918 // larger image
919 dump();
920 llerrs << "LLImageGL::setDiscardLevel() called with larger discard level; use createGLTexture()" << llendl;
921 return FALSE;
922 }
923 else if (mUseMipMaps)
924 {
925 LLPointer<LLImageRaw> imageraw = new LLImageRaw;
926 while(discard_level > mCurrentDiscardLevel)
927 {
928 if (readBackRaw(discard_level, imageraw))
929 {
930 break;
931 }
932 discard_level--;
933 }
934 if (discard_level == mCurrentDiscardLevel)
935 {
936 // unable to increase the discard level
937 return FALSE;
938 }
939 return createGLTexture(discard_level, imageraw);
940 }
941 else
942 {
943#ifndef LL_LINUX // *FIX: This should not be skipped for the linux client.
944 llerrs << "LLImageGL::setDiscardLevel() called on image without mipmaps" << llendl;
945#endif
946 return FALSE;
947 }
948}
949
950BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw)
951{
952 if (discard_level < 0)
953 {
954 discard_level = mCurrentDiscardLevel;
955 }
956
957 if (mTexName == 0 || discard_level < mCurrentDiscardLevel)
958 {
959 return FALSE;
960 }
961
962 S32 gl_discard = discard_level - mCurrentDiscardLevel;
963
964 llverify(bindTextureInternal(0));
965
966 LLGLint glwidth = 0;
967 glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_WIDTH, (GLint*)&glwidth);
968 if (glwidth == 0)
969 {
970 // No mip data smaller than current discard level
971 return FALSE;
972 }
973
974 S32 width = getWidth(discard_level);
975 S32 height = getHeight(discard_level);
976 S32 ncomponents = getComponents();
977 if (ncomponents == 0)
978 {
979 return FALSE;
980 }
981
982 if (width <= 0 || width > 2048 || height <= 0 || height > 2048 || ncomponents < 1 || ncomponents > 4)
983 {
984 llerrs << llformat("LLImageGL::readBackRaw: bogus params: %d x %d x %d",width,height,ncomponents) << llendl;
985 }
986
987 LLGLint is_compressed = 0;
988 glGetTexLevelParameteriv(mTarget, is_compressed, GL_TEXTURE_COMPRESSED, (GLint*)&is_compressed);
989 if (is_compressed)
990 {
991 LLGLint glbytes;
992 glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, (GLint*)&glbytes);
993 imageraw->allocateDataSize(width, height, ncomponents, glbytes);
994 glGetCompressedTexImageARB(mTarget, gl_discard, (GLvoid*)(imageraw->getData()));
995 stop_glerror();
996 }
997 else
998 {
999 imageraw->allocateDataSize(width, height, ncomponents);
1000 glGetTexImage(GL_TEXTURE_2D, gl_discard, mFormatPrimary, mFormatType, (GLvoid*)(imageraw->getData()));
1001 stop_glerror();
1002 }
1003
1004 return TRUE;
1005}
1006
1007void LLImageGL::destroyGLTexture()
1008{
1009 stop_glerror();
1010
1011 if (mTexName != 0)
1012 {
1013 for (int i = 0; i < gGLManager.mNumTextureUnits; i++)
1014 {
1015 if (sCurrentBoundTextures[i] == mTexName)
1016 {
1017 unbindTexture(i, GL_TEXTURE_2D);
1018 stop_glerror();
1019 }
1020 }
1021
1022 sGlobalTextureMemory -= mTextureMemory;
1023 mTextureMemory = 0;
1024
1025 glDeleteTextures(1, (GLuint*)&mTexName);
1026 mTexName = 0;
1027
1028 stop_glerror();
1029 }
1030}
1031
1032//----------------------------------------------------------------------------
1033
1034void LLImageGL::setClamp(BOOL clamps, BOOL clampt)
1035{
1036 mClampS = clamps;
1037 mClampT = clampt;
1038 if (mTexName != 0)
1039 {
1040 glTexParameteri(mBindTarget, GL_TEXTURE_WRAP_S, clamps ? GL_CLAMP_TO_EDGE : GL_REPEAT);
1041 glTexParameteri(mBindTarget, GL_TEXTURE_WRAP_T, clampt ? GL_CLAMP_TO_EDGE : GL_REPEAT);
1042 }
1043 stop_glerror();
1044}
1045
1046void LLImageGL::setMipFilterNearest(BOOL nearest, BOOL min_nearest)
1047{
1048 mMipFilterNearest = nearest;
1049
1050 if (mTexName != 0)
1051 {
1052 if (min_nearest)
1053 {
1054 glTexParameteri(mBindTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1055 }
1056 else if (mHasMipMaps)
1057 {
1058 glTexParameteri(mBindTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
1059 }
1060 else
1061 {
1062 glTexParameteri(mBindTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1063 }
1064 if (mMipFilterNearest)
1065 {
1066 glTexParameteri(mBindTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1067 }
1068 else
1069 {
1070 glTexParameteri(mBindTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1071 }
1072 if (gGLManager.mHasAnisotropic)
1073 {
1074 if (sGlobalUseAnisotropic && !mMipFilterNearest)
1075 {
1076 F32 largest_anisotropy;
1077 glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &largest_anisotropy);
1078 glTexParameterf(mBindTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, largest_anisotropy);
1079 }
1080 else
1081 {
1082 glTexParameterf(mBindTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.f);
1083 }
1084 }
1085 }
1086
1087 stop_glerror();
1088}
1089
1090BOOL LLImageGL::getIsResident(BOOL test_now)
1091{
1092 if (test_now)
1093 {
1094 if (mTexName != 0)
1095 {
1096 glAreTexturesResident(1, (GLuint*)&mTexName, &mIsResident);
1097 }
1098 else
1099 {
1100 mIsResident = FALSE;
1101 }
1102 }
1103
1104 return mIsResident;
1105}
1106
1107S32 LLImageGL::getHeight(S32 discard_level) const
1108{
1109 if (discard_level < 0)
1110 {
1111 discard_level = mCurrentDiscardLevel;
1112 }
1113 S32 height = mHeight >> discard_level;
1114 if (height < 1) height = 1;
1115 return height;
1116}
1117
1118S32 LLImageGL::getWidth(S32 discard_level) const
1119{
1120 if (discard_level < 0)
1121 {
1122 discard_level = mCurrentDiscardLevel;
1123 }
1124 S32 width = mWidth >> discard_level;
1125 if (width < 1) width = 1;
1126 return width;
1127}
1128
1129S32 LLImageGL::getBytes(S32 discard_level) const
1130{
1131 if (discard_level < 0)
1132 {
1133 discard_level = mCurrentDiscardLevel;
1134 }
1135 S32 w = mWidth>>discard_level;
1136 S32 h = mHeight>>discard_level;
1137 if (w == 0) w = 1;
1138 if (h == 0) h = 1;
1139 return dataFormatBytes(mFormatPrimary, w, h);
1140}
1141
1142S32 LLImageGL::getMipBytes(S32 discard_level) const
1143{
1144 if (discard_level < 0)
1145 {
1146 discard_level = mCurrentDiscardLevel;
1147 }
1148 S32 w = mWidth>>discard_level;
1149 S32 h = mHeight>>discard_level;
1150 S32 res = dataFormatBytes(mFormatPrimary, w, h);
1151 if (mUseMipMaps)
1152 {
1153 while (w > 1 && h > 1)
1154 {
1155 w >>= 1; if (w == 0) w = 1;
1156 h >>= 1; if (h == 0) h = 1;
1157 res += dataFormatBytes(mFormatPrimary, w, h);
1158 }
1159 }
1160 return res;
1161}
1162
1163BOOL LLImageGL::getBoundRecently() const
1164{
1165 return (BOOL)(sLastFrameTime - mLastBindTime < MIN_TEXTURE_LIFETIME);
1166}
1167
1168void LLImageGL::setTarget(const LLGLenum target, const LLGLenum bind_target)
1169{
1170 mTarget = target;
1171 mBindTarget = bind_target;
1172}
1173
1174//----------------------------------------------------------------------------
1175
1176// Manual Mip Generation
1177/*
1178 S32 width = getWidth(discard_level);
1179 S32 height = getHeight(discard_level);
1180 S32 w = width, h = height;
1181 S32 nummips = 1;
1182 while (w > 4 && h > 4)
1183 {
1184 w >>= 1; h >>= 1;
1185 nummips++;
1186 }
1187 stop_glerror();
1188 w = width, h = height;
1189 const U8* prev_mip_data = 0;
1190 const U8* cur_mip_data = 0;
1191 for (int m=0; m<nummips; m++)
1192 {
1193 if (m==0)
1194 {
1195 cur_mip_data = rawdata;
1196 }
1197 else
1198 {
1199 S32 bytes = w * h * mComponents;
1200 U8* new_data = new U8[bytes];
1201 LLImageBase::generateMip(prev_mip_data, new_data, w, h, mComponents);
1202 cur_mip_data = new_data;
1203 }
1204 llassert(w > 0 && h > 0 && cur_mip_data);
1205 U8 test = cur_mip_data[w*h*mComponents-1];
1206 {
1207 glTexImage2D(mTarget, m, mFormatInternal, w, h, 0, mFormatPrimary, mFormatType, cur_mip_data);
1208 stop_glerror();
1209 }
1210 if (prev_mip_data && prev_mip_data != rawdata)
1211 {
1212 delete prev_mip_data;
1213 }
1214 prev_mip_data = cur_mip_data;
1215 w >>= 1;
1216 h >>= 1;
1217 }
1218 if (prev_mip_data && prev_mip_data != rawdata)
1219 {
1220 delete prev_mip_data;
1221 }
1222 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
1223 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, nummips);
1224*/
diff --git a/linden/indra/llrender/llimagegl.h b/linden/indra/llrender/llimagegl.h
new file mode 100644
index 0000000..6356703
--- /dev/null
+++ b/linden/indra/llrender/llimagegl.h
@@ -0,0 +1,204 @@
1/**
2 * @file llimagegl.h
3 * @brief Object for managing images and their textures
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28
29#ifndef LL_LLIMAGEGL_H
30#define LL_LLIMAGEGL_H
31
32#include "llimage.h"
33
34#include "llgltypes.h"
35#include "llmemory.h"
36
37//============================================================================
38
39class LLImageGL : public LLThreadSafeRefCount
40{
41public:
42 // Size calculation
43 static S32 dataFormatBits(S32 dataformat);
44 static S32 dataFormatBytes(S32 dataformat, S32 width, S32 height);
45 static S32 dataFormatComponents(S32 dataformat);
46
47 // Wrapper for glBindTexture that keeps LLImageGL in sync.
48 // Usually you want stage = 0 and bind_target = GL_TEXTURE_2D
49 static void bindExternalTexture( LLGLuint gl_name, S32 stage, LLGLenum bind_target);
50 static void unbindTexture(S32 stage, LLGLenum target);
51
52 // needs to be called every frame
53 static void updateStats(F32 current_time);
54
55 // Save off / restore GL textures
56 static void destroyGL(BOOL save_state = TRUE);
57 static void restoreGL();
58
59 // Sometimes called externally for textures not using LLImageGL (should go away...)
60 static S32 updateBoundTexMem(const S32 delta);
61
62 static bool checkSize(S32 width, S32 height);
63
64 // Not currently necessary for LLImageGL, but required in some derived classes,
65 // so include for compatability
66 static BOOL create(LLPointer<LLImageGL>& dest, BOOL usemipmaps = TRUE);
67 static BOOL create(LLPointer<LLImageGL>& dest, U32 width, U32 height, U8 components, BOOL usemipmaps = TRUE);
68 static BOOL create(LLPointer<LLImageGL>& dest, const LLImageRaw* imageraw, BOOL usemipmaps = TRUE);
69
70public:
71 LLImageGL(BOOL usemipmaps = TRUE);
72 LLImageGL(U32 width, U32 height, U8 components, BOOL usemipmaps = TRUE);
73 LLImageGL(const LLImageRaw* imageraw, BOOL usemipmaps = TRUE);
74
75protected:
76 virtual ~LLImageGL();
77 BOOL bindTextureInternal(const S32 stage = 0) const;
78
79public:
80 virtual void dump(); // debugging info to llinfos
81 virtual BOOL bind(const S32 stage = 0) const;
82
83 void setSize(S32 width, S32 height, S32 ncomponents);
84
85 BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0);
86 BOOL createGLTexture(S32 discard_level, const U8* data, BOOL data_hasmips = FALSE, S32 usename = 0);
87 void setImage(const LLImageRaw* imageraw);
88 void setImage(const U8* data_in, BOOL data_hasmips = FALSE);
89 BOOL setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height);
90 BOOL setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height);
91 BOOL setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height);
92 BOOL setDiscardLevel(S32 discard_level);
93 BOOL readBackRaw(S32 discard_level, LLImageRaw* imageraw); // Read back a raw image for this discard level, if it exists
94 void destroyGLTexture();
95
96 void setClamp(BOOL clamps, BOOL clampt);
97 void setMipFilterNearest(BOOL nearest, BOOL min_nearest = FALSE);
98 void setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format = 0, BOOL swap_bytes = FALSE);
99 void dontDiscard() { mDontDiscard = 1; }
100
101 S32 getDiscardLevel() const { return mCurrentDiscardLevel; }
102 S32 getMaxDiscardLevel() const { return mMaxDiscardLevel; }
103
104 S32 getWidth(S32 discard_level = -1) const;
105 S32 getHeight(S32 discard_level = -1) const;
106 U8 getComponents() const { return mComponents; }
107 S32 getBytes(S32 discard_level = -1) const;
108 S32 getMipBytes(S32 discard_level = -1) const;
109 BOOL getBoundRecently() const;
110 LLGLenum getPrimaryFormat() const { return mFormatPrimary; }
111
112 BOOL getClampS() const { return mClampS; }
113 BOOL getClampT() const { return mClampT; }
114 BOOL getMipFilterNearest() const { return mMipFilterNearest; }
115
116 BOOL getHasGLTexture() const { return mTexName != 0; }
117 LLGLuint getTexName() const { return mTexName; }
118
119 BOOL getIsResident(BOOL test_now = FALSE); // not const
120
121 void setTarget(const LLGLenum target, const LLGLenum bind_target);
122
123 BOOL getUseMipMaps() const { return mUseMipMaps; }
124 void setUseMipMaps(BOOL usemips) { mUseMipMaps = usemips; }
125 BOOL getUseDiscard() const { return mUseMipMaps && !mDontDiscard; }
126 BOOL getDontDiscard() const { return mDontDiscard; }
127
128protected:
129 void init(BOOL usemipmaps);
130 virtual void cleanup(); // Clean up the LLImageGL so it can be reinitialized. Be careful when using this in derived class destructors
131
132public:
133 // Various GL/Rendering options
134 S32 mTextureMemory;
135 mutable F32 mLastBindTime; // last time this was bound, by discard level
136 mutable F32 mLastBindAttempt; // last time bindTexture was called on this texture
137
138private:
139 LLPointer<LLImageRaw> mSaveData; // used for destroyGL/restoreGL
140 S8 mUseMipMaps;
141 S8 mHasMipMaps;
142 S8 mHasExplicitFormat; // If false (default), GL format is f(mComponents)
143 S8 mAutoGenMips;
144
145protected:
146 LLGLenum mTarget; // Normally GL_TEXTURE2D, sometimes something else (ex. cube maps)
147 LLGLenum mBindTarget; // NOrmally GL_TEXTURE2D, sometimes something else (ex. cube maps)
148
149 LLGLuint mTexName;
150
151 LLGLboolean mIsResident;
152
153 U16 mWidth;
154 U16 mHeight;
155
156 S8 mComponents;
157 S8 mMaxDiscardLevel;
158 S8 mCurrentDiscardLevel;
159 S8 mDontDiscard; // Keep full res version of this image (for UI, etc)
160
161 S8 mClampS; // Need to save clamp state
162 S8 mClampT;
163 S8 mMipFilterNearest; // if TRUE, set magfilter to GL_NEAREST
164
165 LLGLint mFormatInternal; // = GL internalformat
166 LLGLenum mFormatPrimary; // = GL format (pixel data format)
167 LLGLenum mFormatType;
168 BOOL mFormatSwapBytes;// if true, use glPixelStorei(GL_UNPACK_SWAP_BYTES, 1)
169
170 // STATICS
171public:
172 static std::set<LLImageGL*> sImageList;
173 static S32 sCount;
174
175 static F32 sLastFrameTime;
176
177 static LLGLuint sCurrentBoundTextures[MAX_GL_TEXTURE_UNITS]; // Currently bound texture ID
178
179 // Global memory statistics
180 static S32 sGlobalTextureMemory; // Tracks main memory texmem
181 static S32 sBoundTextureMemory; // Tracks bound texmem for last completed frame
182 static S32 sCurBoundTextureMemory; // Tracks bound texmem for current frame
183
184 static BOOL sGlobalUseAnisotropic;
185
186#if DEBUG_MISS
187 BOOL mMissed; // Missed on last bind?
188 BOOL getMissed() const { return mMissed; };
189#else
190 BOOL getMissed() const { return FALSE; };
191#endif
192};
193
194//RN: maybe this needs to moved elsewhere?
195class LLImageProviderInterface
196{
197public:
198 LLImageProviderInterface() {};
199 virtual ~LLImageProviderInterface() {};
200
201 virtual LLImageGL* getUIImageByID(const LLUUID& id, BOOL clamped = TRUE) = 0;
202};
203
204#endif // LL_LLIMAGEGL_H
diff --git a/linden/indra/llrender/llrender.vcproj b/linden/indra/llrender/llrender.vcproj
new file mode 100644
index 0000000..9ca9b03
--- /dev/null
+++ b/linden/indra/llrender/llrender.vcproj
@@ -0,0 +1,230 @@
1<?xml version="1.0" encoding="Windows-1252"?>
2<VisualStudioProject
3 ProjectType="Visual C++"
4 Version="7.10"
5 Name="llrender"
6 ProjectGUID="{2ADE3C14-94C4-40BF-B033-70F3C954EE90}"
7 Keyword="Win32Proj">
8 <Platforms>
9 <Platform
10 Name="Win32"/>
11 </Platforms>
12 <Configurations>
13 <Configuration
14 Name="Debug|Win32"
15 OutputDirectory="../lib_$(ConfigurationName)/i686-win32"
16 IntermediateDirectory="Debug"
17 ConfigurationType="4"
18 CharacterSet="1">
19 <Tool
20 Name="VCCLCompilerTool"
21 Optimization="0"
22 AdditionalIncludeDirectories="..\llcommon;..\llmath;..\llvfs;..\llmessage;..\llimage;..\llwindow;..\..\libraries\i686-win32\include;..\..\libraries\include\"
23 PreprocessorDefinitions="WIN32;_DEBUG;_LIB;LL_WINDOWS;LL_DEBUG"
24 MinimalRebuild="TRUE"
25 BasicRuntimeChecks="3"
26 RuntimeLibrary="1"
27 StructMemberAlignment="4"
28 ForceConformanceInForLoopScope="TRUE"
29 UsePrecompiledHeader="0"
30 WarningLevel="3"
31 WarnAsError="TRUE"
32 Detect64BitPortabilityProblems="FALSE"
33 DebugInformationFormat="4"/>
34 <Tool
35 Name="VCCustomBuildTool"/>
36 <Tool
37 Name="VCLibrarianTool"
38 OutputFile="$(OutDir)/llrender.lib"/>
39 <Tool
40 Name="VCMIDLTool"/>
41 <Tool
42 Name="VCPostBuildEventTool"/>
43 <Tool
44 Name="VCPreBuildEventTool"/>
45 <Tool
46 Name="VCPreLinkEventTool"/>
47 <Tool
48 Name="VCResourceCompilerTool"/>
49 <Tool
50 Name="VCWebServiceProxyGeneratorTool"/>
51 <Tool
52 Name="VCXMLDataGeneratorTool"/>
53 <Tool
54 Name="VCManagedWrapperGeneratorTool"/>
55 <Tool
56 Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
57 </Configuration>
58 <Configuration
59 Name="Release|Win32"
60 OutputDirectory="../lib_$(ConfigurationName)/i686-win32"
61 IntermediateDirectory="Release"
62 ConfigurationType="4"
63 CharacterSet="1">
64 <Tool
65 Name="VCCLCompilerTool"
66 GlobalOptimizations="TRUE"
67 InlineFunctionExpansion="2"
68 EnableIntrinsicFunctions="TRUE"
69 OptimizeForProcessor="3"
70 OptimizeForWindowsApplication="TRUE"
71 AdditionalIncludeDirectories="..\llcommon;..\llmath;..\llvfs;..\llmessage;..\llimage;..\llwindow;..\..\libraries\i686-win32\include;..\..\libraries\include\"
72 PreprocessorDefinitions="WIN32;NDEBUG;_LIB;LL_WINDOWS;LL_RELEASE"
73 RuntimeLibrary="0"
74 StructMemberAlignment="0"
75 ForceConformanceInForLoopScope="TRUE"
76 UsePrecompiledHeader="0"
77 WarningLevel="3"
78 WarnAsError="TRUE"
79 Detect64BitPortabilityProblems="FALSE"
80 DebugInformationFormat="3"/>
81 <Tool
82 Name="VCCustomBuildTool"/>
83 <Tool
84 Name="VCLibrarianTool"
85 OutputFile="$(OutDir)/llrender.lib"/>
86 <Tool
87 Name="VCMIDLTool"/>
88 <Tool
89 Name="VCPostBuildEventTool"/>
90 <Tool
91 Name="VCPreBuildEventTool"/>
92 <Tool
93 Name="VCPreLinkEventTool"/>
94 <Tool
95 Name="VCResourceCompilerTool"/>
96 <Tool
97 Name="VCWebServiceProxyGeneratorTool"/>
98 <Tool
99 Name="VCXMLDataGeneratorTool"/>
100 <Tool
101 Name="VCManagedWrapperGeneratorTool"/>
102 <Tool
103 Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
104 </Configuration>
105 <Configuration
106 Name="ReleaseNoOpt|Win32"
107 OutputDirectory="../lib_$(ConfigurationName)/i686-win32"
108 IntermediateDirectory="$(ConfigurationName)"
109 ConfigurationType="4"
110 CharacterSet="1">
111 <Tool
112 Name="VCCLCompilerTool"
113 Optimization="0"
114 AdditionalIncludeDirectories="..\llcommon;..\llmath;..\llvfs;..\llmessage;..\llimage;..\llwindow;..\..\libraries\i686-win32\include;..\..\libraries\include\"
115 PreprocessorDefinitions="WIN32;NDEBUG;_LIB;LL_WINDOWS;LL_RELEASE"
116 RuntimeLibrary="0"
117 StructMemberAlignment="0"
118 ForceConformanceInForLoopScope="TRUE"
119 UsePrecompiledHeader="0"
120 WarningLevel="3"
121 WarnAsError="TRUE"
122 Detect64BitPortabilityProblems="FALSE"
123 DebugInformationFormat="3"/>
124 <Tool
125 Name="VCCustomBuildTool"/>
126 <Tool
127 Name="VCLibrarianTool"
128 OutputFile="$(OutDir)/llrender.lib"/>
129 <Tool
130 Name="VCMIDLTool"/>
131 <Tool
132 Name="VCPostBuildEventTool"/>
133 <Tool
134 Name="VCPreBuildEventTool"/>
135 <Tool
136 Name="VCPreLinkEventTool"/>
137 <Tool
138 Name="VCResourceCompilerTool"/>
139 <Tool
140 Name="VCWebServiceProxyGeneratorTool"/>
141 <Tool
142 Name="VCXMLDataGeneratorTool"/>
143 <Tool
144 Name="VCManagedWrapperGeneratorTool"/>
145 <Tool
146 Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
147 </Configuration>
148 </Configurations>
149 <References>
150 </References>
151 <Files>
152 <Filter
153 Name="Source Files"
154 Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
155 UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
156 <File
157 RelativePath=".\llagpmempool.cpp">
158 </File>
159 <File
160 RelativePath=".\llagpmempoolarb.cpp">
161 </File>
162 <File
163 RelativePath=".\llagpmempoolati.cpp">
164 </File>
165 <File
166 RelativePath=".\llagpmempoolnv.cpp">
167 </File>
168 <File
169 RelativePath=".\llfont.cpp">
170 </File>
171 <File
172 RelativePath=".\llfontgl.cpp">
173 </File>
174 <File
175 RelativePath=".\llgldbg.cpp">
176 </File>
177 <File
178 RelativePath=".\llimagegl.cpp">
179 </File>
180 <File
181 RelativePath=".\text_out.cpp">
182 </File>
183 </Filter>
184 <Filter
185 Name="Header Files"
186 Filter="h;hpp;hxx;hm;inl;inc;xsd"
187 UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
188 <File
189 RelativePath=".\glext.h">
190 </File>
191 <File
192 RelativePath=".\llagpmempool.h">
193 </File>
194 <File
195 RelativePath=".\llagpmempoolarb.h">
196 </File>
197 <File
198 RelativePath=".\llagpmempoolati.h">
199 </File>
200 <File
201 RelativePath=".\llagpmempoolnv.h">
202 </File>
203 <File
204 RelativePath=".\llfont.h">
205 </File>
206 <File
207 RelativePath=".\llfontgl.h">
208 </File>
209 <File
210 RelativePath=".\llgldbg.h">
211 </File>
212 <File
213 RelativePath=".\llimagegl.h">
214 </File>
215 <File
216 RelativePath=".\llvertexprogramgl.h">
217 </File>
218 <File
219 RelativePath=".\text_out.h">
220 </File>
221 </Filter>
222 <Filter
223 Name="Resource Files"
224 Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
225 UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
226 </Filter>
227 </Files>
228 <Globals>
229 </Globals>
230</VisualStudioProject>
diff --git a/linden/indra/llrender/llvertexprogramgl.cpp b/linden/indra/llrender/llvertexprogramgl.cpp
new file mode 100644
index 0000000..bc00a64
--- /dev/null
+++ b/linden/indra/llrender/llvertexprogramgl.cpp
@@ -0,0 +1,121 @@
1/**
2 * @file llvertexprogramgl.cpp
3 * @brief LLVertexProgramGL base class
4 *
5 * Copyright (c) 2003-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28// This file contains the definition of LLVertexProgramGL,
29// for purposes of running vertex programs on GL hardware.
30
31#include "linden_common.h"
32
33#include "llvertexprogramgl.h"
34
35#include "llglheaders.h"
36
37LLVertexProgramGL::LLVertexProgramGL()
38{
39 mVertexProgramID = 0;
40}
41
42LLVertexProgramGL::~LLVertexProgramGL()
43{
44 glDeleteProgramsARB(1, (GLuint*) &mVertexProgramID);
45}
46
47BOOL LLVertexProgramGL::load(const char * filename)
48{
49 FILE *fp = fopen(filename, "r");
50 if (!fp)
51 {
52 llwarns << "Unable to open vertex program " << filename << llendl;
53 return FALSE;
54 }
55
56 fseek(fp,0,SEEK_END);
57 S32 file_size = ftell(fp);
58 fseek(fp,0,SEEK_SET);
59
60 char *text_buffer = new char[file_size + 1];
61
62 S32 num_read = (S32)fread(text_buffer, sizeof(char), file_size, fp);
63
64 if (ferror(fp) || num_read == 0)
65 {
66 llwarns << "Unable to read vertex program " << filename << llendl;
67 fclose(fp);
68 delete[] text_buffer;
69 return FALSE;
70 }
71 text_buffer[num_read] = '\0';
72 fclose(fp);
73
74 //Send program string to OpenGL
75 glGenProgramsARB(1, (GLuint*) &mVertexProgramID);
76 glBindProgramARB(GL_VERTEX_PROGRAM_ARB, mVertexProgramID);
77 glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, num_read, text_buffer);
78
79 const GLubyte * program_error_string = glGetString(GL_PROGRAM_ERROR_STRING_ARB);
80
81 GLint error_pos;
82 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_pos);
83
84 if(error_pos!=-1)
85 {
86 glGetError();
87 S32 line_num = 1;
88 char *next_token = strchr(text_buffer, '\n');
89 while(NULL != next_token && next_token < (text_buffer + error_pos))
90 {
91 next_token++;
92 line_num++;
93 next_token = strchr(next_token, '\n');
94 }
95 char output[1024];
96 char bad_code[11];
97 strncpy(bad_code, text_buffer + error_pos, 10);
98 bad_code[10] = '\0';
99
100 sprintf(output, "%s(%d): Vertex Program Error: %s at (%s)\n", filename, line_num, program_error_string, bad_code);
101 gErrorStream << output << std::endl;
102 // clean up buffer
103 delete[] text_buffer;
104 return FALSE;
105 }
106
107 // clean up buffer
108 delete[] text_buffer;
109 return TRUE;
110}
111
112void LLVertexProgramGL::bind()
113{
114 glEnable(GL_VERTEX_PROGRAM_ARB);
115 glBindProgramARB(GL_VERTEX_PROGRAM_ARB, mVertexProgramID);
116}
117
118void LLVertexProgramGL::unbind()
119{
120 glDisable(GL_VERTEX_PROGRAM_ARB);
121}
diff --git a/linden/indra/llrender/llvertexprogramgl.h b/linden/indra/llrender/llvertexprogramgl.h
new file mode 100644
index 0000000..78cb1c9
--- /dev/null
+++ b/linden/indra/llrender/llvertexprogramgl.h
@@ -0,0 +1,51 @@
1/**
2 * @file llvertexprogramgl.h
3 * @brief LLVertexProgramGL base class
4 *
5 * Copyright (c) 2003-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LL_LLVERTEXPROGRAMGL_H
29#define LL_LLVERTEXPROGRAMGL_H
30
31// This file contains the definition of LLVertexProgramGL,
32// for purposes of running vertex programs on GL hardware.
33
34#include "llgl.h"
35
36class LLVertexProgramGL
37{
38public:
39 LLVertexProgramGL();
40 ~LLVertexProgramGL();
41
42 void bind();
43 void unbind();
44
45 BOOL load(const char * filename);
46
47private:
48 LLGLuint mVertexProgramID;
49};
50
51#endif // LL_LLVERTEXPROGRAMGL_H
diff --git a/linden/indra/llrender/text_out.cpp b/linden/indra/llrender/text_out.cpp
new file mode 100644
index 0000000..f4892b2
--- /dev/null
+++ b/linden/indra/llrender/text_out.cpp
@@ -0,0 +1,115 @@
1/**
2 * @file text_out.cpp
3 * @brief Text rendering implementation
4 *
5 * Copyright (c) 2000-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28/* DEPRECATED - Use LLFontGL for raw rendering, or make an LLTextBox to hold the text */
29
30#include "linden_common.h"
31
32#include "text_out.h"
33#include "llfontgl.h"
34//#include "vmath.h"
35#include "v4color.h"
36
37#define MAX_TEXT_LINE_LENGTH (256)
38#define MAX_TEXT_LINES (128)
39
40extern S32 gWindowWidth;
41extern S32 gWindowHeight;
42
43S32 gNumTextLines = 0;
44
45LLColor4 gCurrentColor;
46//U8 gCurrentBGColor[] = { 32, 32, 32 };
47
48//F32 gCurrentScale = 10.f;
49
50typedef struct s_text_line
51{
52// const LLFontGL *font;
53// U8 color[3];
54// U8 bg_color[3];
55 char line[MAX_TEXT_LINE_LENGTH];
56 S32 x, y;
57// ETextModifiers tm;
58// ETextColorModifiers fcm;
59// ETextColorModifiers bcm;
60} TEXT_LINE;
61
62TEXT_LINE gTextLine[MAX_TEXT_LINES];
63
64void set_text_color( const LLColor4& color )
65{
66 gCurrentColor = color;
67}
68/*
69void set_text_bg_color(S32 red, S32 green, S32 blue)
70{
71 gCurrentBGColor[0] = red;
72 gCurrentBGColor[1] = green;
73 gCurrentBGColor[2] = blue;
74}
75*/
76void reset_num_text_lines(void)
77{
78 gNumTextLines = 0;
79}
80
81void add_text(S32 x, S32 y, char *text) // , ETextModifiers tm, ETextColorModifiers fcm, ETextColorModifiers bcm)
82{
83 if (gNumTextLines > MAX_TEXT_LINES) return;
84
85 TEXT_LINE *linep = &gTextLine[gNumTextLines++];
86
87 strcpy(linep->line, text);
88 linep->x = x;
89 linep->y = y;
90}
91
92
93// Writes text on the screen. Deprecated, don't write new code using this.
94void show_text_gl(void)
95{
96 S32 i;
97
98 TEXT_LINE *linep;
99
100 if (gNumTextLines > MAX_TEXT_LINES)
101 {
102 gNumTextLines = MAX_TEXT_LINES;
103 }
104
105 for (i = 0; i < gNumTextLines; i++)
106 {
107 linep = &gTextLine[i];
108
109 LLFontGL::sMonospace->renderUTF8(linep->line, 0, (F32)linep->x, (F32)linep->y, gCurrentColor,
110 LLFontGL::LEFT, LLFontGL::TOP,
111 LLFontGL::NORMAL, S32_MAX, S32_MAX, NULL, FALSE);
112 }
113 gNumTextLines = 0;
114}
115
diff --git a/linden/indra/llrender/text_out.h b/linden/indra/llrender/text_out.h
new file mode 100644
index 0000000..5080bd5
--- /dev/null
+++ b/linden/indra/llrender/text_out.h
@@ -0,0 +1,40 @@
1/**
2 * @file text_out.h
3 * @brief Text rendering implementation
4 *
5 * Copyright (c) 2000-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LL_TEXT_OUT_H
29#define LL_TEXT_OUT_H
30
31// DEPRECATED - Use LLFontGL for raw rendering, or make an LLTextBox to hold the text
32
33class LLColor4;
34
35void set_text_color(const LLColor4& color);
36void add_text(S32 x, S32 y, char *text);
37void show_text_gl(void);
38void reset_num_text_lines(void);
39
40#endif