/*
* gsub_lite.c
*
* Graphics Subroutines (Lite) for ARToolKit.
*
* Copyright (c) 2003-2006 Philip Lamb (PRL) phil@eden.net.nz. All rights reserved.
*
* Rev Date Who Changes
* 2.7.0 2003-08-13 PRL Complete rewrite to ARToolKit-2.65 gsub.c API.
* 2.7.1 2004-03-03 PRL Avoid defining BOOL if already defined
* 2.7.1 2004-03-03 PRL Don't enable lighting if it was not enabled.
* 2.7.2 2004-04-27 PRL Added headerdoc markup. See http://developer.apple.com/darwin/projects/headerdoc/
* 2.7.3 2004-07-02 PRL Much more object-orientated through use of ARGL_CONTEXT_SETTINGS type.
* 2.7.4 2004-07-14 PRL Added gluCheckExtension hack for GLU versions pre-1.3.
* 2.7.5 2004-07-15 PRL Added arglDispImageStateful(); removed extraneous glPixelStorei(GL_UNPACK_IMAGE_HEIGHT,...) calls.
* 2.7.6 2005-02-18 PRL Go back to using int rather than BOOL, to avoid conflict with Objective-C.
* 2.7.7 2005-07-26 PRL Added cleanup routines for texture stuff.
* 2.7.8 2005-07-29 PRL Added distortion compensation enabling/disabling.
* 2.7.9 2005-08-15 PRL Added complete support for runtime selection of pixel format and rectangle/power-of-2 textures.
* 2.8.0 2006-04-04 PRL Move pixel format constants into toolkit global namespace (in config.h).
* 2.8.1 2006-04-06 PRL Move arglDrawMode, arglTexmapMode, arglTexRectangle out of global variables.
* 2.8.2 2006-06-12 PRL More stringent runtime GL caps checking. Fix zoom for DRAWPIXELS mode.
*
*/
/*
*
* This file is part of ARToolKit.
*
* ARToolKit is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* ARToolKit is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ARToolKit; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
// ============================================================================
// Private includes.
// ============================================================================
#include <AR/gsub_lite.h>
#include <stdio.h> // fprintf(), stderr
#include <string.h> // strchr(), strstr(), strlen()
#ifndef __APPLE__
# include <GL/glu.h>
# ifdef GL_VERSION_1_2
# include <GL/glext.h>
# endif
#else
# include <OpenGL/glu.h>
# include <OpenGL/glext.h>
#endif
// ============================================================================
// Private types and defines.
// ============================================================================
#ifdef _MSC_VER
# pragma warning (disable:4068) // Disable MSVC warnings about unknown pragmas.
#endif
// Make sure that required OpenGL constant definitions are available at compile-time.
// N.B. These should not be used unless the renderer indicates (at run-time) that it supports them.
// Define constants for extensions which became core in OpenGL 1.2
#ifndef GL_VERSION_1_2
# if GL_EXT_bgra
# define GL_BGR GL_BGR_EXT
# define GL_BGRA GL_BGRA_EXT
# else
# define GL_BGR 0x80E0
# define GL_BGRA 0x80E1
# endif
# ifndef GL_APPLE_packed_pixels
# define GL_UNSIGNED_INT_8_8_8_8 0x8035
# define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
# endif
# if GL_SGIS_texture_edge_clamp
# define GL_CLAMP_TO_EDGE GL_CLAMP_TO_EDGE_SGIS
# else
# define GL_CLAMP_TO_EDGE 0x812F
# endif
#endif
// Define constants for extensions (not yet core).
#ifndef GL_APPLE_ycbcr_422
# define GL_YCBCR_422_APPLE 0x85B9
# define GL_UNSIGNED_SHORT_8_8_APPLE 0x85BA
# define GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB
#endif
#ifndef GL_EXT_abgr
# define GL_ABGR_EXT 0x8000
#endif
#if GL_NV_texture_rectangle
# define GL_TEXTURE_RECTANGLE GL_TEXTURE_RECTANGLE_NV
# define GL_PROXY_TEXTURE_RECTANGLE GL_PROXY_TEXTURE_RECTANGLE_NV
# define GL_MAX_RECTANGLE_TEXTURE_SIZE GL_MAX_RECTANGLE_TEXTURE_SIZE_NV
#elif GL_EXT_texture_rectangle
# define GL_TEXTURE_RECTANGLE GL_TEXTURE_RECTANGLE_EXT
# define GL_PROXY_TEXTURE_RECTANGLE GL_PROXY_TEXTURE_RECTANGLE_EXT
# define GL_MAX_RECTANGLE_TEXTURE_SIZE GL_MAX_RECTANGLE_TEXTURE_SIZE_EXT
#else
# define GL_TEXTURE_RECTANGLE 0x84F5
# define GL_PROXY_TEXTURE_RECTANGLE 0x84F7
# define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8
#endif
#ifndef GL_MESA_ycbcr_texture
# define GL_YCBCR_MESA 0x8757
# define GL_UNSIGNED_SHORT_8_8_MESA 0x85BA
# define GL_UNSIGNED_SHORT_8_8_REV_MESA 0x85BB
#endif
//#define ARGL_DEBUG
struct _ARGL_CONTEXT_SETTINGS
{
int texturePow2CapabilitiesChecked
;
GLuint texturePow2
;
GLuint listPow2
;
int initedPow2
;
int textureRectangleCapabilitiesChecked
;
GLuint textureRectangle
;
GLuint listRectangle
;
int initedRectangle
;
int initPlease
; // Set to TRUE to request re-init of texture etc.
int asInited_texmapScaleFactor
;
float asInited_zoom
;
int asInited_xsize
;
int asInited_ysize
;
GLsizei texturePow2SizeX
;
GLsizei texturePow2SizeY
;
GLenum texturePow2WrapMode
;
int disableDistortionCompensation
;
GLenum pixIntFormat
;
GLenum pixFormat
;
GLenum pixType
;
GLenum pixSize
;
int arglDrawMode
;
int arglTexmapMode
;
int arglTexRectangle
;
};
typedef struct _ARGL_CONTEXT_SETTINGS ARGL_CONTEXT_SETTINGS
;
// ============================================================================
// Public globals.
// ============================================================================
// It'd be nice if we could wrap these in accessor functions!
// These items relate to Apple's fast texture transfer support.
//#define ARGL_USE_TEXTURE_RANGE // Commented out due to conflicts with GL_APPLE_ycbcr_422 extension.
#if defined(__APPLE__) && defined(APPLE_TEXTURE_FAST_TRANSFER)
int arglAppleClientStorage
= TRUE
; // TRUE | FALSE .
# ifdef ARGL_USE_TEXTURE_RANGE
int arglAppleTextureRange
= TRUE
; // TRUE | FALSE .
GLuint arglAppleTextureRangeStorageHint
= GL_STORAGE_SHARED_APPLE
; // GL_STORAGE_PRIVATE_APPLE | GL_STORAGE_SHARED_APPLE | GL_STORAGE_CACHED_APPLE .
# else
int arglAppleTextureRange
= FALSE
; // TRUE | FALSE .
GLuint arglAppleTextureRangeStorageHint
= GL_STORAGE_PRIVATE_APPLE
; // GL_STORAGE_PRIVATE_APPLE | GL_STORAGE_SHARED_APPLE | GL_STORAGE_CACHED_APPLE .
# endif // ARGL_USE_TEXTURE_RANGE
#endif // __APPLE__ && APPLE_TEXTURE_FAST_TRANSFER
// ============================================================================
// Private globals.
// ============================================================================
#pragma mark -
// ============================================================================
// Private functions.
// ============================================================================
//
// Provide a gluCheckExtension() function, since some platforms don't have GLU version 1.3 or later.
//
GLboolean arglGluCheckExtension
(const GLubyte
* extName
, const GLubyte
*extString
)
{
const GLubyte
*start
;
GLubyte
*where
, *terminator
;
// Extension names should not have spaces.
where
= (GLubyte
*)strchr((const char *)extName
, ' ');
if (where
|| *extName
== '\0')
return GL_FALSE
;
// It takes a bit of care to be fool-proof about parsing the
// OpenGL extensions string. Don't be fooled by sub-strings, etc.
start
= extString
;
for (;;) {
where
= (GLubyte
*) strstr((const char *)start
, (const char *)extName
);
if (!where
)
break;
terminator
= where
+ strlen((const char *)extName
);
if (where
== start
|| *(where
- 1) == ' ')
if (*terminator
== ' ' || *terminator
== '\0')
return GL_TRUE
;
start
= terminator
;
}
return GL_FALSE
;
}
//
// Checks for the presence of an OpenGL capability by version or extension.
// Reports whether the current OpenGL driver's OpenGL implementation version
// meets or exceeds a minimum value passed in in minVersion (represented as a binary-coded
// decimal i.e. version 1.0 is represented as 0x0100). If minVersion is zero, the
// version test will always fail. Alternately, the test is satisfied if an OpenGL extension
// identifier passed in as a character string
// is non-NULL, and is found in the current driver's list of supported extensions.
// Returns: TRUE If either of the tests passes, or FALSE if both fail.
//
static int arglGLCapabilityCheck
(const unsigned short minVersion
, const unsigned char *extension
)
{
const GLubyte
* strRenderer
;
const GLubyte
* strVersion
;
const GLubyte
* strVendor
;
const GLubyte
* strExtensions
;
short j
, shiftVal
;
unsigned short version
= 0; // binary-coded decimal gl version (ie. 1.4 is 0x0140).
strRenderer
= glGetString
(GL_RENDERER
);
strVendor
= glGetString
(GL_VENDOR
);
strVersion
= glGetString
(GL_VERSION
);
j
= 0;
shiftVal
= 8;
// Construct BCD version.
while (((strVersion
[j
] <= '9') && (strVersion
[j
] >= '0')) || (strVersion
[j
] == '.')) { // Get only basic version info (until first non-digit or non-.)
if ((strVersion
[j
] <= '9') && (strVersion
[j
] >= '0')) {
version
+= (strVersion
[j
] - '0') << shiftVal
;
shiftVal
-= 4;
}
j
++;
}
strExtensions
= glGetString
(GL_EXTENSIONS
);
if (0 < minVersion
&& version
>= minVersion
) return (TRUE
);
if (extension
&& arglGluCheckExtension
(extension
, strExtensions
)) return (TRUE
);
return (FALSE
);
}
static int arglDispImageTexPow2CapabilitiesCheck
(const ARParam
*cparam
, ARGL_CONTEXT_SETTINGS_REF contextSettings
)
{
GLint format
;
GLint texture1SizeMax
;
glGetIntegerv
(GL_MAX_TEXTURE_SIZE
, &texture1SizeMax
);
if (cparam
->xsize
> texture1SizeMax
|| cparam
->ysize
> texture1SizeMax
) {
return (FALSE
);
}
// Work out how big textures needs to be.
contextSettings
->texturePow2SizeX
= contextSettings
->texturePow2SizeY
= 1;
while (contextSettings
->texturePow2SizeX
< cparam
->xsize
) {
contextSettings
->texturePow2SizeX
*= 2;
if (contextSettings
->texturePow2SizeX
> texture1SizeMax
) {
return (FALSE
); // Too big to handle.
}
}
while (contextSettings
->texturePow2SizeY
< cparam
->ysize
) {
contextSettings
->texturePow2SizeY
*= 2;
if (contextSettings
->texturePow2SizeY
> texture1SizeMax
) {
return (FALSE
); // Too big to handle.
}
}
// Now check that the renderer can accomodate a texture of this size.
#ifdef APPLE_TEXTURE_FAST_TRANSFER
// Can't use client storage or texture range.
# ifdef ARGL_USE_TEXTURE_RANGE
glTextureRangeAPPLE
(GL_TEXTURE_2D
, 0, NULL
);
glTexParameteri
(GL_TEXTURE_2D
, GL_TEXTURE_STORAGE_HINT_APPLE
, GL_STORAGE_PRIVATE_APPLE
);
# endif // ARGL_USE_TEXTURE_RANGE
glPixelStorei
(GL_UNPACK_CLIENT_STORAGE_APPLE
, FALSE
);
#endif // APPLE_TEXTURE_FAST_TRANSFER
glTexImage2D
(GL_PROXY_TEXTURE_2D
, 0, contextSettings
->pixIntFormat
, contextSettings
->texturePow2SizeX
, contextSettings
->texturePow2SizeY
, 0, contextSettings
->pixFormat
, contextSettings
->pixType
, NULL
);
glGetTexLevelParameteriv
(GL_PROXY_TEXTURE_2D
, 0, GL_TEXTURE_INTERNAL_FORMAT
, &format
);
if (!format
) {
return (FALSE
);
}
// Decide whether we can use GL_CLAMP_TO_EDGE.
if (arglGLCapabilityCheck
(0x0120, (unsigned char *)"GL_SGIS_texture_edge_clamp")) {
contextSettings
->texturePow2WrapMode
= GL_CLAMP_TO_EDGE
;
} else {
contextSettings
->texturePow2WrapMode
= GL_REPEAT
;
}
return (TRUE
);
}
static int arglCleanupTexPow2
(ARGL_CONTEXT_SETTINGS_REF contextSettings
)
{
if (!contextSettings
->initedPow2
) return (FALSE
);
glDeleteTextures
(1, &(contextSettings
->texturePow2
));
glDeleteLists
(contextSettings
->listPow2
, 1);
contextSettings
->texturePow2CapabilitiesChecked
= FALSE
;
contextSettings
->initedPow2
= FALSE
;
return (TRUE
);
}
//
// Blit an image to the screen using OpenGL power-of-two texturing.
//
static void arglDispImageTexPow2
(ARUint8
*image
, const ARParam
*cparam
, const float zoom
, ARGL_CONTEXT_SETTINGS_REF contextSettings
, const int texmapScaleFactor
)
{
float tsx
, tsy
, tex
, tey
;
float px
, py
, qx
, qy
;
double x1
, x2
, x3
, x4
, y1
, y2
, y3
, y4
;
float xx1
, xx2
, xx3
, xx4
, yy1
, yy2
, yy3
, yy4
;
int i
, j
;
if(!contextSettings
->initedPow2
|| contextSettings
->initPlease
) {
contextSettings
->initPlease
= FALSE
;
// Delete previous texture and list, unless this is our first time here.
if (contextSettings
->initedPow2
) arglCleanupTexPow2
(contextSettings
);
// If we have not done so, check texturing capabilities. If they have already been
// checked, and we got to here, then obviously the capabilities were insufficient,
// so just return without doing anything.
if (!contextSettings
->texturePow2CapabilitiesChecked
) {
contextSettings
->texturePow2CapabilitiesChecked
= TRUE
;
if (!arglDispImageTexPow2CapabilitiesCheck
(cparam
, contextSettings
)) {
printf("argl error: Your OpenGL implementation and/or hardware's texturing capabilities are insufficient.\n"); // Windows bug: when running multi-threaded, can't write to stderr!
return;
}
} else {
return;
}
// Set up the texture object.
glGenTextures
(1, &(contextSettings
->texturePow2
));
glBindTexture
(GL_TEXTURE_2D
, contextSettings
->texturePow2
);
glTexParameteri
(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
glTexParameteri
(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
glTexParameteri
(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, contextSettings
->texturePow2WrapMode
);
glTexParameteri
(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, contextSettings
->texturePow2WrapMode
);
#ifdef APPLE_TEXTURE_FAST_TRANSFER
# ifdef ARGL_USE_TEXTURE_RANGE
// Can't use client storage or texture range.
glTextureRangeAPPLE
(GL_TEXTURE_2D
, 0, NULL
);
glTexParameteri
(GL_TEXTURE_2D
, GL_TEXTURE_STORAGE_HINT_APPLE
, GL_STORAGE_PRIVATE_APPLE
);
# endif // ARGL_USE_TEXTURE_RANGE
glPixelStorei
(GL_UNPACK_CLIENT_STORAGE_APPLE
, FALSE
);
#endif // APPLE_TEXTURE_FAST_TRANSFER
// Request OpenGL allocate memory for a power-of-two texture of the appropriate size.
if (texmapScaleFactor
== 2) {
// If texmapScaleFactor is 2, pretend lines in the source image are
// twice as long as they are; glTexImage2D will read only the first
// half of each line, effectively discarding every second line in the source image.
glPixelStorei
(GL_UNPACK_ROW_LENGTH
, cparam
->xsize
*texmapScaleFactor
);
}
glPixelStorei
(GL_UNPACK_ALIGNMENT
, 1);
glTexImage2D
(GL_TEXTURE_2D
, 0, contextSettings
->pixIntFormat
, contextSettings
->texturePow2SizeX
, contextSettings
->texturePow2SizeY
/texmapScaleFactor
, 0, contextSettings
->pixFormat
, contextSettings
->pixType
, NULL
);
if (texmapScaleFactor
== 2) {
glPixelStorei
(GL_UNPACK_ROW_LENGTH
, 0);
}
// Set up the surface which we will texture upon.
contextSettings
->listPow2
= glGenLists
(1);
glNewList
(contextSettings
->listPow2
, GL_COMPILE
); // NB Texture not specified yet so don't execute.
glEnable
(GL_TEXTURE_2D
);
glMatrixMode
(GL_TEXTURE
);
glLoadIdentity
();
glMatrixMode
(GL_MODELVIEW
);
if (contextSettings
->disableDistortionCompensation
) {
glBegin
(GL_QUADS
);
glTexCoord2f
(0.0f, (float)cparam
->ysize
/(float)contextSettings
->texturePow2SizeY
);
glVertex2f
(0.0f, 0.0f);
glTexCoord2f
((float)cparam
->xsize
/(float)contextSettings
->texturePow2SizeX
, (float)cparam
->ysize
/(float)contextSettings
->texturePow2SizeY
);
glVertex2f
((float)cparam
->xsize
* zoom
, 0.0f);
glTexCoord2f
((float)cparam
->xsize
/(float)contextSettings
->texturePow2SizeX
, 0.0f);
glVertex2f
((float)cparam
->xsize
* zoom
, (float)cparam
->ysize
* zoom
);
glTexCoord2f
(0.0f, 0.0f);
glVertex2f
(0.0f, (float)cparam
->ysize
* zoom
);
glEnd
();
} else {
qy
= 0.0f;
tey
= 0.0f;
for(j
= 1; j
<= 20; j
++) { // Do 20 rows.
py
= qy
;
tsy
= tey
;
qy
= cparam
->ysize
* j
/ 20.0f;
tey
= qy
/ contextSettings
->texturePow2SizeY
;
qx
= 0.0f;
tex
= 0.0f;
for(i
= 1; i
<= 20; i
++) { // Draw 20 columns.
px
= qx
;
tsx
= tex
;
qx
= cparam
->xsize
* i
/ 20.0f;
tex
= qx
/ contextSettings
->texturePow2SizeX
;
arParamObserv2Ideal
(cparam
->dist_factor
, (double)px
, (double)py
, &x1
, &y1
);
arParamObserv2Ideal
(cparam
->dist_factor
, (double)qx
, (double)py
, &x2
, &y2
);
arParamObserv2Ideal
(cparam
->dist_factor
, (double)qx
, (double)qy
, &x3
, &y3
);
arParamObserv2Ideal
(cparam
->dist_factor
, (double)px
, (double)qy
, &x4
, &y4
);
xx1
= (float)x1
* zoom
;
yy1
= (cparam
->ysize
- (float)y1
) * zoom
;
xx2
= (float)x2
* zoom
;
yy2
= (cparam
->ysize
- (float)y2
) * zoom
;
xx3
= (float)x3
* zoom
;
yy3
= (cparam
->ysize
- (float)y3
) * zoom
;
xx4
= (float)x4
* zoom
;
yy4
= (cparam
->ysize
- (float)y4
) * zoom
;
glBegin
(GL_QUADS
);
glTexCoord2f
(tsx
, tsy
); glVertex2f
(xx1
, yy1
);
glTexCoord2f
(tex
, tsy
); glVertex2f
(xx2
, yy2
);
glTexCoord2f
(tex
, tey
); glVertex2f
(xx3
, yy3
);
glTexCoord2f
(tsx
, tey
); glVertex2f
(xx4
, yy4
);
glEnd
();
} // columns.
} // rows.
}
glDisable
(GL_TEXTURE_2D
);
glEndList
();
contextSettings
->asInited_ysize
= cparam
->ysize
;
contextSettings
->asInited_xsize
= cparam
->xsize
;
contextSettings
->asInited_zoom
= zoom
;
contextSettings
->asInited_texmapScaleFactor
= texmapScaleFactor
;
contextSettings
->initedPow2
= TRUE
;
}
glBindTexture
(GL_TEXTURE_2D
, contextSettings
->texturePow2
);
#ifdef APPLE_TEXTURE_FAST_TRANSFER
# ifdef ARGL_USE_TEXTURE_RANGE
// Can't use client storage or texture range.
glTextureRangeAPPLE
(GL_TEXTURE_2D
, 0, NULL
);
glTexParameteri
(GL_TEXTURE_2D
, GL_TEXTURE_STORAGE_HINT_APPLE
, GL_STORAGE_PRIVATE_APPLE
);
#endif // ARGL_USE_TEXTURE_RANGE
glPixelStorei
(GL_UNPACK_CLIENT_STORAGE_APPLE
, FALSE
);
#endif // APPLE_TEXTURE_FAST_TRANSFER
if (texmapScaleFactor
== 2) {
// If texmapScaleFactor is 2, pretend lines in the source image are
// twice as long as they are; glTexImage2D will read only the first
// half of each line, effectively discarding every second line in the source image.
glPixelStorei
(GL_UNPACK_ROW_LENGTH
, cparam
->xsize
*texmapScaleFactor
);
}
glPixelStorei
(GL_UNPACK_ALIGNMENT
, 1);
glTexSubImage2D
(GL_TEXTURE_2D
, 0, 0, 0, cparam
->xsize
, cparam
->ysize
/texmapScaleFactor
, contextSettings
->pixFormat
, contextSettings
->pixType
, image
);
glCallList
(contextSettings
->listPow2
);
if (texmapScaleFactor
== 2) {
glPixelStorei
(GL_UNPACK_ROW_LENGTH
, 0);
}
glBindTexture
(GL_TEXTURE_2D
, 0);
}
static int arglDispImageTexRectangleCapabilitiesCheck
(const ARParam
*cparam
, ARGL_CONTEXT_SETTINGS_REF contextSettings
)
{
GLint textureRectangleSizeMax
;
GLint format
;
if (!arglGLCapabilityCheck
(0, (unsigned char *)"GL_NV_texture_rectangle")) {
if (!arglGLCapabilityCheck
(0, (unsigned char *)"GL_EXT_texture_rectangle")) { // Alternate name.
return (FALSE
);
}
}
glGetIntegerv
(GL_MAX_RECTANGLE_TEXTURE_SIZE
, &textureRectangleSizeMax
);
if (cparam
->xsize
> textureRectangleSizeMax
|| cparam
->ysize
> textureRectangleSizeMax
) {
return (FALSE
);
}
// Now check that the renderer can accomodate a texture of this size.
glTexImage2D
(GL_PROXY_TEXTURE_RECTANGLE
, 0, contextSettings
->pixIntFormat
, cparam
->xsize
, cparam
->ysize
, 0, contextSettings
->pixFormat
, contextSettings
->pixType
, NULL
);
glGetTexLevelParameteriv
(GL_PROXY_TEXTURE_RECTANGLE
, 0, GL_TEXTURE_INTERNAL_FORMAT
, &format
);
if (!format
) {
return (FALSE
);
}
return (TRUE
);
}
static int arglCleanupTexRectangle
(ARGL_CONTEXT_SETTINGS_REF contextSettings
)
{
if (!contextSettings
->initedRectangle
) return (FALSE
);
glDeleteTextures
(1, &(contextSettings
->textureRectangle
));
glDeleteLists
(contextSettings
->listRectangle
, 1);
contextSettings
->textureRectangleCapabilitiesChecked
= FALSE
;
contextSettings
->initedRectangle
= FALSE
;
return (TRUE
);
}
//
// Blit an image to the screen using OpenGL rectangle texturing.
//
static void arglDispImageTexRectangle
(ARUint8
*image
, const ARParam
*cparam
, const float zoom
, ARGL_CONTEXT_SETTINGS_REF contextSettings
, const int texmapScaleFactor
)
{
float px
, py
, py_prev
;
double x1
, x2
, y1
, y2
;
float xx1
, xx2
, yy1
, yy2
;
int i
, j
;
if(!contextSettings
->initedRectangle
|| contextSettings
->initPlease
) {
contextSettings
->initPlease
= FALSE
;
// Delete previous texture and list, unless this is our first time here.
if (contextSettings
->initedRectangle
) arglCleanupTexRectangle
(contextSettings
);
// If we have not done so, check texturing capabilities. If they have already been
// checked, and we got to here, then obviously the capabilities were insufficient,
// so just return without doing anything.
if (!contextSettings
->textureRectangleCapabilitiesChecked
) {
contextSettings
->textureRectangleCapabilitiesChecked
= TRUE
;
if (!arglDispImageTexRectangleCapabilitiesCheck
(cparam
, contextSettings
)) {
printf("argl error: Your OpenGL implementation and/or hardware's texturing capabilities are insufficient to support rectangle textures.\n"); // Windows bug: when running multi-threaded, can't write to stderr!
// Fall back to power of 2 texturing.
contextSettings
->arglTexRectangle
= FALSE
;
arglDispImageTexPow2
(image
, cparam
, zoom
, contextSettings
, texmapScaleFactor
);
return;
}
} else {
return;
}
// Set up the rectangle texture object.
glGenTextures
(1, &(contextSettings
->textureRectangle
));
glBindTexture
(GL_TEXTURE_RECTANGLE
, contextSettings
->textureRectangle
);
glTexParameteri
(GL_TEXTURE_RECTANGLE
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
glTexParameteri
(GL_TEXTURE_RECTANGLE
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
glTexParameteri
(GL_TEXTURE_RECTANGLE
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
glTexParameteri
(GL_TEXTURE_RECTANGLE
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
#ifdef APPLE_TEXTURE_FAST_TRANSFER
# ifdef ARGL_USE_TEXTURE_RANGE
if (arglAppleTextureRange
) {
glTextureRangeAPPLE
(GL_TEXTURE_RECTANGLE
, cparam
->xsize
* cparam
->ysize
* contextSettings
->pixSize
, image
);
glTexParameteri
(GL_TEXTURE_RECTANGLE
, GL_TEXTURE_STORAGE_HINT_APPLE
, arglAppleTextureRangeStorageHint
);
} else {
glTextureRangeAPPLE
(GL_TEXTURE_RECTANGLE
, 0, NULL
);
glTexParameteri
(GL_TEXTURE_RECTANGLE
, GL_TEXTURE_STORAGE_HINT_APPLE
, GL_STORAGE_PRIVATE_APPLE
);
}
#endif // ARGL_USE_TEXTURE_RANGE
glPixelStorei
(GL_UNPACK_CLIENT_STORAGE_APPLE
, arglAppleClientStorage
);
#endif // APPLE_TEXTURE_FAST_TRANSFER
// Specify the texture to OpenGL.
if (texmapScaleFactor
== 2) {
// If texmapScaleFactor is 2, pretend lines in the source image are
// twice as long as they are; glTexImage2D will read only the first
// half of each line, effectively discarding every second line in the source image.
glPixelStorei
(GL_UNPACK_ROW_LENGTH
, cparam
->xsize
*texmapScaleFactor
);
}
glPixelStorei
(GL_UNPACK_ALIGNMENT
, 1); // Our image data is tightly packed.
glTexImage2D
(GL_TEXTURE_RECTANGLE
, 0, contextSettings
->pixIntFormat
, cparam
->xsize
, cparam
->ysize
/texmapScaleFactor
, 0, contextSettings
->pixFormat
, contextSettings
->pixType
, image
);
if (texmapScaleFactor
== 2) {
glPixelStorei
(GL_UNPACK_ROW_LENGTH
, 0);
}
// Set up the surface which we will texture upon.
contextSettings
->listRectangle
= glGenLists
(1);
glNewList
(contextSettings
->listRectangle
, GL_COMPILE
);
glEnable
(GL_TEXTURE_RECTANGLE
);
glMatrixMode
(GL_TEXTURE
);
glLoadIdentity
();
glMatrixMode
(GL_MODELVIEW
);
if (contextSettings
->disableDistortionCompensation
) {
glBegin
(GL_QUADS
);
glTexCoord2f
(0.0f, (float)(cparam
->ysize
/texmapScaleFactor
)); glVertex2f
(0.0f, 0.0f);
glTexCoord2f
((float)(cparam
->xsize
), (float)(cparam
->ysize
/texmapScaleFactor
)); glVertex2f
(cparam
->xsize
* zoom
, 0.0f);
glTexCoord2f
((float)(cparam
->xsize
), 0.0f); glVertex2f
(cparam
->xsize
* zoom
, cparam
->ysize
* zoom
);
glTexCoord2f
(0.0f, 0.0f); glVertex2f
(0.0f, cparam
->ysize
* zoom
);
glEnd
();
} else {
py_prev
= 0.0f;
for(j
= 1; j
<= 20; j
++) { // Do 20 rows.
py
= py_prev
;
py_prev
= cparam
->ysize
* j
/ 20.0f;
glBegin
(GL_QUAD_STRIP
);
for(i
= 0; i
<= 20; i
++) { // Draw 21 pairs of vertices per row to make 20 columns.
px
= cparam
->xsize
* i
/ 20.0f;
arParamObserv2Ideal
(cparam
->dist_factor
, (double)px
, (double)py
, &x1
, &y1
);
arParamObserv2Ideal
(cparam
->dist_factor
, (double)px
, (double)py_prev
, &x2
, &y2
);
xx1
= (float)x1
* zoom
;
yy1
= (cparam
->ysize
- (float)y1
) * zoom
;
xx2
= (float)x2
* zoom
;
yy2
= (cparam
->ysize
- (float)y2
) * zoom
;
glTexCoord2f
(px
, py
/texmapScaleFactor
); glVertex2f
(xx1
, yy1
);
glTexCoord2f
(px
, py_prev
/texmapScaleFactor
); glVertex2f
(xx2
, yy2
);
}
glEnd
();
}
}
glDisable
(GL_TEXTURE_RECTANGLE
);
glEndList
();
contextSettings
->asInited_ysize
= cparam
->ysize
;
contextSettings
->asInited_xsize
= cparam
->xsize
;
contextSettings
->asInited_zoom
= zoom
;
contextSettings
->asInited_texmapScaleFactor
= texmapScaleFactor
;
contextSettings
->initedRectangle
= TRUE
;
}
glBindTexture
(GL_TEXTURE_RECTANGLE
, contextSettings
->textureRectangle
);
#ifdef APPLE_TEXTURE_FAST_TRANSFER
# ifdef ARGL_USE_TEXTURE_RANGE
if (arglAppleTextureRange
) {
glTextureRangeAPPLE
(GL_TEXTURE_RECTANGLE
, cparam
->xsize
* cparam
->ysize
* contextSettings
->pixSize
, image
);
glTexParameteri
(GL_TEXTURE_RECTANGLE
, GL_TEXTURE_STORAGE_HINT_APPLE
, arglAppleTextureRangeStorageHint
);
} else {
glTextureRangeAPPLE
(GL_TEXTURE_RECTANGLE
, 0, NULL
);
glTexParameteri
(GL_TEXTURE_RECTANGLE
, GL_TEXTURE_STORAGE_HINT_APPLE
, GL_STORAGE_PRIVATE_APPLE
);
}
#endif // ARGL_USE_TEXTURE_RANGE
glPixelStorei
(GL_UNPACK_CLIENT_STORAGE_APPLE
, arglAppleClientStorage
);
#endif // APPLE_TEXTURE_FAST_TRANSFER
if (texmapScaleFactor
== 2) {
glPixelStorei
(GL_UNPACK_ROW_LENGTH
, cparam
->xsize
*texmapScaleFactor
);
}
glPixelStorei
(GL_UNPACK_ALIGNMENT
, 1);
glTexSubImage2D
(GL_TEXTURE_RECTANGLE
, 0, 0, 0, cparam
->xsize
, cparam
->ysize
/texmapScaleFactor
, contextSettings
->pixFormat
, contextSettings
->pixType
, image
);
glCallList
(contextSettings
->listRectangle
);
if (texmapScaleFactor
== 2) {
glPixelStorei
(GL_UNPACK_ROW_LENGTH
, 0);
}
glBindTexture
(GL_TEXTURE_RECTANGLE
, 0);
}
#pragma mark -
// ============================================================================
// Public functions.
// ============================================================================
ARGL_CONTEXT_SETTINGS_REF arglSetupForCurrentContext
(void)
{
ARGL_CONTEXT_SETTINGS_REF contextSettings
;
contextSettings
= (ARGL_CONTEXT_SETTINGS_REF
)calloc(1, sizeof(ARGL_CONTEXT_SETTINGS
));
// Use default pixel format handed to us by <AR/config.h>.
if (!arglPixelFormatSet
(contextSettings
, AR_DEFAULT_PIXEL_FORMAT
)) {
printf("Unknown default pixel format defined in config.h.\n"); // Windows bug: when running multi-threaded, can't write to stderr!
return (NULL
);
}
arglDrawModeSet
(contextSettings
, AR_DRAW_BY_TEXTURE_MAPPING
);
arglTexmapModeSet
(contextSettings
, AR_DRAW_TEXTURE_FULL_IMAGE
);
arglTexRectangleSet
(contextSettings
, TRUE
);
return (contextSettings
);
}
void arglCleanup
(ARGL_CONTEXT_SETTINGS_REF contextSettings
)
{
arglCleanupTexRectangle
(contextSettings
);
arglCleanupTexPow2
(contextSettings
);
free(contextSettings
);
}
//
// Convert a camera parameter structure into an OpenGL projection matrix.
//
void arglCameraFrustum
(const ARParam
*cparam
, const double focalmin
, const double focalmax
, GLdouble m_projection
[16])
{
double icpara
[3][4];
double trans
[3][4];
double p
[3][3], q
[4][4];
int width
, height
;
int i
, j
;
width
= cparam
->xsize
;
height
= cparam
->ysize
;
if (arParamDecompMat
(cparam
->mat
, icpara
, trans
) < 0) {
printf("arglCameraFrustum(): arParamDecompMat() indicated parameter error.\n"); // Windows bug: when running multi-threaded, can't write to stderr!
return;
}
for (i
= 0; i
< 4; i
++) {
icpara
[1][i
] = (height
- 1)*(icpara
[2][i
]) - icpara
[1][i
];
}
for(i
= 0; i
< 3; i
++) {
for(j
= 0; j
< 3; j
++) {
p
[i
][j
] = icpara
[i
][j
] / icpara
[2][2];
}
}
q
[0][0] = (2.0 * p
[0][0] / (width
- 1));
q
[0][1] = (2.0 * p
[0][1] / (width
- 1));
q
[0][2] = ((2.0 * p
[0][2] / (width
- 1)) - 1.0);
q
[0][3] = 0.0;
q
[1][0] = 0.0;
q
[1][1] = (2.0 * p
[1][1] / (height
- 1));
q
[1][2] = ((2.0 * p
[1][2] / (height
- 1)) - 1.0);
q
[1][3] = 0.0;
q
[2][0] = 0.0;
q
[2][1] = 0.0;
q
[2][2] = (focalmax
+ focalmin
)/(focalmax
- focalmin
);
q
[2][3] = -2.0 * focalmax
* focalmin
/ (focalmax
- focalmin
);
q
[3][0] = 0.0;
q
[3][1] = 0.0;
q
[3][2] = 1.0;
q
[3][3] = 0.0;
for (i
= 0; i
< 4; i
++) { // Row.
// First 3 columns of the current row.
for (j
= 0; j
< 3; j
++) { // Column.
m_projection
[i
+ j
*4] = q
[i
][0] * trans
[0][j
] +
q
[i
][1] * trans
[1][j
] +
q
[i
][2] * trans
[2][j
];
}
// Fourth column of the current row.
m_projection
[i
+ 3*4] = q
[i
][0] * trans
[0][3] +
q
[i
][1] * trans
[1][3] +
q
[i
][2] * trans
[2][3] +
q
[i
][3];
}
}
void arglCameraFrustumRH
(const ARParam
*cparam
, const double focalmin
, const double focalmax
, GLdouble m_projection
[16])
{
double icpara
[3][4];
double trans
[3][4];
double p
[3][3], q
[4][4];
int width
, height
;
int i
, j
;
width
= cparam
->xsize
;
height
= cparam
->ysize
;
if (arParamDecompMat
(cparam
->mat
, icpara
, trans
) < 0) {
printf("arglCameraFrustum(): arParamDecompMat() indicated parameter error.\n"); // Windows bug: when running multi-threaded, can't write to stderr!
return;
}
for (i
= 0; i
< 4; i
++) {
icpara
[1][i
] = (height
- 1)*(icpara
[2][i
]) - icpara
[1][i
];
}
for(i
= 0; i
< 3; i
++) {
for(j
= 0; j
< 3; j
++) {
p
[i
][j
] = icpara
[i
][j
] / icpara
[2][2];
}
}
q
[0][0] = (2.0 * p
[0][0] / (width
- 1));
q
[0][1] = (2.0 * p
[0][1] / (width
- 1));
q
[0][2] = -((2.0 * p
[0][2] / (width
- 1)) - 1.0);
q
[0][3] = 0.0;
q
[1][0] = 0.0;
q
[1][1] = -(2.0 * p
[1][1] / (height
- 1));
q
[1][2] = -((2.0 * p
[1][2] / (height
- 1)) - 1.0);
q
[1][3] = 0.0;
q
[2][0] = 0.0;
q
[2][1] = 0.0;
q
[2][2] = (focalmax
+ focalmin
)/(focalmin
- focalmax
);
q
[2][3] = 2.0 * focalmax
* focalmin
/ (focalmin
- focalmax
);
q
[3][0] = 0.0;
q
[3][1] = 0.0;
q
[3][2] = -1.0;
q
[3][3] = 0.0;
for (i
= 0; i
< 4; i
++) { // Row.
// First 3 columns of the current row.
for (j
= 0; j
< 3; j
++) { // Column.
m_projection
[i
+ j
*4] = q
[i
][0] * trans
[0][j
] +
q
[i
][1] * trans
[1][j
] +
q
[i
][2] * trans
[2][j
];
}
// Fourth column of the current row.
m_projection
[i
+ 3*4] = q
[i
][0] * trans
[0][3] +
q
[i
][1] * trans
[1][3] +
q
[i
][2] * trans
[2][3] +
q
[i
][3];
}
}
void arglCameraView
(const double para
[3][4], GLdouble m_modelview
[16], const double scale
)
{
m_modelview
[0 + 0*4] = para
[0][0]; // R1C1
m_modelview
[0 + 1*4] = para
[0][1]; // R1C2
m_modelview
[0 + 2*4] = para
[0][2];
m_modelview
[0 + 3*4] = para
[0][3];
m_modelview
[1 + 0*4] = para
[1][0]; // R2
m_modelview
[1 + 1*4] = para
[1][1];
m_modelview
[1 + 2*4] = para
[1][2];
m_modelview
[1 + 3*4] = para
[1][3];
m_modelview
[2 + 0*4] = para
[2][0]; // R3
m_modelview
[2 + 1*4] = para
[2][1];
m_modelview
[2 + 2*4] = para
[2][2];
m_modelview
[2 + 3*4] = para
[2][3];
m_modelview
[3 + 0*4] = 0.0;
m_modelview
[3 + 1*4] = 0.0;
m_modelview
[3 + 2*4] = 0.0;
m_modelview
[3 + 3*4] = 1.0;
if (scale
!= 0.0) {
m_modelview
[12] *= scale
;
m_modelview
[13] *= scale
;
m_modelview
[14] *= scale
;
}
}
void arglCameraViewRH
(const double para
[3][4], GLdouble m_modelview
[16], const double scale
)
{
m_modelview
[0 + 0*4] = para
[0][0]; // R1C1
m_modelview
[0 + 1*4] = para
[0][1]; // R1C2
m_modelview
[0 + 2*4] = para
[0][2];
m_modelview
[0 + 3*4] = para
[0][3];
m_modelview
[1 + 0*4] = -para
[1][0]; // R2
m_modelview
[1 + 1*4] = -para
[1][1];
m_modelview
[1 + 2*4] = -para
[1][2];
m_modelview
[1 + 3*4] = -para
[1][3];
m_modelview
[2 + 0*4] = -para
[2][0]; // R3
m_modelview
[2 + 1*4] = -para
[2][1];
m_modelview
[2 + 2*4] = -para
[2][2];
m_modelview
[2 + 3*4] = -para
[2][3];
m_modelview
[3 + 0*4] = 0.0;
m_modelview
[3 + 1*4] = 0.0;
m_modelview
[3 + 2*4] = 0.0;
m_modelview
[3 + 3*4] = 1.0;
if (scale
!= 0.0) {
m_modelview
[12] *= scale
;
m_modelview
[13] *= scale
;
m_modelview
[14] *= scale
;
}
}
void arglDispImage
(ARUint8
*image
, const ARParam
*cparam
, const double zoom
, ARGL_CONTEXT_SETTINGS_REF contextSettings
)
{
GLint texEnvModeSave
;
GLboolean lightingSave
;
GLboolean depthTestSave
;
#ifdef ARGL_DEBUG
GLenum err
;
const GLubyte
*errs
;
#endif // ARGL_DEBUG
if (!image
) return;
// Prepare an orthographic projection, set camera position for 2D drawing, and save GL state.
glGetTexEnviv
(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, &texEnvModeSave
); // Save GL texture environment mode.
if (texEnvModeSave
!= GL_REPLACE
) glTexEnvi
(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
lightingSave
= glIsEnabled
(GL_LIGHTING
); // Save enabled state of lighting.
if (lightingSave
== GL_TRUE
) glDisable
(GL_LIGHTING
);
depthTestSave
= glIsEnabled
(GL_DEPTH_TEST
); // Save enabled state of depth test.
if (depthTestSave
== GL_TRUE
) glDisable
(GL_DEPTH_TEST
);
glMatrixMode
(GL_PROJECTION
);
glPushMatrix
();
glLoadIdentity
();
gluOrtho2D
(0, cparam
->xsize
, 0, cparam
->ysize
);
glMatrixMode
(GL_MODELVIEW
);
glPushMatrix
();
glLoadIdentity
();
if (arDebug
) { // Globals from ar.h: arDebug, arImage, arImageProcMode.
if (arImage
) {
if (arImageProcMode
== AR_IMAGE_PROC_IN_HALF
) {
ARParam cparamScaled
= *cparam
;
cparamScaled.
xsize /= 2;
cparamScaled.
ysize /= 2;
arglDispImageStateful
(arImage
, &cparamScaled
, zoom
* 2.0, contextSettings
);
} else {
arglDispImageStateful
(arImage
, cparam
, zoom
, contextSettings
);
}
}
} else {
arglDispImageStateful
(image
, cparam
, zoom
, contextSettings
);
}
// Restore previous projection, camera position, and GL state.
glMatrixMode
(GL_PROJECTION
);
glPopMatrix
();
glMatrixMode
(GL_MODELVIEW
);
glPopMatrix
();
if (depthTestSave
== GL_TRUE
) glEnable
(GL_DEPTH_TEST
); // Restore enabled state of depth test.
if (lightingSave
== GL_TRUE
) glEnable
(GL_LIGHTING
); // Restore enabled state of lighting.
if (texEnvModeSave
!= GL_REPLACE
) glTexEnvi
(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, texEnvModeSave
); // Restore GL texture environment mode.
#ifdef ARGL_DEBUG
// Report any errors we generated.
while ((err
= glGetError
()) != GL_NO_ERROR
) {
errs
= gluErrorString
(err
); // fetch error code
fprintf(stderr
, "GL error: %s (%i)\n", errs
, (int)err
); // write err code and number to stderr
}
#endif // ARGL_DEBUG
}
void arglDispImageStateful
(ARUint8
*image
, const ARParam
*cparam
, const double zoom
, ARGL_CONTEXT_SETTINGS_REF contextSettings
)
{
float zoomf
;
int texmapScaleFactor
, params
[4];
zoomf
= (float)zoom
;
texmapScaleFactor
= contextSettings
->arglTexmapMode
+ 1;
if (contextSettings
->arglDrawMode
== AR_DRAW_BY_GL_DRAW_PIXELS
) {
glDisable
(GL_TEXTURE_2D
);
glGetIntegerv
(GL_VIEWPORT
, (GLint
*)params
);
glPixelZoom
(zoomf
* ((float)(params
[2]) / (float)(cparam
->xsize
)),
-zoomf
* ((float)(params
[3]) / (float)(cparam
->ysize
)));
glRasterPos2f
(0.0f, (float)(cparam
->ysize
));
glPixelStorei
(GL_UNPACK_ALIGNMENT
, 1);
glDrawPixels
(cparam
->xsize
, cparam
->ysize
, contextSettings
->pixFormat
, contextSettings
->pixType
, image
);
} else {
// Check whether any settings in globals/parameters have changed.
// N.B. We don't check cparam->dist_factor[], but this is unlikely to change!
if ((texmapScaleFactor
!= contextSettings
->asInited_texmapScaleFactor
) ||
(zoomf
!= contextSettings
->asInited_zoom
) ||
(cparam
->xsize
!= contextSettings
->asInited_xsize
) ||
(cparam
->ysize
!= contextSettings
->asInited_ysize
)) {
contextSettings
->initPlease
= TRUE
;
}
if (contextSettings
->arglTexRectangle
) {
arglDispImageTexRectangle
(image
, cparam
, zoomf
, contextSettings
, texmapScaleFactor
);
} else {
arglDispImageTexPow2
(image
, cparam
, zoomf
, contextSettings
, texmapScaleFactor
);
}
}
}
int arglDistortionCompensationSet
(ARGL_CONTEXT_SETTINGS_REF contextSettings
, int enable
)
{
if (!contextSettings
) return (FALSE
);
contextSettings
->disableDistortionCompensation
= !enable
;
contextSettings
->initPlease
= TRUE
;
return (TRUE
);
}
int arglDistortionCompensationGet
(ARGL_CONTEXT_SETTINGS_REF contextSettings
, int *enable
)
{
if (!contextSettings
) return (FALSE
);
*enable
= !contextSettings
->disableDistortionCompensation
;
return (TRUE
);
}
int arglPixelFormatSet
(ARGL_CONTEXT_SETTINGS_REF contextSettings
, AR_PIXEL_FORMAT format
)
{
if (!contextSettings
) return (FALSE
);
switch (format
) {
case AR_PIXEL_FORMAT_RGBA
:
contextSettings
->pixIntFormat
= GL_RGBA
;
contextSettings
->pixFormat
= GL_RGBA
;
contextSettings
->pixType
= GL_UNSIGNED_BYTE
;
contextSettings
->pixSize
= 4;
break;
case AR_PIXEL_FORMAT_ABGR
: // SGI.
if (arglGLCapabilityCheck
(0, (unsigned char *)"GL_EXT_abgr")) {
contextSettings
->pixIntFormat
= GL_RGBA
;
contextSettings
->pixFormat
= GL_ABGR_EXT
;
contextSettings
->pixType
= GL_UNSIGNED_BYTE
;
contextSettings
->pixSize
= 4;
} else {
return (FALSE
);
}
break;
case AR_PIXEL_FORMAT_BGRA
: // Windows.
if (arglGLCapabilityCheck
(0x0120, (unsigned char *)"GL_EXT_bgra")) {
contextSettings
->pixIntFormat
= GL_RGBA
;
contextSettings
->pixFormat
= GL_BGRA
;
contextSettings
->pixType
= GL_UNSIGNED_BYTE
;
contextSettings
->pixSize
= 4;
} else {
return (FALSE
);
}
break;
case AR_PIXEL_FORMAT_ARGB
: // Mac.
if (arglGLCapabilityCheck
(0x0120, (unsigned char *)"GL_EXT_bgra")
&& arglGLCapabilityCheck
(0x0120, (unsigned char *)"GL_APPLE_packed_pixels")) {
contextSettings
->pixIntFormat
= GL_RGBA
;
contextSettings
->pixFormat
= GL_BGRA
;
#ifdef AR_BIG_ENDIAN
contextSettings
->pixType
= GL_UNSIGNED_INT_8_8_8_8_REV
;
#else
contextSettings
->pixType
= GL_UNSIGNED_INT_8_8_8_8
;
#endif
contextSettings
->pixSize
= 4;
} else {
return (FALSE
);
}
break;
case AR_PIXEL_FORMAT_RGB
:
contextSettings
->pixIntFormat
= GL_RGB
;
contextSettings
->pixFormat
= GL_RGB
;
contextSettings
->pixType
= GL_UNSIGNED_BYTE
;
contextSettings
->pixSize
= 3;
break;
case AR_PIXEL_FORMAT_BGR
:
if (arglGLCapabilityCheck
(0x0120, (unsigned char *)"GL_EXT_bgra")) {
contextSettings
->pixIntFormat
= GL_RGB
;
contextSettings
->pixFormat
= GL_BGR
;
contextSettings
->pixType
= GL_UNSIGNED_BYTE
;
contextSettings
->pixSize
= 3;
} else {
return (FALSE
);
}
break;
case AR_PIXEL_FORMAT_MONO
:
contextSettings
->pixIntFormat
= GL_LUMINANCE
;
contextSettings
->pixFormat
= GL_LUMINANCE
;
contextSettings
->pixType
= GL_UNSIGNED_BYTE
;
contextSettings
->pixSize
= 1;
break;
case AR_PIXEL_FORMAT_2vuy
:
if (arglGLCapabilityCheck
(0, (unsigned char *)"GL_APPLE_ycbcr_422")) {
contextSettings
->pixIntFormat
= GL_RGB
;
contextSettings
->pixFormat
= GL_YCBCR_422_APPLE
;
#ifdef AR_BIG_ENDIAN
contextSettings
->pixType
= GL_UNSIGNED_SHORT_8_8_REV_APPLE
;
#else
contextSettings
->pixType
= GL_UNSIGNED_SHORT_8_8_APPLE
;
#endif
} else if (arglGLCapabilityCheck
(0, (unsigned char *)"GL_MESA_ycbcr_texture")) {
contextSettings
->pixIntFormat
= GL_YCBCR_MESA
;
contextSettings
->pixFormat
= GL_YCBCR_MESA
;
#ifdef AR_BIG_ENDIAN
contextSettings
->pixType
= GL_UNSIGNED_SHORT_8_8_REV_MESA
;
#else
contextSettings
->pixType
= GL_UNSIGNED_SHORT_8_8_MESA
;
#endif
} else {
return (FALSE
);
}
contextSettings
->pixSize
= 2;
break;
case AR_PIXEL_FORMAT_yuvs
:
if (arglGLCapabilityCheck
(0, (unsigned char *)"GL_APPLE_ycbcr_422")) {
contextSettings
->pixIntFormat
= GL_RGB
;
contextSettings
->pixFormat
= GL_YCBCR_422_APPLE
;
#ifdef AR_BIG_ENDIAN
contextSettings
->pixType
= GL_UNSIGNED_SHORT_8_8_APPLE
;
#else
contextSettings
->pixType
= GL_UNSIGNED_SHORT_8_8_REV_APPLE
;
#endif
} else if (arglGLCapabilityCheck
(0, (unsigned char *)"GL_MESA_ycbcr_texture")) {
contextSettings
->pixIntFormat
= GL_YCBCR_MESA
;
contextSettings
->pixFormat
= GL_YCBCR_MESA
;
#ifdef AR_BIG_ENDIAN
contextSettings
->pixType
= GL_UNSIGNED_SHORT_8_8_MESA
;
#else
contextSettings
->pixType
= GL_UNSIGNED_SHORT_8_8_REV_MESA
;
#endif
} else {
return (FALSE
);
}
contextSettings
->pixSize
= 2;
break;
default:
return (FALSE
);
break;
}
contextSettings
->initPlease
= TRUE
;
return (TRUE
);
}
int arglPixelFormatGet
(ARGL_CONTEXT_SETTINGS_REF contextSettings
, AR_PIXEL_FORMAT
*format
, int *size
)
{
if (!contextSettings
) return (FALSE
);
switch (contextSettings
->pixFormat
) {
case GL_RGBA
:
*format
= AR_PIXEL_FORMAT_RGBA
;
*size
= 4;
break;
case GL_ABGR_EXT
:
*format
= AR_PIXEL_FORMAT_ABGR
;
*size
= 4;
break;
case GL_BGRA
:
if (contextSettings
->pixType
== GL_UNSIGNED_BYTE
) *format
= AR_PIXEL_FORMAT_BGRA
;
#ifdef AR_BIG_ENDIAN
else if (contextSettings
->pixType
== GL_UNSIGNED_INT_8_8_8_8_REV
) *format
= AR_PIXEL_FORMAT_ARGB
;
#else
else if (contextSettings
->pixType
== GL_UNSIGNED_INT_8_8_8_8
) *format
= AR_PIXEL_FORMAT_ARGB
;
#endif
else return (FALSE
);
*size
= 4;
break;
case GL_RGB
:
*format
= AR_PIXEL_FORMAT_RGB
;
*size
= 3;
break;
case GL_BGR
:
*format
= AR_PIXEL_FORMAT_BGR
;
*size
= 3;
break;
case GL_YCBCR_422_APPLE
:
case GL_YCBCR_MESA
:
#ifdef AR_BIG_ENDIAN
if (contextSettings
->pixType
== GL_UNSIGNED_SHORT_8_8_REV_APPLE
) *format
= AR_PIXEL_FORMAT_2vuy
; // N.B.: GL_UNSIGNED_SHORT_8_8_REV_APPLE = GL_UNSIGNED_SHORT_8_8_REV_MESA
else if (contextSettings
->pixType
== GL_UNSIGNED_SHORT_8_8_APPLE
) *format
= AR_PIXEL_FORMAT_yuvs
; // GL_UNSIGNED_SHORT_8_8_APPLE = GL_UNSIGNED_SHORT_8_8_MESA
#else
if (contextSettings
->pixType
== GL_UNSIGNED_SHORT_8_8_APPLE
) *format
= AR_PIXEL_FORMAT_2vuy
;
else if (contextSettings
->pixType
== GL_UNSIGNED_SHORT_8_8_REV_APPLE
) *format
= AR_PIXEL_FORMAT_yuvs
;
#endif
else return (FALSE
);
*size
= 2;
break;
case GL_LUMINANCE
:
*format
= AR_PIXEL_FORMAT_MONO
;
*size
= 1;
break;
default:
return (FALSE
);
break;
}
return (TRUE
);
}
void arglDrawModeSet
(ARGL_CONTEXT_SETTINGS_REF contextSettings
, const int mode
)
{
if (!contextSettings
|| mode
< 0 || mode
> 1) return; // Sanity check.
contextSettings
->arglDrawMode
= mode
;
}
int arglDrawModeGet
(ARGL_CONTEXT_SETTINGS_REF contextSettings
)
{
if (!contextSettings
) return (-1); // Sanity check.
return (contextSettings
->arglDrawMode
);
}
void arglTexmapModeSet
(ARGL_CONTEXT_SETTINGS_REF contextSettings
, const int mode
)
{
if (!contextSettings
|| mode
< 0 || mode
> 1) return; // Sanity check.
contextSettings
->arglTexmapMode
= mode
;
}
int arglTexmapModeGet
(ARGL_CONTEXT_SETTINGS_REF contextSettings
)
{
if (!contextSettings
) return (-1); // Sanity check.
return (contextSettings
->arglTexmapMode
);
}
void arglTexRectangleSet
(ARGL_CONTEXT_SETTINGS_REF contextSettings
, const int state
)
{
if (!contextSettings
) return; // Sanity check.
contextSettings
->arglTexRectangle
= state
;
}
int arglTexRectangleGet
(ARGL_CONTEXT_SETTINGS_REF contextSettings
)
{
if (!contextSettings
) return (-1); // Sanity check.
return (contextSettings
->arglTexRectangle
);
}