/* $Id: texture.c,v 1.10 2005/04/23 07:49:14 gregcouch Exp $ */ /* * Togl - a Tk OpenGL widget * Copyright (C) 1996-1997 Brian Paul and Ben Bederson * See the LICENSE file for copyright details. */ /* * An example Togl program demonstrating texture mapping */ #include "togl.h" #include #include #if defined(TOGL_AGL) || defined(TOGL_AGL_CLASSIC) # include #else # include #endif #include "image.h" /* * The following variable is a special hack that is needed in order for * Sun shared libraries to be used for Tcl. */ #ifdef SUN extern int matherr(); int *tclDummyMathPtr = (int *) matherr; #endif #define CHECKER 0 #define FACE 1 #define TREE 2 static GLenum minfilter = GL_NEAREST_MIPMAP_LINEAR; static GLenum magfilter = GL_LINEAR; static GLenum swrap = GL_REPEAT; static GLenum twrap = GL_REPEAT; static GLenum envmode = GL_MODULATE; static GLubyte polycolor[4] = { 255, 255, 255, 255 }; static int image = CHECKER; static GLfloat coord_scale = 1.0; static GLfloat xrot = 0.0; static GLfloat yrot = 0.0; static GLfloat scale = 1.0; static GLint width, height; static GLboolean blend = GL_FALSE; /* * Load a texture image. n is one of CHECKER, FACE or TREE. */ void texture_image(int n) { if (n == CHECKER) { #define WIDTH 64 #define HEIGHT 64 GLubyte teximage[WIDTH * HEIGHT][4]; int i, j; for (i = 0; i < HEIGHT; i++) { for (j = 0; j < WIDTH; j++) { GLubyte value; value = ((i / 4 + j / 4) % 2) ? 0xff : 0x00; teximage[i * WIDTH + j][0] = value; teximage[i * WIDTH + j][1] = value; teximage[i * WIDTH + j][2] = value; teximage[i * WIDTH + j][3] = value; } } glEnable(GL_TEXTURE_2D); gluBuild2DMipmaps(GL_TEXTURE_2D, 4, WIDTH, HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, teximage); blend = GL_FALSE; #undef WIDTH #undef HEIGHT } else if (n == FACE) { TK_RGBImageRec *img = tkRGBImageLoad("ben.rgb"); if (img) { glEnable(GL_TEXTURE_2D); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); gluBuild2DMipmaps(GL_TEXTURE_2D, img->sizeZ, img->sizeX, img->sizeY, img->sizeZ == 3 ? GL_RGB : GL_RGBA, GL_UNSIGNED_BYTE, img->data); blend = GL_TRUE; } } else if (n == TREE) { TK_RGBImageRec *img = tkRGBImageLoad("tree2.rgba"); if (img) { glEnable(GL_TEXTURE_2D); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); gluBuild2DMipmaps(GL_TEXTURE_2D, img->sizeZ, img->sizeX, img->sizeY, img->sizeZ == 3 ? GL_RGB : GL_RGBA, GL_UNSIGNED_BYTE, img->data); blend = GL_TRUE; } } else { abort(); } } /* * Togl widget create callback. This is called by Tcl/Tk when the widget has * been realized. Here's where one may do some one-time context setup or * initializations. */ void create_cb(Togl *togl) { glEnable(GL_DEPTH_TEST); /* Enable depth buffering */ texture_image(CHECKER); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magfilter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minfilter); } /* * Togl widget reshape callback. This is called by Tcl/Tk when the widget * has been resized. Typically, we call glViewport and perhaps setup the * projection matrix. */ void reshape_cb(Togl *togl) { width = Togl_Width(togl); height = Togl_Height(togl); glViewport(0, 0, width, height); } static void check_error(char *where) { GLenum error; while (1) { error = glGetError(); if (error == GL_NO_ERROR) { break; } printf("OpenGL error near %s: %s\n", where, gluErrorString(error)); } } /* * Togl widget display callback. This is called by Tcl/Tk when the widget's * contents have to be redrawn. Typically, we clear the color and depth * buffers, render our objects, then swap the front/back color buffers. */ void display_cb(Togl *togl) { float aspect = (float) width / (float) height; check_error("begin display\n"); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* Draw background image */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glDisable(GL_TEXTURE_2D); glDisable(GL_DEPTH_TEST); glBegin(GL_POLYGON); glColor3f(0.0, 0.0, 0.3); glVertex2f(-1.0, -1.0); glColor3f(0.0, 0.0, 0.3); glVertex2f(1.0, -1.0); glColor3f(0.0, 0.0, 0.9); glVertex2f(1.0, 1.0); glColor3f(0.0, 0.0, 0.9); glVertex2f(-1.0, 1.0); glEnd(); /* draw textured object */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-aspect, aspect, -1.0, 1.0, 2.0, 10.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0, 0.0, -5.0); glScalef(scale, scale, scale); glRotatef(yrot, 0.0, 1.0, 0.0); glRotatef(xrot, 1.0, 0.0, 0.0); glEnable(GL_DEPTH_TEST); glEnable(GL_TEXTURE_2D); glColor4ubv(polycolor); if (blend) { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); } glBegin(GL_POLYGON); glTexCoord2f(0.0, 0.0); glVertex2f(-1.0, -1.0); glTexCoord2f(coord_scale, 0.0); glVertex2f(1.0, -1.0); glTexCoord2f(coord_scale, coord_scale); glVertex2f(1.0, 1.0); glTexCoord2f(0.0, coord_scale); glVertex2f(-1.0, 1.0); glEnd(); glDisable(GL_BLEND); Togl_SwapBuffers(togl); } /* * Called when a magnification filter radio button is pressed. */ int magfilter_cb(Togl *togl, int argc, CONST84 char *argv[]) { Tcl_Interp *interp = Togl_Interp(togl); if (strcmp(argv[2], "GL_NEAREST") == 0) { magfilter = GL_NEAREST; } else if (strcmp(argv[2], "GL_LINEAR") == 0) { magfilter = GL_LINEAR; } else { Tcl_SetResult(interp, "unknown magnification filter type", TCL_STATIC); return TCL_ERROR; } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magfilter); Togl_PostRedisplay(togl); return TCL_OK; } /* * Called when a minification filter radio button is pressed. */ int minfilter_cb(Togl *togl, int argc, CONST84 char *argv[]) { Tcl_Interp *interp = Togl_Interp(togl); if (strcmp(argv[2], "GL_NEAREST") == 0) { minfilter = GL_NEAREST; } else if (strcmp(argv[2], "GL_LINEAR") == 0) { minfilter = GL_LINEAR; } else if (strcmp(argv[2], "GL_NEAREST_MIPMAP_NEAREST") == 0) { minfilter = GL_NEAREST_MIPMAP_NEAREST; } else if (strcmp(argv[2], "GL_LINEAR_MIPMAP_NEAREST") == 0) { minfilter = GL_LINEAR_MIPMAP_NEAREST; } else if (strcmp(argv[2], "GL_NEAREST_MIPMAP_LINEAR") == 0) { minfilter = GL_NEAREST_MIPMAP_LINEAR; } else if (strcmp(argv[2], "GL_LINEAR_MIPMAP_LINEAR") == 0) { minfilter = GL_LINEAR_MIPMAP_LINEAR; } else { Tcl_SetResult(interp, "unknown minification filter type", TCL_STATIC); return TCL_ERROR; } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minfilter); Togl_PostRedisplay(togl); return TCL_OK; } int xrot_cb(Togl *togl, int argc, CONST84 char *argv[]) { Tcl_Interp *interp = Togl_Interp(togl); /* error checking */ if (argc != 3) { Tcl_SetResult(interp, "wrong # args: should be \"pathName setXrot ?angle?\"", TCL_STATIC); return TCL_ERROR; } xrot = atof(argv[2]); Togl_PostRedisplay(togl); /* Let result string equal value */ strcpy(interp->result, argv[2]); return TCL_OK; } int yrot_cb(Togl *togl, int argc, CONST84 char *argv[]) { Tcl_Interp *interp = Togl_Interp(togl); /* error checking */ if (argc != 3) { Tcl_SetResult(interp, "wrong # args: should be \"pathName setYrot ?angle?\"", TCL_STATIC); return TCL_ERROR; } yrot = atof(argv[2]); Togl_PostRedisplay(togl); /* Let result string equal value */ strcpy(interp->result, argv[2]); return TCL_OK; } int scale_cb(Togl *togl, int argc, CONST84 char *argv[]) { Tcl_Interp *interp = Togl_Interp(togl); /* error checking */ if (argc != 3) { Tcl_SetResult(interp, "wrong # args: should be \"pathName scale ?value?\"", TCL_STATIC); return TCL_ERROR; } scale = atof(argv[2]); Togl_PostRedisplay(togl); /* Let result string equal value */ strcpy(interp->result, argv[2]); return TCL_OK; } /* * Called when S texture coordinate wrapping is changed. */ int swrap_cb(Togl *togl, int argc, CONST84 char *argv[]) { Tcl_Interp *interp = Togl_Interp(togl); /* error checking */ if (argc != 3) { Tcl_SetResult(interp, "wrong # args: should be \"pathName swrap ?mode?\"", TCL_STATIC); return TCL_ERROR; } if (strcmp(argv[2], "GL_CLAMP") == 0) { swrap = GL_CLAMP; } else if (strcmp(argv[2], "GL_REPEAT") == 0) { swrap = GL_REPEAT; } else { Tcl_SetResult(interp, "unknown wrap value", TCL_STATIC); return TCL_ERROR; } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, swrap); Togl_PostRedisplay(togl); /* Let result string equal value */ strcpy(interp->result, argv[2]); return TCL_OK; } /* * Called when T texture coordinate wrapping is changed. */ int twrap_cb(Togl *togl, int argc, CONST84 char *argv[]) { Tcl_Interp *interp = Togl_Interp(togl); /* error checking */ if (argc != 3) { Tcl_SetResult(interp, "wrong # args: should be \"pathName twrap ?mode?\"", TCL_STATIC); return TCL_ERROR; } if (strcmp(argv[2], "GL_CLAMP") == 0) { twrap = GL_CLAMP; } else if (strcmp(argv[2], "GL_REPEAT") == 0) { twrap = GL_REPEAT; } else { Tcl_SetResult(interp, "unknown wrap value", TCL_STATIC); return TCL_ERROR; } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, twrap); Togl_PostRedisplay(togl); /* Let result string equal value */ strcpy(interp->result, argv[2]); return TCL_OK; } /* * Called when the texture environment mode is changed. */ int envmode_cb(Togl *togl, int argc, CONST84 char *argv[]) { Tcl_Interp *interp = Togl_Interp(togl); /* error checking */ if (argc != 3) { Tcl_SetResult(interp, "wrong # args: should be \"pathName envmode ?mode?\"", TCL_STATIC); return TCL_ERROR; } if (strcmp(argv[2], "GL_MODULATE") == 0) { envmode = GL_MODULATE; } else if (strcmp(argv[2], "GL_DECAL") == 0) { envmode = GL_DECAL; } else if (strcmp(argv[2], "GL_BLEND") == 0) { envmode = GL_BLEND; } else { Tcl_SetResult(interp, "unknown texture env mode", TCL_STATIC); return TCL_ERROR; } glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, envmode); Togl_PostRedisplay(togl); /* Let result string equal value */ strcpy(interp->result, argv[2]); return TCL_OK; } /* * Called when the polygon color is changed. */ int polycolor_cb(Togl *togl, int argc, CONST84 char *argv[]) { Tcl_Interp *interp = Togl_Interp(togl); /* error checking */ if (argc != 5) { Tcl_SetResult(interp, "wrong # args: should be \"pathName polycolor ?r? ?g? ?b?\"", TCL_STATIC); return TCL_ERROR; } polycolor[0] = atoi(argv[2]); polycolor[1] = atoi(argv[3]); polycolor[2] = atoi(argv[4]); Togl_PostRedisplay(togl); /* Let result string equal value */ strcpy(interp->result, argv[2]); return TCL_OK; } /* * Called when the texture image is to be changed */ int image_cb(Togl *togl, int argc, CONST84 char *argv[]) { Tcl_Interp *interp = Togl_Interp(togl); /* error checking */ if (argc != 3) { Tcl_SetResult(interp, "wrong # args: should be \"pathName image ?name?\"", TCL_STATIC); return TCL_ERROR; } if (strcmp(argv[2], "CHECKER") == 0) { texture_image(CHECKER); } else if (strcmp(argv[2], "FACE") == 0) { texture_image(FACE); } else if (strcmp(argv[2], "TREE") == 0) { texture_image(TREE); } else { Tcl_SetResult(interp, "unknown texture image", TCL_STATIC); return TCL_ERROR; } Togl_PostRedisplay(togl); /* Let result string equal value */ strcpy(interp->result, argv[2]); return TCL_OK; } /* * Called when the texture coordinate scale is changed. */ int coord_scale_cb(Togl *togl, int argc, CONST84 char *argv[]) { Tcl_Interp *interp = Togl_Interp(togl); float s; /* error checking */ if (argc != 3) { Tcl_SetResult(interp, "wrong # args: should be \"pathName coord_scale ?scale?\"", TCL_STATIC); return TCL_ERROR; } s = atof(argv[2]); if (s > 0.0 && s < 10.0) { coord_scale = s; Togl_PostRedisplay(togl); } /* Let result string equal value */ strcpy(interp->result, argv[2]); return TCL_OK; } TOGL_EXTERN int Texture_Init(Tcl_Interp *interp) { /* * Initialize Tcl, Tk, and the Togl widget module. */ #ifdef USE_TCL_STUBS if (Tcl_InitStubs(interp, "8.1", 0) == NULL) { return TCL_ERROR; } #endif #ifdef USE_TK_STUBS if (Tk_InitStubs(interp, "8.1", 0) == NULL) { return TCL_ERROR; } #endif if (Togl_Init(interp) == TCL_ERROR) { return TCL_ERROR; } /* * Specify the C callback functions for widget creation, display, * and reshape. */ Togl_CreateFunc(create_cb); Togl_DisplayFunc(display_cb); Togl_ReshapeFunc(reshape_cb); /* * Make a new Togl widget command so the Tcl code can set a C variable. */ Togl_CreateCommand("min_filter", minfilter_cb); Togl_CreateCommand("mag_filter", magfilter_cb); Togl_CreateCommand("xrot", xrot_cb); Togl_CreateCommand("yrot", yrot_cb); Togl_CreateCommand("scale", scale_cb); Togl_CreateCommand("swrap", swrap_cb); Togl_CreateCommand("twrap", twrap_cb); Togl_CreateCommand("envmode", envmode_cb); Togl_CreateCommand("polycolor", polycolor_cb); Togl_CreateCommand("image", image_cb); Togl_CreateCommand("coord_scale", coord_scale_cb); /* * Call Tcl_CreateCommand for application-specific commands, if * they weren't already created by the init procedures called above. */ return TCL_OK; }