blob: 2174305b0c8694836e6c17d8888bf9c3f6167ab3 [file] [log] [blame]
Adam Jacksoncb3610e2004-10-25 21:09:16 +00001/*
Adam Jacksondc8058c2008-09-19 17:16:53 -04002 * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
3 * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice including the dates of first publication and
13 * either this permission notice or a reference to
14 * http://oss.sgi.com/projects/FreeB/
15 * shall be included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
22 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 *
25 * Except as contained in this notice, the name of Silicon Graphics, Inc.
26 * shall not be used in advertising or otherwise to promote the sale, use or
27 * other dealings in this Software without prior written authorization from
28 * Silicon Graphics, Inc.
29 */
Adam Jacksoncb3610e2004-10-25 21:09:16 +000030
31#include "packrender.h"
32
Adam Jackson473fe6d2004-11-03 18:55:31 +000033static const GLubyte MsbToLsbTable[256] = {
Adam Jacksoncb3610e2004-10-25 21:09:16 +000034 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
35 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
36 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
37 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
38 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
39 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
40 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
41 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
42 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
43 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
44 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
45 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
46 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
47 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
48 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
49 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
50 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
51 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
52 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
53 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
54 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
55 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
56 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
57 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
58 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
59 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
60 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
61 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
62 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
63 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
64 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
65 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
66};
67
Adam Jackson473fe6d2004-11-03 18:55:31 +000068static const GLubyte LowBitsMask[9] = {
Adam Jacksoncb3610e2004-10-25 21:09:16 +000069 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff,
70};
71
Adam Jackson473fe6d2004-11-03 18:55:31 +000072static const GLubyte HighBitsMask[9] = {
Adam Jacksoncb3610e2004-10-25 21:09:16 +000073 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff,
74};
75
76
77/*
78** Copy bitmap data from clients packed memory applying unpacking modes as the
79** data is transfered into the destImage buffer. Return in modes the
80** set of pixel modes that are to be done by the server.
81*/
82static void FillBitmap(__GLXcontext *gc, GLint width, GLint height,
83 GLenum format, const GLvoid *userdata,
84 GLubyte *destImage)
85{
86 const __GLXattribute * state = gc->client_state_private;
87 GLint rowLength = state->storeUnpack.rowLength;
88 GLint alignment = state->storeUnpack.alignment;
89 GLint skipPixels = state->storeUnpack.skipPixels;
90 GLint skipRows = state->storeUnpack.skipRows;
91 GLint lsbFirst = state->storeUnpack.lsbFirst;
92 GLint elementsLeft, bitOffset, currentByte, nextByte, highBitMask;
93 GLint lowBitMask, i;
94 GLint components, groupsPerRow, rowSize, padding, elementsPerRow;
95 const GLubyte *start, *iter;
96
97 if (rowLength > 0) {
98 groupsPerRow = rowLength;
99 } else {
100 groupsPerRow = width;
101 }
102 components = __glElementsPerGroup(format,GL_BITMAP);
103 rowSize = (groupsPerRow * components + 7) >> 3;
104 padding = (rowSize % alignment);
105 if (padding) {
106 rowSize += alignment - padding;
107 }
108 start = ((const GLubyte*) userdata) + skipRows * rowSize +
109 ((skipPixels * components) >> 3);
110 bitOffset = (skipPixels * components) & 7;
111 highBitMask = LowBitsMask[8-bitOffset];
112 lowBitMask = HighBitsMask[bitOffset];
113 elementsPerRow = width * components;
114 for (i = 0; i < height; i++) {
115 elementsLeft = elementsPerRow;
116 iter = start;
117 while (elementsLeft) {
118 /* First retrieve low bits from current byte */
119 if (lsbFirst) {
120 currentByte = MsbToLsbTable[iter[0]];
121 } else {
122 currentByte = iter[0];
123 }
124 if (bitOffset) {
125 /* Need to read next byte to finish current byte */
126 if (elementsLeft > (8 - bitOffset)) {
127 if (lsbFirst) {
128 nextByte = MsbToLsbTable[iter[1]];
129 } else {
130 nextByte = iter[1];
131 }
132 currentByte =
133 ((currentByte & highBitMask) << bitOffset) |
134 ((nextByte & lowBitMask) >> (8 - bitOffset));
135 } else {
136 currentByte =
137 ((currentByte & highBitMask) << bitOffset);
138 }
139 }
140 if (elementsLeft >= 8) {
141 *destImage = currentByte;
142 elementsLeft -= 8;
143 } else {
144 *destImage = currentByte & HighBitsMask[elementsLeft];
145 elementsLeft = 0;
146 }
147 destImage++;
148 iter++;
149 }
150 start += rowSize;
151 }
152}
153
154/*
155** Extract array from user's data applying all pixel store modes.
156** The internal packed array format used has LSB_FIRST = FALSE and
157** ALIGNMENT = 1.
158*/
159void __glFillImage(__GLXcontext *gc, GLint dim, GLint width, GLint height,
160 GLint depth, GLenum format, GLenum type,
161 const GLvoid *userdata, GLubyte *newimage, GLubyte *modes)
162{
163 const __GLXattribute * state = gc->client_state_private;
164 GLint rowLength = state->storeUnpack.rowLength;
165 GLint imageHeight = state->storeUnpack.imageHeight;
166 GLint alignment = state->storeUnpack.alignment;
167 GLint skipPixels = state->storeUnpack.skipPixels;
168 GLint skipRows = state->storeUnpack.skipRows;
169 GLint skipImages = state->storeUnpack.skipImages;
170 GLint swapBytes = state->storeUnpack.swapEndian;
171 GLint components, elementSize, rowSize, padding, groupsPerRow, groupSize;
172 GLint elementsPerRow, imageSize, rowsPerImage, h, i, j, k;
173 const GLubyte *start, *iter, *itera, *iterb, *iterc;
174 GLubyte *iter2;
175
176 if (type == GL_BITMAP) {
177 FillBitmap(gc, width, height, format, userdata, newimage);
178 } else {
179 components = __glElementsPerGroup(format,type);
180 if (rowLength > 0) {
181 groupsPerRow = rowLength;
182 } else {
183 groupsPerRow = width;
184 }
185 if (imageHeight > 0) {
186 rowsPerImage = imageHeight;
187 } else {
188 rowsPerImage = height;
189 }
190
191 elementSize = __glBytesPerElement(type);
192 groupSize = elementSize * components;
193 if (elementSize == 1) swapBytes = 0;
194
195 rowSize = groupsPerRow * groupSize;
196 padding = (rowSize % alignment);
197 if (padding) {
198 rowSize += alignment - padding;
199 }
200 imageSize = rowSize * rowsPerImage;
201 start = ((const GLubyte*) userdata) + skipImages * imageSize +
202 skipRows * rowSize + skipPixels * groupSize;
203 iter2 = newimage;
204 elementsPerRow = width * components;
205
206 if (swapBytes) {
207 itera = start;
208 for (h = 0; h < depth; h++) {
209 iterb = itera;
210 for (i = 0; i < height; i++) {
211 iterc = iterb;
212 for (j = 0; j < elementsPerRow; j++) {
213 for (k = 1; k <= elementSize; k++) {
214 iter2[k-1] = iterc[elementSize - k];
215 }
216 iter2 += elementSize;
217 iterc += elementSize;
218 }
219 iterb += rowSize;
220 }
221 itera += imageSize;
222 }
223 } else {
224 itera = start;
225 for (h = 0; h < depth; h++) {
226 if (rowSize == elementsPerRow * elementSize) {
227 /* Ha! This is mondo easy! */
228 __GLX_MEM_COPY(iter2, itera,
229 elementsPerRow * elementSize * height);
230 iter2 += elementsPerRow * elementSize * height;
231 } else {
232 iter = itera;
233 for (i = 0; i < height; i++) {
234 __GLX_MEM_COPY(iter2, iter, elementsPerRow*elementSize);
235 iter2 += elementsPerRow * elementSize;
236 iter += rowSize;
237 }
238 }
239 itera += imageSize;
240 }
241 }
242 }
243
244 /* Setup store modes that describe what we just did */
245 if (modes) {
Ian Romanick5f1f2292005-01-07 02:39:09 +0000246 if ( dim < 3 ) {
247 (void) memcpy( modes, __glXDefaultPixelStore + 4, 20 );
248 }
249 else {
250 (void) memcpy( modes, __glXDefaultPixelStore + 0, 36 );
251 }
Adam Jacksoncb3610e2004-10-25 21:09:16 +0000252 }
253}
254
255/*
256** Empty a bitmap in LSB_FIRST=GL_FALSE and ALIGNMENT=4 format packing it
257** into the clients memory using the pixel store PACK modes.
258*/
259static void EmptyBitmap(__GLXcontext *gc, GLint width, GLint height,
260 GLenum format, const GLubyte *sourceImage,
261 GLvoid *userdata)
262{
263 const __GLXattribute * state = gc->client_state_private;
264 GLint rowLength = state->storePack.rowLength;
265 GLint alignment = state->storePack.alignment;
266 GLint skipPixels = state->storePack.skipPixels;
267 GLint skipRows = state->storePack.skipRows;
268 GLint lsbFirst = state->storePack.lsbFirst;
269 GLint components, groupsPerRow, rowSize, padding, elementsPerRow;
270 GLint sourceRowSize, sourcePadding, sourceSkip;
271 GLubyte *start, *iter;
272 GLint elementsLeft, bitOffset, currentByte, highBitMask, lowBitMask;
273 GLint writeMask, i;
274 GLubyte writeByte;
275
276 components = __glElementsPerGroup(format,GL_BITMAP);
277 if (rowLength > 0) {
278 groupsPerRow = rowLength;
279 } else {
280 groupsPerRow = width;
281 }
282
283 rowSize = (groupsPerRow * components + 7) >> 3;
284 padding = (rowSize % alignment);
285 if (padding) {
286 rowSize += alignment - padding;
287 }
288 sourceRowSize = (width * components + 7) >> 3;
289 sourcePadding = (sourceRowSize % 4);
290 if (sourcePadding) {
291 sourceSkip = 4 - sourcePadding;
292 } else {
293 sourceSkip = 0;
294 }
295 start = ((GLubyte*) userdata) + skipRows * rowSize +
296 ((skipPixels * components) >> 3);
297 bitOffset = (skipPixels * components) & 7;
298 highBitMask = LowBitsMask[8-bitOffset];
299 lowBitMask = HighBitsMask[bitOffset];
300 elementsPerRow = width * components;
301 for (i = 0; i < height; i++) {
302 elementsLeft = elementsPerRow;
303 iter = start;
304 writeMask = highBitMask;
305 writeByte = 0;
306 while (elementsLeft) {
307 /* Set up writeMask (to write to current byte) */
308 if (elementsLeft + bitOffset < 8) {
309 /* Need to trim writeMask */
310 writeMask &= HighBitsMask[bitOffset+elementsLeft];
311 }
312
313 if (lsbFirst) {
314 currentByte = MsbToLsbTable[iter[0]];
315 } else {
316 currentByte = iter[0];
317 }
318
319 if (bitOffset) {
320 writeByte |= (sourceImage[0] >> bitOffset);
321 currentByte = (currentByte & ~writeMask) |
322 (writeByte & writeMask);
323 writeByte = (sourceImage[0] << (8 - bitOffset));
324 } else {
325 currentByte = (currentByte & ~writeMask) |
326 (sourceImage[0] & writeMask);
327 }
328
329 if (lsbFirst) {
330 iter[0] = MsbToLsbTable[currentByte];
331 } else {
332 iter[0] = currentByte;
333 }
334
335 if (elementsLeft >= 8) {
336 elementsLeft -= 8;
337 } else {
338 elementsLeft = 0;
339 }
340 sourceImage++;
341 iter++;
342 writeMask = 0xff;
343 }
344 if (writeByte) {
345 /* Some data left over that still needs writing */
346 writeMask &= lowBitMask;
347 if (lsbFirst) {
348 currentByte = MsbToLsbTable[iter[0]];
349 } else {
350 currentByte = iter[0];
351 }
352 currentByte = (currentByte & ~writeMask) | (writeByte & writeMask);
353 if (lsbFirst) {
354 iter[0] = MsbToLsbTable[currentByte];
355 } else {
356 iter[0] = currentByte;
357 }
358 }
359 start += rowSize;
360 sourceImage += sourceSkip;
361 }
362}
363
364/*
365** Insert array into user's data applying all pixel store modes.
366** The packed array format from the server is LSB_FIRST = FALSE,
367** SWAP_BYTES = the current pixel storage pack mode, and ALIGNMENT = 4.
368** Named __glEmptyImage() because it is the opposite of __glFillImage().
369*/
370/* ARGSUSED */
371void __glEmptyImage(__GLXcontext *gc, GLint dim, GLint width, GLint height,
372 GLint depth, GLenum format, GLenum type,
373 const GLubyte *sourceImage, GLvoid *userdata)
374{
375 const __GLXattribute * state = gc->client_state_private;
376 GLint rowLength = state->storePack.rowLength;
377 GLint imageHeight = state->storePack.imageHeight;
378 GLint alignment = state->storePack.alignment;
379 GLint skipPixels = state->storePack.skipPixels;
380 GLint skipRows = state->storePack.skipRows;
381 GLint skipImages = state->storePack.skipImages;
382 GLint components, elementSize, rowSize, padding, groupsPerRow, groupSize;
383 GLint elementsPerRow, sourceRowSize, sourcePadding, h, i;
384 GLint imageSize, rowsPerImage;
385 GLubyte *start, *iter, *itera;
386
387 if (type == GL_BITMAP) {
388 EmptyBitmap(gc, width, height, format, sourceImage, userdata);
389 } else {
390 components = __glElementsPerGroup(format,type);
391 if (rowLength > 0) {
392 groupsPerRow = rowLength;
393 } else {
394 groupsPerRow = width;
395 }
396 if (imageHeight > 0) {
397 rowsPerImage = imageHeight;
398 } else {
399 rowsPerImage = height;
400 }
401 elementSize = __glBytesPerElement(type);
402 groupSize = elementSize * components;
403 rowSize = groupsPerRow * groupSize;
404 padding = (rowSize % alignment);
405 if (padding) {
406 rowSize += alignment - padding;
407 }
408 sourceRowSize = width * groupSize;
409 sourcePadding = (sourceRowSize % 4);
410 if (sourcePadding) {
411 sourceRowSize += 4 - sourcePadding;
412 }
413 imageSize = sourceRowSize * rowsPerImage;
414 start = ((GLubyte*) userdata) + skipImages * imageSize +
415 skipRows * rowSize + skipPixels * groupSize;
416 elementsPerRow = width * components;
417
418 itera = start;
419 for (h = 0; h < depth; h++) {
420 if ((rowSize == sourceRowSize) && (sourcePadding == 0)) {
421 /* Ha! This is mondo easy! */
422 __GLX_MEM_COPY(itera, sourceImage,
423 elementsPerRow * elementSize * height);
424 sourceImage += elementsPerRow * elementSize * height;
425 } else {
426 iter = itera;
427 for (i = 0; i < height; i++) {
428 __GLX_MEM_COPY(iter, sourceImage,
429 elementsPerRow * elementSize);
430 sourceImage += sourceRowSize;
431 iter += rowSize;
432 }
433 }
434 itera += imageSize;
435 }
436 }
437}