diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llrender | |
parent | README.txt (diff) | |
download | meta-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 '')
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 @@ | |||
1 | llrender/llagpmempoolarb.cpp | ||
2 | llrender/llagpmempool.cpp | ||
3 | llrender/llfont.cpp | ||
4 | llrender/llfontgl.cpp | ||
5 | llrender/llgldbg.cpp | ||
6 | llrender/llimagegl.cpp | ||
7 | llrender/llvertexprogramgl.cpp | ||
8 | llrender/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 | ||
42 | S32 LLAGPMemPool::LLFreeBlock::sNumBlocks = 0; | ||
43 | |||
44 | LLAGPMemPool::LLAGPMemPool() | ||
45 | { | ||
46 | mSize = 0; | ||
47 | mTotalAllocated = 0; | ||
48 | } | ||
49 | |||
50 | LLAGPMemPool::~LLAGPMemPool() | ||
51 | { | ||
52 | mFreeList.deleteAll(); | ||
53 | } | ||
54 | |||
55 | LLAGPMemPool *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 | |||
85 | LLAGPMemBlock *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 | |||
137 | void 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 | |||
169 | void 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 | |||
184 | void 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... | ||
38 | const S32 MIN_AGP_SIZE = 8000000; | ||
39 | |||
40 | class LLAGPMemBlock; | ||
41 | |||
42 | class LLAGPMemPool | ||
43 | { | ||
44 | public: | ||
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(); | ||
79 | protected: | ||
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. | ||
91 | class LLAGPMemBlock | ||
92 | { | ||
93 | public: | ||
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; | ||
117 | protected: | ||
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 | |||
37 | LLAGPMemPoolAPPLE::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 | |||
62 | LLAGPMemBlockAPPLE::~LLAGPMemBlockAPPLE() | ||
63 | { | ||
64 | mMemPoolp->freeBlock(this); | ||
65 | } | ||
66 | |||
67 | LLAGPMemBlock *LLAGPMemPoolAPPLE::createBlock(const U32 offset, const U32 size) | ||
68 | { | ||
69 | return new LLAGPMemBlockAPPLE(this, mBase, offset, size); | ||
70 | } | ||
71 | |||
72 | LLAGPMemPoolAPPLE::~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 | |||
82 | void LLAGPMemPoolAPPLE::bind() | ||
83 | { | ||
84 | if(mBase) | ||
85 | { | ||
86 | glVertexArrayRangeAPPLE(mSize, mBase); | ||
87 | } | ||
88 | } | ||
89 | |||
90 | void LLAGPMemPoolAPPLE::enable() | ||
91 | { | ||
92 | glEnableClientState(GL_VERTEX_ARRAY_RANGE_APPLE); | ||
93 | } | ||
94 | |||
95 | void LLAGPMemPoolAPPLE::disable() | ||
96 | { | ||
97 | glDisableClientState(GL_VERTEX_ARRAY_RANGE_APPLE); | ||
98 | } | ||
99 | |||
100 | void LLAGPMemPoolAPPLE::flush() | ||
101 | { | ||
102 | if(mBase) | ||
103 | { | ||
104 | glFlushVertexArrayRangeAPPLE(mSize, mBase); | ||
105 | } | ||
106 | } | ||
107 | |||
108 | void 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 | |||
131 | U32 LLAGPMemPoolAPPLE::createFence() | ||
132 | { | ||
133 | U32 fence; | ||
134 | glGenFencesAPPLE(1, (GLuint*)&fence); | ||
135 | glSetFenceAPPLE(fence); | ||
136 | glFinishFenceAPPLE(fence); | ||
137 | return fence; | ||
138 | } | ||
139 | |||
140 | |||
141 | void LLAGPMemPoolAPPLE::deleteFence(const U32 fence) | ||
142 | { | ||
143 | glDeleteFencesAPPLE(1, (GLuint*)&fence); | ||
144 | } | ||
145 | |||
146 | |||
147 | void LLAGPMemPoolAPPLE::sendFence(U32 fence) | ||
148 | { | ||
149 | glSetFenceAPPLE(fence); | ||
150 | } | ||
151 | |||
152 | |||
153 | void 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 | |||
169 | LLAGPMemBlockAPPLE::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 | |||
177 | void 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 | |||
186 | void 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 | |||
196 | void 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 | |||
206 | void 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 | |||
216 | void 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 | |||
226 | void 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 | |||
236 | void 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 | |||
245 | U8* LLAGPMemBlockAPPLE::getMappedMem() | ||
246 | { | ||
247 | return mMemp; | ||
248 | } | ||
249 | |||
250 | |||
251 | void 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 | |||
264 | void 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 | |||
279 | U32 LLAGPMemBlockAPPLE::createFence() | ||
280 | { | ||
281 | U32 fence; | ||
282 | glGenFencesAPPLE(1, (GLuint*)&fence); | ||
283 | glSetFenceAPPLE(fence); | ||
284 | glFinishFenceAPPLE(fence); | ||
285 | return fence; | ||
286 | } | ||
287 | |||
288 | void LLAGPMemBlockAPPLE::deleteFence(const U32 fence) | ||
289 | { | ||
290 | glDeleteFencesAPPLE(1, (GLuint*)&fence); | ||
291 | } | ||
292 | |||
293 | void LLAGPMemBlockAPPLE::sendFence(U32 fence) | ||
294 | { | ||
295 | glSetFenceAPPLE(fence); | ||
296 | } | ||
297 | |||
298 | void 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 | ||
308 | void 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 | ||
34 | class LLAGPMemPoolAPPLE : public LLAGPMemPool | ||
35 | { | ||
36 | public: | ||
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 | |||
51 | protected: | ||
52 | /*virtual*/ LLAGPMemBlock *createBlock(const U32 offset, const U32 size); | ||
53 | |||
54 | protected: | ||
55 | U8 *mBase; | ||
56 | }; | ||
57 | |||
58 | class LLAGPMemBlockAPPLE : public LLAGPMemBlock | ||
59 | { | ||
60 | public: | ||
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 | |||
86 | private: | ||
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 | |||
34 | LLAGPMemPoolARB::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 | |||
50 | LLAGPMemPoolARB::~LLAGPMemPoolARB() | ||
51 | { | ||
52 | } | ||
53 | |||
54 | |||
55 | LLAGPMemBlock* LLAGPMemPoolARB::allocBlock(const S32 size) | ||
56 | { | ||
57 | return allocBlock(size, GL_ARRAY_BUFFER_ARB); | ||
58 | } | ||
59 | |||
60 | LLAGPMemBlock *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 | |||
79 | void 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 | |||
94 | LLAGPMemBlock *LLAGPMemPoolARB::createBlock(const U32 offset, const U32 size) | ||
95 | { | ||
96 | return createBlock(offset, size, GL_ARRAY_BUFFER_ARB); | ||
97 | } | ||
98 | |||
99 | LLAGPMemBlock *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 | |||
108 | void LLAGPMemPoolARB::disable() | ||
109 | { | ||
110 | } | ||
111 | |||
112 | void LLAGPMemPoolARB::dump() | ||
113 | { | ||
114 | } | ||
115 | |||
116 | |||
117 | ///////////////////////////// | ||
118 | // | ||
119 | // LLAGPMemBlockARB | ||
120 | // | ||
121 | // ARB ImplementARBon of an AGP memory block | ||
122 | // | ||
123 | |||
124 | LLAGPMemBlockARB::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 | |||
142 | void 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 | |||
151 | void 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 | |||
161 | void 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 | |||
171 | void 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 | |||
181 | void 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 | |||
190 | void 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 | |||
200 | void LLAGPMemBlockARB::bindGLVertexClothingWeightPointer(const S32 index, const U32 stride, const U32 offset) | ||
201 | { | ||
202 | return; | ||
203 | } | ||
204 | |||
205 | |||
206 | void 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 | |||
216 | void 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 | |||
227 | U8* 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 | |||
33 | class LLAGPMemPoolARB : public LLAGPMemPool | ||
34 | { | ||
35 | public: | ||
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(); | ||
55 | protected: | ||
56 | /*virtual*/ LLAGPMemBlock *createBlock(const U32 offset, const U32 size); | ||
57 | LLAGPMemBlock *createBlock(const U32 offset, const U32 size, const U32 target); | ||
58 | |||
59 | protected: | ||
60 | U32 mName; | ||
61 | }; | ||
62 | |||
63 | class LLAGPMemBlockARB : public LLAGPMemBlock | ||
64 | { | ||
65 | public: | ||
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; } | ||
95 | private: | ||
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 | |||
35 | LLAGPMemPoolATI::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 | |||
67 | LLAGPMemPoolATI::~LLAGPMemPoolATI() | ||
68 | { | ||
69 | if (mName) | ||
70 | { | ||
71 | glFreeObjectBufferATI(mName); | ||
72 | } | ||
73 | } | ||
74 | |||
75 | |||
76 | LLAGPMemBlock *LLAGPMemPoolATI::createBlock(const U32 offset, const U32 size) | ||
77 | { | ||
78 | return new LLAGPMemBlockATI(this, mName, offset, size); | ||
79 | } | ||
80 | |||
81 | |||
82 | void LLAGPMemPoolATI::dump() | ||
83 | { | ||
84 | } | ||
85 | |||
86 | |||
87 | ///////////////////////////// | ||
88 | // | ||
89 | // LLAGPMemBlockATI | ||
90 | // | ||
91 | // ATI Implementation of an AGP memory block | ||
92 | // | ||
93 | |||
94 | LLAGPMemBlockATI::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 | |||
103 | void LLAGPMemBlockATI::bindGLVertexPointer(const U32 stride, const U32 offset) | ||
104 | { | ||
105 | glArrayObjectATI(GL_VERTEX_ARRAY, 3, GL_FLOAT, stride, mName, mOffset + offset); | ||
106 | } | ||
107 | |||
108 | |||
109 | void LLAGPMemBlockATI::bindGLNormalPointer(const U32 stride, const U32 offset) | ||
110 | { | ||
111 | glArrayObjectATI(GL_NORMAL_ARRAY, 3, GL_FLOAT, stride, mName, mOffset + offset); | ||
112 | } | ||
113 | |||
114 | |||
115 | void 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 | |||
121 | void 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 | |||
127 | void 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 | |||
133 | void 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 | |||
139 | void 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 | |||
144 | U8* LLAGPMemBlockATI::getMappedMem() | ||
145 | { | ||
146 | return NULL; | ||
147 | } | ||
148 | |||
149 | void LLAGPMemBlockATI::copy(void *mem, const U32 size) | ||
150 | { | ||
151 | llassert(size <= mSize); | ||
152 | glUpdateObjectBufferATI(mName, mOffset, size, mem, GL_PRESERVE_ATI); | ||
153 | } | ||
154 | |||
155 | void 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 | |||
33 | class LLAGPMemPoolATI : public LLAGPMemPool | ||
34 | { | ||
35 | public: | ||
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(); | ||
51 | protected: | ||
52 | /*virtual*/ LLAGPMemBlock *createBlock(const U32 offset, const U32 size); | ||
53 | |||
54 | protected: | ||
55 | U32 mName; | ||
56 | }; | ||
57 | |||
58 | class LLAGPMemBlockATI : public LLAGPMemBlock | ||
59 | { | ||
60 | public: | ||
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) { } | ||
84 | private: | ||
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 | |||
44 | BOOL LLAGPMemPoolNV::sWriteOK = TRUE; | ||
45 | |||
46 | LLAGPMemPoolNV::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 | |||
86 | LLAGPMemBlock *LLAGPMemPoolNV::createBlock(const U32 offset, const U32 size) | ||
87 | { | ||
88 | return new LLAGPMemBlockNV(this, mBase, offset, size); | ||
89 | } | ||
90 | |||
91 | LLAGPMemPoolNV::~LLAGPMemPoolNV() | ||
92 | { | ||
93 | if (mBase) | ||
94 | { | ||
95 | wglFreeMemoryNV(mBase); | ||
96 | } | ||
97 | } | ||
98 | |||
99 | void LLAGPMemPoolNV::bind() | ||
100 | { | ||
101 | glVertexArrayRangeNV(mSize, mBase); | ||
102 | } | ||
103 | |||
104 | void LLAGPMemPoolNV::enable() | ||
105 | { | ||
106 | glEnableClientState(GL_VERTEX_ARRAY_RANGE_NV); | ||
107 | sWriteOK = FALSE; | ||
108 | } | ||
109 | |||
110 | void LLAGPMemPoolNV::disable() | ||
111 | { | ||
112 | glDisableClientState(GL_VERTEX_ARRAY_RANGE_NV); | ||
113 | sWriteOK = TRUE; | ||
114 | } | ||
115 | |||
116 | void LLAGPMemPoolNV::flush() | ||
117 | { | ||
118 | glFlushVertexArrayRangeNV(); | ||
119 | } | ||
120 | |||
121 | U32 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 | |||
130 | void LLAGPMemPoolNV::deleteFence(const U32 fence) | ||
131 | { | ||
132 | glDeleteFencesNV(1, &fence); | ||
133 | } | ||
134 | |||
135 | void LLAGPMemPoolNV::sendFence(U32 fence) | ||
136 | { | ||
137 | glSetFenceNV(fence, GL_ALL_COMPLETED_NV); | ||
138 | } | ||
139 | |||
140 | void LLAGPMemPoolNV::waitFence(U32 fence) | ||
141 | { | ||
142 | if(!glTestFenceNV(fence)) | ||
143 | { | ||
144 | glFinishFenceNV(fence); | ||
145 | } | ||
146 | } | ||
147 | |||
148 | |||
149 | //static | ||
150 | BOOL LLAGPMemPoolNV::isWriteOK() | ||
151 | { | ||
152 | return sWriteOK; | ||
153 | } | ||
154 | |||
155 | void 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 | |||
178 | LLAGPMemBlockNV::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 | |||
185 | extern U8* gAGPVertices; | ||
186 | |||
187 | void 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 | |||
196 | void 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 | |||
206 | void 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 | |||
216 | void 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 | |||
226 | void 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 | |||
236 | void 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 | |||
246 | void 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 | |||
255 | U8* LLAGPMemBlockNV::getMappedMem() | ||
256 | { | ||
257 | return mMemp; | ||
258 | } | ||
259 | |||
260 | void 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 | |||
276 | void 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 | |||
293 | U32 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 | |||
302 | void LLAGPMemBlockNV::deleteFence(const U32 fence) | ||
303 | { | ||
304 | glDeleteFencesNV(1, &fence); | ||
305 | } | ||
306 | |||
307 | void LLAGPMemBlockNV::sendFence(U32 fence) | ||
308 | { | ||
309 | glSetFenceNV(fence, GL_ALL_COMPLETED_NV); | ||
310 | } | ||
311 | |||
312 | void 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 | |||
33 | class LLAGPMemPoolNV : public LLAGPMemPool | ||
34 | { | ||
35 | public: | ||
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); | ||
51 | protected: | ||
52 | /*virtual*/ LLAGPMemBlock *createBlock(const U32 offset, const U32 size); | ||
53 | |||
54 | protected: | ||
55 | U8 *mBase; | ||
56 | |||
57 | static BOOL sWriteOK; | ||
58 | }; | ||
59 | |||
60 | class LLAGPMemBlockNV : public LLAGPMemBlock | ||
61 | { | ||
62 | public: | ||
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 | |||
88 | private: | ||
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 | |||
51 | FT_Render_Mode gFontRenderMode = FT_RENDER_MODE_NORMAL; | ||
52 | |||
53 | LLFontManager *gFontManagerp = NULL; | ||
54 | |||
55 | FT_Library gFTLibrary = NULL; | ||
56 | |||
57 | //static | ||
58 | void LLFontManager::initClass() | ||
59 | { | ||
60 | gFontManagerp = new LLFontManager; | ||
61 | } | ||
62 | |||
63 | //static | ||
64 | void LLFontManager::cleanupClass() | ||
65 | { | ||
66 | delete gFontManagerp; | ||
67 | gFontManagerp = NULL; | ||
68 | } | ||
69 | |||
70 | LLFontManager::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 | |||
83 | LLFontManager::~LLFontManager() | ||
84 | { | ||
85 | FT_Done_FreeType(gFTLibrary); | ||
86 | } | ||
87 | |||
88 | |||
89 | LLFontGlyphInfo::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 | |||
103 | LLFontList::LLFontList() | ||
104 | { | ||
105 | } | ||
106 | |||
107 | LLFontList::~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 | } | ||
116 | void LLFontList::addAtEnd(LLFont *font) | ||
117 | { | ||
118 | // Purely a convenience function | ||
119 | this->push_back(font); | ||
120 | } | ||
121 | |||
122 | LLFont::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 | |||
141 | LLFont::~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 | |||
153 | void LLFont::setRawImage(LLImageRaw *imagep) | ||
154 | { | ||
155 | mRawImagep = imagep; // will delete old raw image if we have one and created it | ||
156 | } | ||
157 | |||
158 | // virtual | ||
159 | F32 LLFont::getLineHeight() const | ||
160 | { | ||
161 | return mLineHeight; | ||
162 | } | ||
163 | |||
164 | // virtual | ||
165 | F32 LLFont::getAscenderHeight() const | ||
166 | { | ||
167 | return mAscender; | ||
168 | } | ||
169 | |||
170 | // virtual | ||
171 | F32 LLFont::getDescenderHeight() const | ||
172 | { | ||
173 | return mDescender; | ||
174 | } | ||
175 | |||
176 | BOOL 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 | |||
280 | void 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 | |||
298 | LLFontGlyphInfo* 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 | |||
309 | BOOL 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 | |||
323 | BOOL 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 | |||
361 | void 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 | |||
375 | BOOL 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 | |||
492 | BOOL LLFont::addGlyph(const llwchar wch, const U32 glyph_index) | ||
493 | { | ||
494 | return addGlyphFromFont(this, wch, glyph_index); | ||
495 | } | ||
496 | |||
497 | |||
498 | F32 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 | |||
566 | void 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 | |||
576 | F32 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 | |||
592 | void 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 | |||
35 | class LLImageRaw; | ||
36 | class LLFontManager; | ||
37 | class 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 | ||
43 | struct FT_FaceRec_; | ||
44 | typedef struct FT_FaceRec_* LLFT_Face; | ||
45 | |||
46 | extern LLFontManager *gFontManagerp; | ||
47 | |||
48 | class LLFontManager | ||
49 | { | ||
50 | public: | ||
51 | static void initClass(); | ||
52 | static void cleanupClass(); | ||
53 | |||
54 | public: | ||
55 | LLFontManager(); | ||
56 | virtual ~LLFontManager(); | ||
57 | }; | ||
58 | |||
59 | class LLFontGlyphInfo | ||
60 | { | ||
61 | public: | ||
62 | LLFontGlyphInfo(U32 index); | ||
63 | public: | ||
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 | ||
80 | class LLFontList : public std::vector<LLFont*> | ||
81 | { | ||
82 | public: | ||
83 | LLFontList(); | ||
84 | ~LLFontList(); | ||
85 | void addAtEnd(LLFont *font); | ||
86 | }; | ||
87 | |||
88 | |||
89 | class LLFont | ||
90 | { | ||
91 | public: | ||
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 | ||
142 | protected: | ||
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 | ||
154 | protected: | ||
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 | |||
184 | private: | ||
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 | |||
37 | const S32 BOLD_OFFSET = 1; | ||
38 | |||
39 | // static class members | ||
40 | F32 LLFontGL::sVertDPI = 96.f; | ||
41 | F32 LLFontGL::sHorizDPI = 96.f; | ||
42 | F32 LLFontGL::sScaleX = 1.f; | ||
43 | F32 LLFontGL::sScaleY = 1.f; | ||
44 | LLString LLFontGL::sAppDir; | ||
45 | |||
46 | LLFontGL* LLFontGL::sMonospace = NULL; | ||
47 | LLFontGL* LLFontGL::sSansSerifSmall = NULL; | ||
48 | LLFontGL* LLFontGL::sSansSerif = NULL; | ||
49 | LLFontGL* LLFontGL::sSansSerifBig = NULL; | ||
50 | LLFontGL* LLFontGL::sSansSerifHuge = NULL; | ||
51 | LLFontGL* LLFontGL::sSansSerifBold = NULL; | ||
52 | LLFontList* LLFontGL::sSSFallback = NULL; | ||
53 | LLFontList* LLFontGL::sSSSmallFallback = NULL; | ||
54 | LLFontList* LLFontGL::sSSBigFallback = NULL; | ||
55 | LLFontList* LLFontGL::sSSHugeFallback = NULL; | ||
56 | LLFontList* LLFontGL::sSSBoldFallback = NULL; | ||
57 | LLColor4 LLFontGL::sShadowColor(0.f, 0.f, 0.f, 1.f); | ||
58 | |||
59 | LLCoordFont LLFontGL::sCurOrigin; | ||
60 | std::vector<LLCoordFont> LLFontGL::sOriginStack; | ||
61 | |||
62 | LLFontGL*& gExtCharFont = LLFontGL::sSansSerif; | ||
63 | |||
64 | const F32 EXT_X_BEARING = 1.f; | ||
65 | const F32 EXT_Y_BEARING = 0.f; | ||
66 | const F32 EXT_KERNING = 1.f; | ||
67 | const F32 PIXEL_BORDER_THRESHOLD = 0.0001f; | ||
68 | const F32 PIXEL_CORRECTION_DISTANCE = 0.01f; | ||
69 | |||
70 | const F32 PAD_AMT = 0.5f; | ||
71 | |||
72 | F32 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 | |||
79 | F32 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 | ||
87 | U8 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 | |||
109 | LLFontGL::LLFontGL() | ||
110 | : LLFont() | ||
111 | { | ||
112 | init(); | ||
113 | clearEmbeddedChars(); | ||
114 | } | ||
115 | |||
116 | LLFontGL::LLFontGL(const LLFontGL &source) | ||
117 | { | ||
118 | llerrs << "Not implemented!" << llendl; | ||
119 | } | ||
120 | |||
121 | LLFontGL::~LLFontGL() | ||
122 | { | ||
123 | mImageGLp = NULL; | ||
124 | mRawImageGLp = NULL; | ||
125 | clearEmbeddedChars(); | ||
126 | } | ||
127 | |||
128 | void 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 | |||
144 | void LLFontGL::reset() | ||
145 | { | ||
146 | init(); | ||
147 | resetBitmap(); | ||
148 | } | ||
149 | |||
150 | // static | ||
151 | LLString 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 | ||
184 | LLString 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 | ||
205 | bool 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 | ||
243 | bool 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 | ||
264 | BOOL 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 | ||
412 | void 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 | ||
449 | void 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 | |||
466 | LLFontGL &LLFontGL::operator=(const LLFontGL &source) | ||
467 | { | ||
468 | llerrs << "Not implemented" << llendl; | ||
469 | return *this; | ||
470 | } | ||
471 | |||
472 | BOOL 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 | |||
484 | BOOL 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 | |||
500 | S32 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 | |||
513 | S32 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 | |||
891 | LLImageGL *LLFontGL::getImageGL() const | ||
892 | { | ||
893 | return mImageGLp; | ||
894 | } | ||
895 | |||
896 | S32 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 | |||
902 | S32 LLFontGL::getWidth(const llwchar* wchars) const | ||
903 | { | ||
904 | return getWidth(wchars, 0, S32_MAX); | ||
905 | } | ||
906 | |||
907 | S32 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 | |||
913 | S32 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 | |||
919 | F32 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 | |||
925 | F32 LLFontGL::getWidthF32(const llwchar* wchars) const | ||
926 | { | ||
927 | return getWidthF32(wchars, 0, S32_MAX); | ||
928 | } | ||
929 | |||
930 | F32 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 | |||
936 | F32 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 | ||
983 | S32 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 | |||
1094 | S32 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 | |||
1168 | S32 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 | |||
1273 | const 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 | |||
1285 | F32 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 | |||
1300 | void LLFontGL::clearEmbeddedChars() | ||
1301 | { | ||
1302 | for_each(mEmbeddedChars.begin(), mEmbeddedChars.end(), DeletePairedPointer()); | ||
1303 | mEmbeddedChars.clear(); | ||
1304 | } | ||
1305 | |||
1306 | void LLFontGL::addEmbeddedChar( llwchar wc, LLImageGL* image, const LLString& label ) | ||
1307 | { | ||
1308 | LLWString wlabel = utf8str_to_wstring(label); | ||
1309 | addEmbeddedChar(wc, image, wlabel); | ||
1310 | } | ||
1311 | |||
1312 | void 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 | |||
1318 | void 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 | ||
1329 | LLString 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 | ||
1362 | LLFontGL* 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 | ||
1393 | LLString 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 | ||
1402 | LLFontGL::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 | ||
1422 | LLString 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 | ||
1432 | LLFontGL::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 | |||
37 | class LLColor4; | ||
38 | |||
39 | class LLFontGL : public LLFont | ||
40 | { | ||
41 | public: | ||
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 | |||
199 | protected: | ||
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 | |||
210 | public: | ||
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 | |||
236 | protected: | ||
237 | /*virtual*/ BOOL addChar(const llwchar wch); | ||
238 | static LLString getFontPathLocal(); | ||
239 | static LLString getFontPathSystem(); | ||
240 | |||
241 | protected: | ||
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 | |||
247 | public: | ||
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 | //------------------------------------------------------------------------ | ||
42 | char *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 | //------------------------------------------------------------------------ | ||
58 | char *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 | //------------------------------------------------------------------------ | ||
72 | const char *boolstr(int b) | ||
73 | { | ||
74 | return b ? "GL_TRUE" : "GL_FALSE"; | ||
75 | } | ||
76 | |||
77 | //------------------------------------------------------------------------ | ||
78 | // fv4() | ||
79 | //------------------------------------------------------------------------ | ||
80 | char *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 | //------------------------------------------------------------------------ | ||
90 | char *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 | //------------------------------------------------------------------------ | ||
100 | char *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 | //------------------------------------------------------------------------ | ||
110 | void 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. | ||
32 | void 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 | |||
43 | const F32 MIN_TEXTURE_LIFETIME = 10.f; | ||
44 | |||
45 | //statics | ||
46 | LLGLuint LLImageGL::sCurrentBoundTextures[MAX_GL_TEXTURE_UNITS] = { 0 }; | ||
47 | |||
48 | S32 LLImageGL::sGlobalTextureMemory = 0; | ||
49 | S32 LLImageGL::sBoundTextureMemory = 0; | ||
50 | S32 LLImageGL::sCurBoundTextureMemory = 0; | ||
51 | S32 LLImageGL::sCount = 0; | ||
52 | |||
53 | BOOL LLImageGL::sGlobalUseAnisotropic = FALSE; | ||
54 | F32 LLImageGL::sLastFrameTime = 0.f; | ||
55 | |||
56 | std::set<LLImageGL*> LLImageGL::sImageList; | ||
57 | |||
58 | //---------------------------------------------------------------------------- | ||
59 | |||
60 | //static | ||
61 | S32 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 | ||
83 | S32 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 | ||
97 | S32 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 | ||
120 | void 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 | ||
129 | void 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 | ||
138 | void LLImageGL::updateStats(F32 current_time) | ||
139 | { | ||
140 | sLastFrameTime = current_time; | ||
141 | sBoundTextureMemory = sCurBoundTextureMemory; | ||
142 | sCurBoundTextureMemory = 0; | ||
143 | } | ||
144 | |||
145 | //static | ||
146 | S32 LLImageGL::updateBoundTexMem(const S32 delta) | ||
147 | { | ||
148 | LLImageGL::sCurBoundTextureMemory += delta; | ||
149 | return LLImageGL::sCurBoundTextureMemory; | ||
150 | } | ||
151 | |||
152 | //---------------------------------------------------------------------------- | ||
153 | |||
154 | //static | ||
155 | void 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 | ||
179 | void 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 | ||
200 | BOOL LLImageGL::create(LLPointer<LLImageGL>& dest, BOOL usemipmaps) | ||
201 | { | ||
202 | dest = new LLImageGL(usemipmaps); | ||
203 | return TRUE; | ||
204 | } | ||
205 | |||
206 | BOOL 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 | |||
212 | BOOL LLImageGL::create(LLPointer<LLImageGL>& dest, const LLImageRaw* imageraw, BOOL usemipmaps) | ||
213 | { | ||
214 | dest = new LLImageGL(imageraw, usemipmaps); | ||
215 | return TRUE; | ||
216 | } | ||
217 | |||
218 | //---------------------------------------------------------------------------- | ||
219 | |||
220 | LLImageGL::LLImageGL(BOOL usemipmaps) | ||
221 | : mSaveData(0) | ||
222 | { | ||
223 | init(usemipmaps); | ||
224 | setSize(0, 0, 0); | ||
225 | sImageList.insert(this); | ||
226 | sCount++; | ||
227 | } | ||
228 | |||
229 | LLImageGL::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 | |||
239 | LLImageGL::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 | |||
249 | LLImageGL::~LLImageGL() | ||
250 | { | ||
251 | LLImageGL::cleanup(); | ||
252 | sImageList.erase(this); | ||
253 | sCount--; | ||
254 | } | ||
255 | |||
256 | void 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 | |||
290 | void LLImageGL::cleanup() | ||
291 | { | ||
292 | if (!gGLManager.mIsDisabled) | ||
293 | { | ||
294 | destroyGLTexture(); | ||
295 | } | ||
296 | mSaveData = NULL; // deletes data | ||
297 | } | ||
298 | |||
299 | //---------------------------------------------------------------------------- | ||
300 | |||
301 | static 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 | ||
315 | bool LLImageGL::checkSize(S32 width, S32 height) | ||
316 | { | ||
317 | return check_power_of_two(width) && check_power_of_two(height); | ||
318 | } | ||
319 | |||
320 | void 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 | ||
359 | void 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 | |||
386 | BOOL 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 | ||
434 | BOOL 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 | |||
445 | void 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 | |||
461 | void 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 | |||
470 | void 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 | |||
656 | BOOL 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 | |||
740 | BOOL 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 | ||
746 | BOOL 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 | |||
760 | BOOL 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 | |||
819 | BOOL 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 | |||
899 | BOOL 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 | |||
950 | BOOL 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 | |||
1007 | void 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 | |||
1034 | void 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 | |||
1046 | void 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 | |||
1090 | BOOL 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 | |||
1107 | S32 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 | |||
1118 | S32 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 | |||
1129 | S32 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 | |||
1142 | S32 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 | |||
1163 | BOOL LLImageGL::getBoundRecently() const | ||
1164 | { | ||
1165 | return (BOOL)(sLastFrameTime - mLastBindTime < MIN_TEXTURE_LIFETIME); | ||
1166 | } | ||
1167 | |||
1168 | void 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 | |||
39 | class LLImageGL : public LLThreadSafeRefCount | ||
40 | { | ||
41 | public: | ||
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 | |||
70 | public: | ||
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 | |||
75 | protected: | ||
76 | virtual ~LLImageGL(); | ||
77 | BOOL bindTextureInternal(const S32 stage = 0) const; | ||
78 | |||
79 | public: | ||
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 | |||
128 | protected: | ||
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 | |||
132 | public: | ||
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 | |||
138 | private: | ||
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 | |||
145 | protected: | ||
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 | ||
171 | public: | ||
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? | ||
195 | class LLImageProviderInterface | ||
196 | { | ||
197 | public: | ||
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 | |||
37 | LLVertexProgramGL::LLVertexProgramGL() | ||
38 | { | ||
39 | mVertexProgramID = 0; | ||
40 | } | ||
41 | |||
42 | LLVertexProgramGL::~LLVertexProgramGL() | ||
43 | { | ||
44 | glDeleteProgramsARB(1, (GLuint*) &mVertexProgramID); | ||
45 | } | ||
46 | |||
47 | BOOL 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 | |||
112 | void LLVertexProgramGL::bind() | ||
113 | { | ||
114 | glEnable(GL_VERTEX_PROGRAM_ARB); | ||
115 | glBindProgramARB(GL_VERTEX_PROGRAM_ARB, mVertexProgramID); | ||
116 | } | ||
117 | |||
118 | void 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 | |||
36 | class LLVertexProgramGL | ||
37 | { | ||
38 | public: | ||
39 | LLVertexProgramGL(); | ||
40 | ~LLVertexProgramGL(); | ||
41 | |||
42 | void bind(); | ||
43 | void unbind(); | ||
44 | |||
45 | BOOL load(const char * filename); | ||
46 | |||
47 | private: | ||
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 | |||
40 | extern S32 gWindowWidth; | ||
41 | extern S32 gWindowHeight; | ||
42 | |||
43 | S32 gNumTextLines = 0; | ||
44 | |||
45 | LLColor4 gCurrentColor; | ||
46 | //U8 gCurrentBGColor[] = { 32, 32, 32 }; | ||
47 | |||
48 | //F32 gCurrentScale = 10.f; | ||
49 | |||
50 | typedef 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 | |||
62 | TEXT_LINE gTextLine[MAX_TEXT_LINES]; | ||
63 | |||
64 | void set_text_color( const LLColor4& color ) | ||
65 | { | ||
66 | gCurrentColor = color; | ||
67 | } | ||
68 | /* | ||
69 | void 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 | */ | ||
76 | void reset_num_text_lines(void) | ||
77 | { | ||
78 | gNumTextLines = 0; | ||
79 | } | ||
80 | |||
81 | void 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. | ||
94 | void 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 | |||
33 | class LLColor4; | ||
34 | |||
35 | void set_text_color(const LLColor4& color); | ||
36 | void add_text(S32 x, S32 y, char *text); | ||
37 | void show_text_gl(void); | ||
38 | void reset_num_text_lines(void); | ||
39 | |||
40 | #endif | ||