2 * Copyright © 2004 David Reveman
4 * Permission to use, copy, modify, distribute, and sell this software
5 * and its documentation for any purpose is hereby granted without
6 * fee, provided that the above copyright notice appear in all copies
7 * and that both that copyright notice and this permission notice
8 * appear in supporting documentation, and that the name of
9 * David Reveman not be used in advertising or publicity pertaining to
10 * distribution of the software without specific, written prior permission.
11 * David Reveman makes no representations about the suitability of this
12 * software for any purpose. It is provided "as is" without express or
15 * DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
17 * NO EVENT SHALL DAVID REVEMAN BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
19 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
20 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
21 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Author: David Reveman <davidr@novell.com>
27 #include <X11/fonts/fontstruct.h>
28 #include "dixfontstr.h"
30 xglDataTypeInfoRec xglGeometryDataTypes
[2] = {
31 { GLITZ_DATA_TYPE_SHORT
, sizeof (glitz_short_t
) },
32 { GLITZ_DATA_TYPE_FLOAT
, sizeof (glitz_float_t
) }
35 glitz_buffer_hint_t usageTypes
[] = {
36 GLITZ_BUFFER_HINT_STREAM_DRAW
,
37 GLITZ_BUFFER_HINT_STATIC_DRAW
,
38 GLITZ_BUFFER_HINT_DYNAMIC_DRAW
42 xglGeometryResize (ScreenPtr pScreen
,
43 xglGeometryPtr pGeometry
,
46 XGL_SCREEN_PRIV (pScreen
);
48 if (size
== pGeometry
->size
)
51 if (pGeometry
->broken
)
54 if (pGeometry
->usage
== GEOMETRY_USAGE_SYSMEM
)
56 pGeometry
->data
= xrealloc (pGeometry
->data
, size
);
58 if (pGeometry
->buffer
)
59 glitz_buffer_destroy (pGeometry
->buffer
);
61 pGeometry
->buffer
= NULL
;
65 pGeometry
->buffer
= glitz_buffer_create_for_data (pGeometry
->data
);
66 if (!pGeometry
->buffer
)
68 pGeometry
->broken
= TRUE
;
74 pGeometry
->broken
= TRUE
;
80 glitz_buffer_t
*newBuffer
;
85 glitz_vertex_buffer_create (pScreenPriv
->drawable
, NULL
, size
,
86 usageTypes
[pGeometry
->usage
]);
89 pGeometry
->broken
= TRUE
;
95 if (pGeometry
->buffer
&& newBuffer
)
97 void *oldData
, *newData
;
99 oldData
= glitz_buffer_map (pGeometry
->buffer
,
100 GLITZ_BUFFER_ACCESS_READ_ONLY
);
101 newData
= glitz_buffer_map (newBuffer
,
102 GLITZ_BUFFER_ACCESS_WRITE_ONLY
);
104 if (oldData
&& newData
)
105 memcpy (newData
, oldData
, MIN (size
, pGeometry
->size
));
107 glitz_buffer_unmap (pGeometry
->buffer
);
108 glitz_buffer_unmap (newBuffer
);
110 glitz_buffer_destroy (pGeometry
->buffer
);
112 pGeometry
->buffer
= newBuffer
;
115 pGeometry
->size
= size
;
117 if (pGeometry
->endOffset
> size
)
118 pGeometry
->endOffset
= size
;
121 #define MAP_GEOMETRY(pScreen, pGeometry, offset, units, ptr, _size) \
122 if ((pGeometry)->broken) \
124 (_size) = (units) * xglGeometryDataTypes[(pGeometry)->dataType].size; \
125 if (((pGeometry)->size - (offset)) < (_size)) \
127 xglGeometryResize (pScreen, pGeometry, \
128 (pGeometry)->endOffset + (_size) + 500); \
129 if ((pGeometry)->broken) \
132 (ptr) = glitz_buffer_map ((pGeometry)->buffer, \
133 GLITZ_BUFFER_ACCESS_WRITE_ONLY); \
136 (pGeometry)->broken = TRUE; \
141 #define UNMAP_GEOMETRY(pGeometry, offset, _size) \
142 if (glitz_buffer_unmap ((pGeometry)->buffer)) \
144 (pGeometry)->broken = TRUE; \
147 if (((offset) + (_size)) > (pGeometry)->endOffset) \
149 (pGeometry)->endOffset = (offset) + (_size); \
150 (pGeometry)->count = (pGeometry)->endOffset / \
151 (2 * xglGeometryDataTypes[(pGeometry)->dataType].size); \
155 * Adds a number of boxes as GL_QUAD primitives
158 xglGeometryAddBox (ScreenPtr pScreen
,
159 xglGeometryPtr pGeometry
,
170 MAP_GEOMETRY (pScreen
, pGeometry
, offset
, nBox
* 8, ptr
, size
);
172 switch (pGeometry
->dataType
) {
173 case GEOMETRY_DATA_TYPE_SHORT
:
175 glitz_short_t
*data
= (glitz_short_t
*) ptr
;
179 *data
++ = (glitz_short_t
) pBox
->x1
;
180 *data
++ = (glitz_short_t
) pBox
->y1
;
181 *data
++ = (glitz_short_t
) pBox
->x2
;
182 *data
++ = (glitz_short_t
) pBox
->y1
;
183 *data
++ = (glitz_short_t
) pBox
->x2
;
184 *data
++ = (glitz_short_t
) pBox
->y2
;
185 *data
++ = (glitz_short_t
) pBox
->x1
;
186 *data
++ = (glitz_short_t
) pBox
->y2
;
191 case GEOMETRY_DATA_TYPE_FLOAT
:
193 glitz_float_t
*data
= (glitz_float_t
*) ptr
;
197 *data
++ = (glitz_float_t
) pBox
->x1
;
198 *data
++ = (glitz_float_t
) pBox
->y1
;
199 *data
++ = (glitz_float_t
) pBox
->x2
;
200 *data
++ = (glitz_float_t
) pBox
->y1
;
201 *data
++ = (glitz_float_t
) pBox
->x2
;
202 *data
++ = (glitz_float_t
) pBox
->y2
;
203 *data
++ = (glitz_float_t
) pBox
->x1
;
204 *data
++ = (glitz_float_t
) pBox
->y2
;
211 UNMAP_GEOMETRY (pGeometry
, offset
, size
);
215 * Adds a number of spans as GL_LINE primitives
218 xglGeometryAddSpan (ScreenPtr pScreen
,
219 xglGeometryPtr pGeometry
,
231 MAP_GEOMETRY (pScreen
, pGeometry
, offset
, n
* 4, ptr
, size
);
233 switch (pGeometry
->dataType
) {
234 case GEOMETRY_DATA_TYPE_SHORT
:
236 glitz_short_t
*data
= (glitz_short_t
*) ptr
;
240 *data
++ = (glitz_short_t
) ppt
->x
;
241 *data
++ = (glitz_short_t
) ppt
->y
;
242 *data
++ = (glitz_short_t
) (ppt
->x
+ *pwidth
);
243 *data
++ = (glitz_short_t
) ppt
->y
;
249 case GEOMETRY_DATA_TYPE_FLOAT
:
251 glitz_float_t
*data
= (glitz_float_t
*) ptr
;
255 *data
++ = (glitz_float_t
) ppt
->x
;
256 *data
++ = (glitz_float_t
) ppt
->y
;
257 *data
++ = (glitz_float_t
) (ppt
->x
+ *pwidth
);
258 *data
++ = (glitz_float_t
) ppt
->y
;
266 UNMAP_GEOMETRY (pGeometry
, offset
, size
);
270 * This macro is needed for end pixels to be rasterized correctly using
271 * OpenGL as OpenGL line segments are half-opened.
273 #define ADJUST_END_POINT(start, end, isPoint) \
274 (((end) > (start)) ? (end) + 1: \
275 ((end) < (start)) ? (end) - 1: \
276 (isPoint) ? (end) + 1: \
280 * Adds a number of connected lines as GL_LINE_STRIP primitives
283 xglGeometryAddLine (ScreenPtr pScreen
,
284 xglGeometryPtr pGeometry
,
298 MAP_GEOMETRY (pScreen
, pGeometry
, offset
, npt
* 2, ptr
, size
);
303 switch (pGeometry
->dataType
) {
304 case GEOMETRY_DATA_TYPE_SHORT
:
306 glitz_short_t
*data
= (glitz_short_t
*) ptr
;
310 if (mode
== CoordModePrevious
)
323 *data
++ = (glitz_short_t
) pt
.x
;
324 *data
++ = (glitz_short_t
) pt
.y
;
329 *data
++ = (glitz_short_t
)
330 ADJUST_END_POINT (ppt
->x
, pt
.x
, ppt
->y
== pt
.y
);
331 *data
++ = (glitz_short_t
) ADJUST_END_POINT (ppt
->y
, pt
.y
, 0);
337 case GEOMETRY_DATA_TYPE_FLOAT
:
339 glitz_float_t
*data
= (glitz_float_t
*) ptr
;
343 if (mode
== CoordModePrevious
)
356 *data
++ = (glitz_float_t
) pt
.x
;
357 *data
++ = (glitz_float_t
) pt
.y
;
362 *data
++ = (glitz_float_t
)
363 ADJUST_END_POINT (ppt
->x
, pt
.x
, ppt
->y
== pt
.y
);
364 *data
++ = (glitz_float_t
) ADJUST_END_POINT (ppt
->y
, pt
.y
, 0);
372 UNMAP_GEOMETRY (pGeometry
, offset
, size
);
376 * Adds a number of line segments as GL_LINE primitives
379 xglGeometryAddSegment (ScreenPtr pScreen
,
380 xglGeometryPtr pGeometry
,
391 MAP_GEOMETRY (pScreen
, pGeometry
, offset
, nsegInit
* 4, ptr
, size
);
393 switch (pGeometry
->dataType
) {
394 case GEOMETRY_DATA_TYPE_SHORT
:
396 glitz_short_t
*data
= (glitz_short_t
*) ptr
;
400 *data
++ = (glitz_short_t
) pSegInit
->x1
;
401 *data
++ = (glitz_short_t
) pSegInit
->y1
;
402 *data
++ = (glitz_short_t
)
403 ADJUST_END_POINT (pSegInit
->x1
, pSegInit
->x2
,
404 pSegInit
->y1
== pSegInit
->y2
);
405 *data
++ = (glitz_short_t
)
406 ADJUST_END_POINT (pSegInit
->y1
, pSegInit
->y2
, 0);
411 case GEOMETRY_DATA_TYPE_FLOAT
:
413 glitz_float_t
*data
= (glitz_float_t
*) ptr
;
417 *data
++ = (glitz_float_t
) pSegInit
->x1
;
418 *data
++ = (glitz_float_t
) pSegInit
->y1
;
419 *data
++ = (glitz_float_t
)
420 ADJUST_END_POINT (pSegInit
->x1
, pSegInit
->x2
,
421 pSegInit
->y1
== pSegInit
->y2
);
422 *data
++ = (glitz_float_t
)
423 ADJUST_END_POINT (pSegInit
->y1
, pSegInit
->y2
, 0);
430 UNMAP_GEOMETRY (pGeometry
, offset
, size
);
434 xglGeometryForGlyph (ScreenPtr pScreen
,
435 xglGeometryPtr pGeometry
,
437 CharInfoPtr
*ppciInit
,
442 unsigned char *glyphbase
= (pointer
) ~0;
443 unsigned char *pglyph
;
447 int n
, lastX
= 0, lastY
= 0;
448 glitz_multi_array_t
*array
;
449 glitz_buffer_t
*buffer
;
456 pglyph
= FONTGLYPHBITS (pglyphBase
, *ppci
++);
457 if (pglyph
< glyphbase
)
461 buffer
= glitz_buffer_create_for_data (glyphbase
);
464 pGeometry
->broken
= TRUE
;
468 GEOMETRY_SET_BUFFER (pGeometry
, buffer
);
470 array
= glitz_multi_array_create (nGlyph
);
473 pGeometry
->broken
= TRUE
;
477 GEOMETRY_SET_MULTI_ARRAY (pGeometry
, array
);
483 pglyph
= FONTGLYPHBITS (pglyphBase
, pci
);
484 gWidth
= GLYPHWIDTHPIXELS (pci
);
485 gHeight
= GLYPHHEIGHTPIXELS (pci
);
487 if (gWidth
&& gHeight
)
489 gx
= x
+ pci
->metrics
.leftSideBearing
;
490 gy
= -pci
->metrics
.ascent
;
492 glitz_multi_array_add (array
,
493 (pglyph
- glyphbase
) * 8,
495 (gx
- lastX
) << 16, (gy
- lastY
) << 16);
499 x
+= pci
->metrics
.characterWidth
;
502 glitz_buffer_destroy (buffer
);
503 glitz_multi_array_destroy (array
);
506 #define FIXED_LINE_X_TO_FLOAT(line, v) \
508 ((line).p1.x + (xFixed_16_16) \
509 (((xFixed_32_32) ((v) - (line).p1.y) * \
510 ((line).p2.x - (line).p1.x)) / \
511 ((line).p2.y - (line).p1.y)))) / 65536)
513 #define FIXED_LINE_X_CEIL_TO_FLOAT(line, v) \
515 ((line).p1.x + (xFixed_16_16) \
516 (((((line).p2.y - (line).p1.y) - 1) + \
517 ((xFixed_32_32) ((v) - (line).p1.y) * \
518 ((line).p2.x - (line).p1.x))) / \
519 ((line).p2.y - (line).p1.y)))) / 65536)
522 * Adds a number of trapezoids as GL_QUAD primitives
525 xglGeometryAddTrapezoid (ScreenPtr pScreen
,
526 xglGeometryPtr pGeometry
,
537 MAP_GEOMETRY (pScreen
, pGeometry
, offset
, nTrap
* 8, ptr
, size
);
539 switch (pGeometry
->dataType
) {
540 case GEOMETRY_DATA_TYPE_SHORT
:
542 pGeometry
->broken
= TRUE
;
544 case GEOMETRY_DATA_TYPE_FLOAT
:
546 glitz_float_t
*data
= (glitz_float_t
*) ptr
;
547 glitz_float_t top
, bottom
;
551 top
= FIXED_TO_FLOAT (pTrap
->top
);
552 bottom
= FIXED_TO_FLOAT (pTrap
->bottom
);
554 *data
++ = FIXED_LINE_X_TO_FLOAT (pTrap
->left
, pTrap
->top
);
556 *data
++ = FIXED_LINE_X_CEIL_TO_FLOAT (pTrap
->right
, pTrap
->top
);
558 *data
++ = FIXED_LINE_X_CEIL_TO_FLOAT (pTrap
->right
, pTrap
->bottom
);
560 *data
++ = FIXED_LINE_X_TO_FLOAT (pTrap
->left
, pTrap
->bottom
);
568 UNMAP_GEOMETRY (pGeometry
, offset
, size
);
572 * Adds a number of traps as GL_QUAD primitives
575 xglGeometryAddTrap (ScreenPtr pScreen
,
576 xglGeometryPtr pGeometry
,
587 MAP_GEOMETRY (pScreen
, pGeometry
, offset
, nTrap
* 8, ptr
, size
);
589 switch (pGeometry
->dataType
) {
590 case GEOMETRY_DATA_TYPE_SHORT
:
592 pGeometry
->broken
= TRUE
;
594 case GEOMETRY_DATA_TYPE_FLOAT
:
596 glitz_float_t
*data
= (glitz_float_t
*) ptr
;
597 glitz_float_t top
, bottom
;
601 top
= FIXED_TO_FLOAT (pTrap
->top
.y
);
602 bottom
= FIXED_TO_FLOAT (pTrap
->bot
.y
);
604 *data
++ = FIXED_TO_FLOAT (pTrap
->top
.l
);
606 *data
++ = FIXED_TO_FLOAT (pTrap
->top
.r
);
608 *data
++ = FIXED_TO_FLOAT (pTrap
->bot
.r
);
610 *data
++ = FIXED_TO_FLOAT (pTrap
->bot
.l
);
618 UNMAP_GEOMETRY (pGeometry
, offset
, size
);
621 /* XXX: scratch geometry size never shrinks, it just gets larger when
622 required. this is not acceptable. */
624 xglGetScratchGeometryWithSize (ScreenPtr pScreen
,
627 xglGeometryPtr pGeometry
;
629 XGL_SCREEN_PRIV (pScreen
);
631 pGeometry
= &pScreenPriv
->scratchGeometry
;
633 if (pGeometry
->broken
|| pGeometry
->size
< size
)
635 GEOMETRY_UNINIT (pGeometry
);
636 GEOMETRY_INIT (pScreen
, pGeometry
, pGeometry
->type
,
637 pScreenPriv
->geometryUsage
, size
);
641 if (pGeometry
->array
)
643 glitz_multi_array_destroy (pGeometry
->array
);
644 pGeometry
->array
= NULL
;
646 pGeometry
->endOffset
= 0;
649 pGeometry
->first
= 0;
650 pGeometry
->count
= 0;
651 pGeometry
->width
= 2;
658 xglGetScratchVertexGeometryWithType (ScreenPtr pScreen
,
662 xglGeometryPtr pGeometry
;
665 stride
= 2 * xglGeometryDataTypes
[type
].size
;
667 pGeometry
= xglGetScratchGeometryWithSize (pScreen
, count
* stride
);
669 pGeometry
->type
= GLITZ_GEOMETRY_TYPE_VERTEX
;
670 pGeometry
->dataType
= type
;
672 pGeometry
->f
.vertex
.primitive
= GLITZ_PRIMITIVE_QUADS
;
673 pGeometry
->f
.vertex
.type
= xglGeometryDataTypes
[type
].type
;
674 pGeometry
->f
.vertex
.bytes_per_vertex
= stride
;
675 pGeometry
->f
.vertex
.attributes
= 0;
681 xglGetScratchVertexGeometry (ScreenPtr pScreen
,
684 xglGeometryPtr pGeometry
;
687 XGL_SCREEN_PRIV (pScreen
);
689 type
= pScreenPriv
->geometryDataType
;
690 stride
= 2 * xglGeometryDataTypes
[type
].size
;
692 pGeometry
= xglGetScratchGeometryWithSize (pScreen
, count
* stride
);
694 pGeometry
->type
= GLITZ_GEOMETRY_TYPE_VERTEX
;
695 pGeometry
->dataType
= type
;
697 pGeometry
->f
.vertex
.primitive
= GLITZ_PRIMITIVE_QUADS
;
698 pGeometry
->f
.vertex
.type
= xglGeometryDataTypes
[type
].type
;
699 pGeometry
->f
.vertex
.bytes_per_vertex
= stride
;
700 pGeometry
->f
.vertex
.attributes
= 0;
706 xglSetGeometry (xglGeometryPtr pGeometry
,
707 glitz_surface_t
*surface
)
709 if (pGeometry
->broken
)
712 glitz_set_geometry (surface
, pGeometry
->type
, &pGeometry
->f
,
715 if (pGeometry
->array
)
716 glitz_set_multi_array (surface
, pGeometry
->array
,
717 pGeometry
->xOff
, pGeometry
->yOff
);
719 glitz_set_array (surface
,
720 pGeometry
->first
, pGeometry
->width
, pGeometry
->count
,
721 pGeometry
->xOff
, pGeometry
->yOff
);