1848b8605Smrg/*
2848b8605Smrg * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
3848b8605Smrg * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
4848b8605Smrg *
5848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
6848b8605Smrg * copy of this software and associated documentation files (the "Software"),
7848b8605Smrg * to deal in the Software without restriction, including without limitation
8848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
10848b8605Smrg * Software is furnished to do so, subject to the following conditions:
11848b8605Smrg *
12848b8605Smrg * The above copyright notice including the dates of first publication and
13848b8605Smrg * either this permission notice or a reference to
14848b8605Smrg * http://oss.sgi.com/projects/FreeB/
15848b8605Smrg * shall be included in all copies or substantial portions of the Software.
16848b8605Smrg *
17848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20848b8605Smrg * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21848b8605Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
22848b8605Smrg * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23848b8605Smrg * SOFTWARE.
24848b8605Smrg *
25848b8605Smrg * Except as contained in this notice, the name of Silicon Graphics, Inc.
26848b8605Smrg * shall not be used in advertising or otherwise to promote the sale, use or
27848b8605Smrg * other dealings in this Software without prior written authorization from
28848b8605Smrg * Silicon Graphics, Inc.
29848b8605Smrg */
30848b8605Smrg
31848b8605Smrg#include "packrender.h"
32848b8605Smrg
33848b8605Smrgstatic const GLubyte MsbToLsbTable[256] = {
34848b8605Smrg   0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
35848b8605Smrg   0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
36848b8605Smrg   0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
37848b8605Smrg   0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
38848b8605Smrg   0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
39848b8605Smrg   0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
40848b8605Smrg   0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
41848b8605Smrg   0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
42848b8605Smrg   0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
43848b8605Smrg   0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
44848b8605Smrg   0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
45848b8605Smrg   0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
46848b8605Smrg   0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
47848b8605Smrg   0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
48848b8605Smrg   0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
49848b8605Smrg   0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
50848b8605Smrg   0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
51848b8605Smrg   0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
52848b8605Smrg   0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
53848b8605Smrg   0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
54848b8605Smrg   0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
55848b8605Smrg   0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
56848b8605Smrg   0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
57848b8605Smrg   0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
58848b8605Smrg   0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
59848b8605Smrg   0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
60848b8605Smrg   0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
61848b8605Smrg   0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
62848b8605Smrg   0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
63848b8605Smrg   0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
64848b8605Smrg   0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
65848b8605Smrg   0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
66848b8605Smrg};
67848b8605Smrg
68848b8605Smrgstatic const GLubyte LowBitsMask[9] = {
69848b8605Smrg   0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff,
70848b8605Smrg};
71848b8605Smrg
72848b8605Smrgstatic const GLubyte HighBitsMask[9] = {
73848b8605Smrg   0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff,
74848b8605Smrg};
75848b8605Smrg
76848b8605Smrg
77848b8605Smrg/*
78848b8605Smrg** Copy bitmap data from clients packed memory applying unpacking modes as the
79848b8605Smrg** data is transfered into the destImage buffer.  Return in modes the
80848b8605Smrg** set of pixel modes that are to be done by the server.
81848b8605Smrg*/
82848b8605Smrgstatic void
83848b8605SmrgFillBitmap(struct glx_context * gc, GLint width, GLint height,
84848b8605Smrg           GLenum format, const GLvoid * userdata, GLubyte * destImage)
85848b8605Smrg{
86848b8605Smrg   const __GLXattribute *state = gc->client_state_private;
87848b8605Smrg   GLint rowLength = state->storeUnpack.rowLength;
88848b8605Smrg   GLint alignment = state->storeUnpack.alignment;
89848b8605Smrg   GLint skipPixels = state->storeUnpack.skipPixels;
90848b8605Smrg   GLint skipRows = state->storeUnpack.skipRows;
91848b8605Smrg   GLint lsbFirst = state->storeUnpack.lsbFirst;
92848b8605Smrg   GLint elementsLeft, bitOffset, currentByte, nextByte, highBitMask;
93848b8605Smrg   GLint lowBitMask, i;
94848b8605Smrg   GLint components, groupsPerRow, rowSize, padding, elementsPerRow;
95848b8605Smrg   const GLubyte *start, *iter;
96848b8605Smrg
97848b8605Smrg   if (rowLength > 0) {
98848b8605Smrg      groupsPerRow = rowLength;
99848b8605Smrg   }
100848b8605Smrg   else {
101848b8605Smrg      groupsPerRow = width;
102848b8605Smrg   }
103848b8605Smrg   components = __glElementsPerGroup(format, GL_BITMAP);
104848b8605Smrg   rowSize = (groupsPerRow * components + 7) >> 3;
105848b8605Smrg   padding = (rowSize % alignment);
106848b8605Smrg   if (padding) {
107848b8605Smrg      rowSize += alignment - padding;
108848b8605Smrg   }
109848b8605Smrg   start = ((const GLubyte *) userdata) + skipRows * rowSize +
110848b8605Smrg      ((skipPixels * components) >> 3);
111848b8605Smrg   bitOffset = (skipPixels * components) & 7;
112848b8605Smrg   highBitMask = LowBitsMask[8 - bitOffset];
113848b8605Smrg   lowBitMask = HighBitsMask[bitOffset];
114848b8605Smrg   elementsPerRow = width * components;
115848b8605Smrg   for (i = 0; i < height; i++) {
116848b8605Smrg      elementsLeft = elementsPerRow;
117848b8605Smrg      iter = start;
118848b8605Smrg      while (elementsLeft) {
119848b8605Smrg         /* First retrieve low bits from current byte */
120848b8605Smrg         if (lsbFirst) {
121848b8605Smrg            currentByte = MsbToLsbTable[iter[0]];
122848b8605Smrg         }
123848b8605Smrg         else {
124848b8605Smrg            currentByte = iter[0];
125848b8605Smrg         }
126848b8605Smrg         if (bitOffset) {
127848b8605Smrg            /* Need to read next byte to finish current byte */
128848b8605Smrg            if (elementsLeft > (8 - bitOffset)) {
129848b8605Smrg               if (lsbFirst) {
130848b8605Smrg                  nextByte = MsbToLsbTable[iter[1]];
131848b8605Smrg               }
132848b8605Smrg               else {
133848b8605Smrg                  nextByte = iter[1];
134848b8605Smrg               }
135848b8605Smrg               currentByte =
136848b8605Smrg                  ((currentByte & highBitMask) << bitOffset) |
137848b8605Smrg                  ((nextByte & lowBitMask) >> (8 - bitOffset));
138848b8605Smrg            }
139848b8605Smrg            else {
140848b8605Smrg               currentByte = ((currentByte & highBitMask) << bitOffset);
141848b8605Smrg            }
142848b8605Smrg         }
143848b8605Smrg         if (elementsLeft >= 8) {
144848b8605Smrg            *destImage = currentByte;
145848b8605Smrg            elementsLeft -= 8;
146848b8605Smrg         }
147848b8605Smrg         else {
148848b8605Smrg            *destImage = currentByte & HighBitsMask[elementsLeft];
149848b8605Smrg            elementsLeft = 0;
150848b8605Smrg         }
151848b8605Smrg         destImage++;
152848b8605Smrg         iter++;
153848b8605Smrg      }
154848b8605Smrg      start += rowSize;
155848b8605Smrg   }
156848b8605Smrg}
157848b8605Smrg
158848b8605Smrg/*
159848b8605Smrg** Extract array from user's data applying all pixel store modes.
160848b8605Smrg** The internal packed array format used has LSB_FIRST = FALSE and
161848b8605Smrg** ALIGNMENT = 1.
162848b8605Smrg*/
163848b8605Smrgvoid
164848b8605Smrg__glFillImage(struct glx_context * gc, GLint dim, GLint width, GLint height,
165848b8605Smrg              GLint depth, GLenum format, GLenum type,
166848b8605Smrg              const GLvoid * userdata, GLubyte * newimage, GLubyte * modes)
167848b8605Smrg{
168848b8605Smrg   const __GLXattribute *state = gc->client_state_private;
169848b8605Smrg   GLint rowLength = state->storeUnpack.rowLength;
170848b8605Smrg   GLint imageHeight = state->storeUnpack.imageHeight;
171848b8605Smrg   GLint alignment = state->storeUnpack.alignment;
172848b8605Smrg   GLint skipPixels = state->storeUnpack.skipPixels;
173848b8605Smrg   GLint skipRows = state->storeUnpack.skipRows;
174848b8605Smrg   GLint skipImages = state->storeUnpack.skipImages;
175848b8605Smrg   GLint swapBytes = state->storeUnpack.swapEndian;
176848b8605Smrg   GLint components, elementSize, rowSize, padding, groupsPerRow, groupSize;
177848b8605Smrg   GLint elementsPerRow, imageSize, rowsPerImage, h, i, j, k;
178848b8605Smrg   const GLubyte *start, *iter, *itera, *iterb, *iterc;
179848b8605Smrg   GLubyte *iter2;
180848b8605Smrg
181848b8605Smrg   if (type == GL_BITMAP) {
182848b8605Smrg      FillBitmap(gc, width, height, format, userdata, newimage);
183848b8605Smrg   }
184848b8605Smrg   else {
185848b8605Smrg      components = __glElementsPerGroup(format, type);
186848b8605Smrg      if (rowLength > 0) {
187848b8605Smrg         groupsPerRow = rowLength;
188848b8605Smrg      }
189848b8605Smrg      else {
190848b8605Smrg         groupsPerRow = width;
191848b8605Smrg      }
192848b8605Smrg      if (imageHeight > 0) {
193848b8605Smrg         rowsPerImage = imageHeight;
194848b8605Smrg      }
195848b8605Smrg      else {
196848b8605Smrg         rowsPerImage = height;
197848b8605Smrg      }
198848b8605Smrg
199848b8605Smrg      elementSize = __glBytesPerElement(type);
200848b8605Smrg      groupSize = elementSize * components;
201848b8605Smrg      if (elementSize == 1)
202848b8605Smrg         swapBytes = 0;
203848b8605Smrg
204848b8605Smrg      rowSize = groupsPerRow * groupSize;
205848b8605Smrg      padding = (rowSize % alignment);
206848b8605Smrg      if (padding) {
207848b8605Smrg         rowSize += alignment - padding;
208848b8605Smrg      }
209848b8605Smrg      imageSize = rowSize * rowsPerImage;
210848b8605Smrg      start = ((const GLubyte *) userdata) + skipImages * imageSize +
211848b8605Smrg         skipRows * rowSize + skipPixels * groupSize;
212848b8605Smrg      iter2 = newimage;
213848b8605Smrg      elementsPerRow = width * components;
214848b8605Smrg
215848b8605Smrg      if (swapBytes) {
216848b8605Smrg         itera = start;
217848b8605Smrg         for (h = 0; h < depth; h++) {
218848b8605Smrg            iterb = itera;
219848b8605Smrg            for (i = 0; i < height; i++) {
220848b8605Smrg               iterc = iterb;
221848b8605Smrg               for (j = 0; j < elementsPerRow; j++) {
222848b8605Smrg                  for (k = 1; k <= elementSize; k++) {
223848b8605Smrg                     iter2[k - 1] = iterc[elementSize - k];
224848b8605Smrg                  }
225848b8605Smrg                  iter2 += elementSize;
226848b8605Smrg                  iterc += elementSize;
227848b8605Smrg               }
228848b8605Smrg               iterb += rowSize;
229848b8605Smrg            }
230848b8605Smrg            itera += imageSize;
231848b8605Smrg         }
232848b8605Smrg      }
233848b8605Smrg      else {
234848b8605Smrg         itera = start;
235848b8605Smrg         for (h = 0; h < depth; h++) {
236848b8605Smrg            if (rowSize == elementsPerRow * elementSize) {
237848b8605Smrg               /* Ha!  This is mondo easy! */
238848b8605Smrg               __GLX_MEM_COPY(iter2, itera,
239848b8605Smrg                              elementsPerRow * elementSize * height);
240848b8605Smrg               iter2 += elementsPerRow * elementSize * height;
241848b8605Smrg            }
242848b8605Smrg            else {
243848b8605Smrg               iter = itera;
244848b8605Smrg               for (i = 0; i < height; i++) {
245848b8605Smrg                  __GLX_MEM_COPY(iter2, iter, elementsPerRow * elementSize);
246848b8605Smrg                  iter2 += elementsPerRow * elementSize;
247848b8605Smrg                  iter += rowSize;
248848b8605Smrg               }
249848b8605Smrg            }
250848b8605Smrg            itera += imageSize;
251848b8605Smrg         }
252848b8605Smrg      }
253848b8605Smrg   }
254848b8605Smrg
255848b8605Smrg   /* Setup store modes that describe what we just did */
256848b8605Smrg   if (modes) {
257848b8605Smrg      if (dim < 3) {
258848b8605Smrg         (void) memcpy(modes, __glXDefaultPixelStore + 4, 20);
259848b8605Smrg      }
260848b8605Smrg      else {
261848b8605Smrg         (void) memcpy(modes, __glXDefaultPixelStore + 0, 36);
262848b8605Smrg      }
263848b8605Smrg   }
264848b8605Smrg}
265848b8605Smrg
266848b8605Smrg/*
267848b8605Smrg** Empty a bitmap in LSB_FIRST=GL_FALSE and ALIGNMENT=4 format packing it
268848b8605Smrg** into the clients memory using the pixel store PACK modes.
269848b8605Smrg*/
270848b8605Smrgstatic void
271848b8605SmrgEmptyBitmap(struct glx_context * gc, GLint width, GLint height,
272848b8605Smrg            GLenum format, const GLubyte * sourceImage, GLvoid * userdata)
273848b8605Smrg{
274848b8605Smrg   const __GLXattribute *state = gc->client_state_private;
275848b8605Smrg   GLint rowLength = state->storePack.rowLength;
276848b8605Smrg   GLint alignment = state->storePack.alignment;
277848b8605Smrg   GLint skipPixels = state->storePack.skipPixels;
278848b8605Smrg   GLint skipRows = state->storePack.skipRows;
279848b8605Smrg   GLint lsbFirst = state->storePack.lsbFirst;
280848b8605Smrg   GLint components, groupsPerRow, rowSize, padding, elementsPerRow;
281848b8605Smrg   GLint sourceRowSize, sourcePadding, sourceSkip;
282848b8605Smrg   GLubyte *start, *iter;
283848b8605Smrg   GLint elementsLeft, bitOffset, currentByte, highBitMask, lowBitMask;
284848b8605Smrg   GLint writeMask, i;
285848b8605Smrg   GLubyte writeByte;
286848b8605Smrg
287848b8605Smrg   components = __glElementsPerGroup(format, GL_BITMAP);
288848b8605Smrg   if (rowLength > 0) {
289848b8605Smrg      groupsPerRow = rowLength;
290848b8605Smrg   }
291848b8605Smrg   else {
292848b8605Smrg      groupsPerRow = width;
293848b8605Smrg   }
294848b8605Smrg
295848b8605Smrg   rowSize = (groupsPerRow * components + 7) >> 3;
296848b8605Smrg   padding = (rowSize % alignment);
297848b8605Smrg   if (padding) {
298848b8605Smrg      rowSize += alignment - padding;
299848b8605Smrg   }
300848b8605Smrg   sourceRowSize = (width * components + 7) >> 3;
301848b8605Smrg   sourcePadding = (sourceRowSize % 4);
302848b8605Smrg   if (sourcePadding) {
303848b8605Smrg      sourceSkip = 4 - sourcePadding;
304848b8605Smrg   }
305848b8605Smrg   else {
306848b8605Smrg      sourceSkip = 0;
307848b8605Smrg   }
308848b8605Smrg   start = ((GLubyte *) userdata) + skipRows * rowSize +
309848b8605Smrg      ((skipPixels * components) >> 3);
310848b8605Smrg   bitOffset = (skipPixels * components) & 7;
311848b8605Smrg   highBitMask = LowBitsMask[8 - bitOffset];
312848b8605Smrg   lowBitMask = HighBitsMask[bitOffset];
313848b8605Smrg   elementsPerRow = width * components;
314848b8605Smrg   for (i = 0; i < height; i++) {
315848b8605Smrg      elementsLeft = elementsPerRow;
316848b8605Smrg      iter = start;
317848b8605Smrg      writeMask = highBitMask;
318848b8605Smrg      writeByte = 0;
319848b8605Smrg      while (elementsLeft) {
320848b8605Smrg         /* Set up writeMask (to write to current byte) */
321848b8605Smrg         if (elementsLeft + bitOffset < 8) {
322848b8605Smrg            /* Need to trim writeMask */
323848b8605Smrg            writeMask &= HighBitsMask[bitOffset + elementsLeft];
324848b8605Smrg         }
325848b8605Smrg
326848b8605Smrg         if (lsbFirst) {
327848b8605Smrg            currentByte = MsbToLsbTable[iter[0]];
328848b8605Smrg         }
329848b8605Smrg         else {
330848b8605Smrg            currentByte = iter[0];
331848b8605Smrg         }
332848b8605Smrg
333848b8605Smrg         if (bitOffset) {
334848b8605Smrg            writeByte |= (sourceImage[0] >> bitOffset);
335848b8605Smrg            currentByte = (currentByte & ~writeMask) |
336848b8605Smrg               (writeByte & writeMask);
337848b8605Smrg            writeByte = (sourceImage[0] << (8 - bitOffset));
338848b8605Smrg         }
339848b8605Smrg         else {
340848b8605Smrg            currentByte = (currentByte & ~writeMask) |
341848b8605Smrg               (sourceImage[0] & writeMask);
342848b8605Smrg         }
343848b8605Smrg
344848b8605Smrg         if (lsbFirst) {
345848b8605Smrg            iter[0] = MsbToLsbTable[currentByte];
346848b8605Smrg         }
347848b8605Smrg         else {
348848b8605Smrg            iter[0] = currentByte;
349848b8605Smrg         }
350848b8605Smrg
351848b8605Smrg         if (elementsLeft >= 8) {
352848b8605Smrg            elementsLeft -= 8;
353848b8605Smrg         }
354848b8605Smrg         else {
355848b8605Smrg            elementsLeft = 0;
356848b8605Smrg         }
357848b8605Smrg         sourceImage++;
358848b8605Smrg         iter++;
359848b8605Smrg         writeMask = 0xff;
360848b8605Smrg      }
361848b8605Smrg      if (writeByte) {
362848b8605Smrg         /* Some data left over that still needs writing */
363848b8605Smrg         writeMask &= lowBitMask;
364848b8605Smrg         if (lsbFirst) {
365848b8605Smrg            currentByte = MsbToLsbTable[iter[0]];
366848b8605Smrg         }
367848b8605Smrg         else {
368848b8605Smrg            currentByte = iter[0];
369848b8605Smrg         }
370848b8605Smrg         currentByte = (currentByte & ~writeMask) | (writeByte & writeMask);
371848b8605Smrg         if (lsbFirst) {
372848b8605Smrg            iter[0] = MsbToLsbTable[currentByte];
373848b8605Smrg         }
374848b8605Smrg         else {
375848b8605Smrg            iter[0] = currentByte;
376848b8605Smrg         }
377848b8605Smrg      }
378848b8605Smrg      start += rowSize;
379848b8605Smrg      sourceImage += sourceSkip;
380848b8605Smrg   }
381848b8605Smrg}
382848b8605Smrg
383848b8605Smrg/*
384848b8605Smrg** Insert array into user's data applying all pixel store modes.
385848b8605Smrg** The packed array format from the server is LSB_FIRST = FALSE,
386848b8605Smrg** SWAP_BYTES = the current pixel storage pack mode, and ALIGNMENT = 4.
387848b8605Smrg** Named __glEmptyImage() because it is the opposite of __glFillImage().
388848b8605Smrg*/
389848b8605Smrg/* ARGSUSED */
390848b8605Smrgvoid
391848b8605Smrg__glEmptyImage(struct glx_context * gc, GLint dim, GLint width, GLint height,
392848b8605Smrg               GLint depth, GLenum format, GLenum type,
393848b8605Smrg               const GLubyte * sourceImage, GLvoid * userdata)
394848b8605Smrg{
395848b8605Smrg   const __GLXattribute *state = gc->client_state_private;
396848b8605Smrg   GLint rowLength = state->storePack.rowLength;
397848b8605Smrg   GLint imageHeight = state->storePack.imageHeight;
398848b8605Smrg   GLint alignment = state->storePack.alignment;
399848b8605Smrg   GLint skipPixels = state->storePack.skipPixels;
400848b8605Smrg   GLint skipRows = state->storePack.skipRows;
401848b8605Smrg   GLint skipImages = state->storePack.skipImages;
402848b8605Smrg   GLint components, elementSize, rowSize, padding, groupsPerRow, groupSize;
403848b8605Smrg   GLint elementsPerRow, sourceRowSize, sourcePadding, h, i;
404848b8605Smrg   GLint imageSize, rowsPerImage;
405848b8605Smrg   GLubyte *start, *iter, *itera;
406848b8605Smrg
407848b8605Smrg   if (type == GL_BITMAP) {
408848b8605Smrg      EmptyBitmap(gc, width, height, format, sourceImage, userdata);
409848b8605Smrg   }
410848b8605Smrg   else {
411848b8605Smrg      components = __glElementsPerGroup(format, type);
412848b8605Smrg      if (rowLength > 0) {
413848b8605Smrg         groupsPerRow = rowLength;
414848b8605Smrg      }
415848b8605Smrg      else {
416848b8605Smrg         groupsPerRow = width;
417848b8605Smrg      }
418848b8605Smrg      if (imageHeight > 0) {
419848b8605Smrg         rowsPerImage = imageHeight;
420848b8605Smrg      }
421848b8605Smrg      else {
422848b8605Smrg         rowsPerImage = height;
423848b8605Smrg      }
424848b8605Smrg      elementSize = __glBytesPerElement(type);
425848b8605Smrg      groupSize = elementSize * components;
426848b8605Smrg      rowSize = groupsPerRow * groupSize;
427848b8605Smrg      padding = (rowSize % alignment);
428848b8605Smrg      if (padding) {
429848b8605Smrg         rowSize += alignment - padding;
430848b8605Smrg      }
431848b8605Smrg      sourceRowSize = width * groupSize;
432848b8605Smrg      sourcePadding = (sourceRowSize % 4);
433848b8605Smrg      if (sourcePadding) {
434848b8605Smrg         sourceRowSize += 4 - sourcePadding;
435848b8605Smrg      }
436848b8605Smrg      imageSize = sourceRowSize * rowsPerImage;
437848b8605Smrg      start = ((GLubyte *) userdata) + skipImages * imageSize +
438848b8605Smrg         skipRows * rowSize + skipPixels * groupSize;
439848b8605Smrg      elementsPerRow = width * components;
440848b8605Smrg
441848b8605Smrg      itera = start;
442848b8605Smrg      for (h = 0; h < depth; h++) {
443848b8605Smrg         if ((rowSize == sourceRowSize) && (sourcePadding == 0)) {
444848b8605Smrg            /* Ha!  This is mondo easy! */
445848b8605Smrg            __GLX_MEM_COPY(itera, sourceImage,
446848b8605Smrg                           elementsPerRow * elementSize * height);
447848b8605Smrg            sourceImage += elementsPerRow * elementSize * height;
448848b8605Smrg         }
449848b8605Smrg         else {
450848b8605Smrg            iter = itera;
451848b8605Smrg            for (i = 0; i < height; i++) {
452848b8605Smrg               __GLX_MEM_COPY(iter, sourceImage,
453848b8605Smrg                              elementsPerRow * elementSize);
454848b8605Smrg               sourceImage += sourceRowSize;
455848b8605Smrg               iter += rowSize;
456848b8605Smrg            }
457848b8605Smrg         }
458848b8605Smrg         itera += imageSize;
459848b8605Smrg      }
460848b8605Smrg   }
461848b8605Smrg}
462