aboutsummaryrefslogtreecommitdiff
path: root/opengl/system/pdp_texture.c
diff options
context:
space:
mode:
authorPablo Martín <caedesv@users.sourceforge.net>2003-09-07 21:51:37 +0000
committerPablo Martín <caedesv@users.sourceforge.net>2003-09-07 21:51:37 +0000
commit9aa1e112850a11854caa2198393dbd910e226151 (patch)
tree9ed62d40d96b503049229e1cb2555c4883416cb9 /opengl/system/pdp_texture.c
parent213978fa8a868661dda88e6b4e7cacec1c90677a (diff)
Updating pdp version to 0.12.2
svn path=/trunk/externals/pdp/; revision=942
Diffstat (limited to 'opengl/system/pdp_texture.c')
-rw-r--r--opengl/system/pdp_texture.c541
1 files changed, 541 insertions, 0 deletions
diff --git a/opengl/system/pdp_texture.c b/opengl/system/pdp_texture.c
new file mode 100644
index 0000000..46e1c7a
--- /dev/null
+++ b/opengl/system/pdp_texture.c
@@ -0,0 +1,541 @@
+/*
+ * OpenGL Extension Module for pdp - texture packet implementation
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+/* this modules implemtents the opengl texture packet
+ it contains only portable opengl code */
+
+#include <stdio.h>
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include "pdp_opengl.h"
+#include "pdp_texture.h"
+#include "pdp_dpd_command.h"
+
+
+static t_pdp_class *texture_class;
+
+static t_pdp_dpd_commandfactory _tex_cf;
+
+typedef struct _texture_command
+{
+ t_pdp_dpd_command base;
+ int p_src;
+ int p_dst;
+} t_texture_command;
+
+
+/* all symbols are C-style */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+
+/* returns a pointer to the packet subheader given the pdp header */
+static t_texture *_pdp_tex_info(t_pdp *x)
+{
+ return (t_texture *)&(x->info.raw);
+}
+
+
+/* create a pow of 2 texture dimension, ge than 8 */
+static int _round_to_pow_2(int n){
+ int r = 8;
+ while (n > r) r <<= 1;
+ return r;
+}
+
+t_pdp_symbol *_pdp_get_tex_description_from_params(GLsizei width, GLsizei height, GLint format)
+{
+ char description[1024];
+ char *c = description;
+
+ c += sprintf(c, "texture");
+ switch(format){
+ case GL_LUMINANCE: c += sprintf(c, "/grey"); break;
+ case GL_RGB: c += sprintf(c, "/rgb"); break;
+ case GL_RGBA: c += sprintf(c, "/rgba"); break;
+ default:
+ c += sprintf(c, "/unknown"); goto exit;
+ }
+ c += sprintf(c, "/%dx%d", width, height);
+
+ exit:
+ return pdp_gensym(description);
+}
+
+t_pdp_symbol *_pdp_tex_get_description(t_pdp *header)
+{
+ t_texture *texture = _pdp_tex_info(header);
+ int encoding;
+
+ if (!header) return pdp_gensym("invalid");
+ else if (!header->desc){
+ if (header->type == PDP_TEXTURE){
+ /* if description is not defined, try to construct it */
+ return _pdp_get_tex_description_from_params(texture->width, texture->height, texture->format);
+ }
+ else return pdp_gensym("unknown");
+ }
+ else return header->desc;
+}
+
+
+static int _pdp_packet_texture_old_or_dummy(u32 width, u32 height, s32 format);
+static void _pdp_packet_gentexture(int packet);
+
+static void texture_command_convert_bitmap_to_texture(t_texture_command *c)
+{
+ t_texture *t = (t_texture *)pdp_packet_subheader(c->p_dst);
+
+ /* make sure packet contains a texture, since it is created with _pdp_packet_reuse_texture */
+ _pdp_packet_gentexture(c->p_dst);
+
+ /* flip source image before uploading */
+ pdp_packet_bitmap_flip_top_bottom(c->p_src);
+
+ /* fill texture */
+ pdp_packet_texture_make_current(c->p_dst);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, t->sub_width, t->sub_height,
+ t->format, GL_UNSIGNED_BYTE, (char *)pdp_packet_data(c->p_src));
+
+ /* decrease refcount */
+ pdp_packet_mark_unused(c->p_src);
+ pdp_packet_mark_unused(c->p_dst);
+
+ //post("conversion done");
+ pdp_dpd_command_suicide(c);
+}
+
+
+/* converters to standard pdp types */
+int _pdp_packet_texture_convert_image_to_texture(int packet, t_pdp_symbol *dest_template)
+{
+ int p_temp, p;
+
+ //post ("converting to bitmap");
+ p_temp = pdp_packet_convert_rw(packet, pdp_gensym("bitmap/*/*"));
+ if (p_temp == -1) return -1;
+
+ //post ("converting to texture");
+ p = pdp_packet_convert_rw(p_temp, pdp_gensym("texture/*/*"));
+ pdp_packet_mark_unused(p_temp);
+ return p;
+}
+
+
+
+/* converters to standard pdp types */
+int _pdp_packet_texture_convert_bitmap_to_texture(int packet, t_pdp_symbol *dest_template)
+{
+ t_pdp *header = pdp_packet_header(packet);
+ void *data = pdp_packet_data (packet);
+ int new_p;
+ u32 w;
+ u32 h;
+ t_texture_command *c;
+
+ if (!pdp_packet_bitmap_isvalid(packet)) return -1;
+
+ w = header->info.image.width;
+ h = header->info.image.height;
+
+ switch (header->info.image.encoding){
+ case PDP_BITMAP_GREY:
+ /* create greyscale texture */
+ new_p = _pdp_packet_texture_old_or_dummy(w,h, GL_LUMINANCE);
+ break;
+ case PDP_BITMAP_RGB:
+ /* create rgb texture */
+ new_p = _pdp_packet_texture_old_or_dummy(w,h, GL_RGB);
+ break;
+ case PDP_BITMAP_RGBA:
+ /* create greyscale texture */
+ new_p = _pdp_packet_texture_old_or_dummy(w,h, GL_RGBA);
+ break;
+ default:
+ new_p = -1;
+ break;
+ }
+
+ if (new_p != -1){
+
+ /* remark: this is a hack. a texture has to be created
+ when a rendering context is active. this means it has
+ to be created in the correct thread. therefore a dpd
+ command is added to the 3dp queue. this seems to work,
+ but without a dropping mechanism, this can overload the
+ queue. the real solution would be to add a converter
+ object to a 3dp chain, or to accept image or bitmap
+ packets in 3dp objects */
+
+
+ /* dispatch command */
+ c = (t_texture_command *)pdp_dpd_commandfactory_get_new_command(&_tex_cf);
+ c->p_src = pdp_packet_copy_rw(packet);
+ c->p_dst = pdp_packet_copy_ro(new_p);
+ pdp_procqueue_add(pdp_opengl_get_queue(), c, texture_command_convert_bitmap_to_texture, 0, 0);
+ }
+ return new_p;
+
+}
+
+
+
+int _pdp_packet_texture_convert_texture_to_bitmap(int packet, t_pdp_symbol *dest_template0)
+{
+ post("_pdp_packet_texture_convert_texture_to_bitmap not implemented.");
+ return -1;
+}
+
+
+t_texture *pdp_packet_texture_info(int packet)
+{
+ t_pdp *header = pdp_packet_header(packet);
+ if (pdp_packet_texture_isvalid(packet)) return _pdp_tex_info(header);
+ else return 0;
+}
+
+/* check if valid texture packet. all other methods assume packet is valid */
+int pdp_packet_texture_isvalid(int packet)
+{
+ t_pdp *header;
+ if (!(header = pdp_packet_header(packet))) return 0;
+ if (PDP_TEXTURE != header->type) return 0;
+ return glIsTexture(_pdp_tex_info(header)->tex_obj);
+}
+
+
+
+static void _tex_init_obj(t_texture *t)
+{
+ //u8 *dummydata;
+ //int i;
+
+ glBindTexture(GL_TEXTURE_2D, t->tex_obj);
+ glTexImage2D(GL_TEXTURE_2D, 0, t->format, t->width, t->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
+
+ /* debug
+ dummydata = (u8 *)malloc(t->width*t->height*4);
+ for (i=0; i<t->width*t->height*4; i++){dummydata[i] = random(); }
+ glTexImage2D(GL_TEXTURE_2D, 0, t->format, t->width, t->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, dummydata);
+ free(dummydata);
+ */
+
+}
+
+
+static void _pdp_tex_copy(t_pdp *dst, t_pdp *src);
+static void _pdp_tex_clone(t_pdp *dst, t_pdp *src);
+static void _pdp_tex_reinit(t_pdp *dst);
+static void _pdp_tex_cleanup(t_pdp *dst);
+
+static void _pdp_tex_init_methods(t_pdp *h)
+{
+ h->theclass = texture_class;
+}
+
+static void _pdp_tex_reinit(t_pdp *dst)
+{
+ /* this does nothing. texture is assumed to be in a valid state */
+}
+static void _pdp_tex_clone(t_pdp *dst, t_pdp *src)
+{
+ t_texture *dst_t = _pdp_tex_info(dst);
+ t_texture *src_t = _pdp_tex_info(src);
+
+ //post("WARNING: _pdp_tex_clone: should not be called from outside 3d thread");
+
+ /* determine if destination texture is valid */
+ if (glIsTexture(dst_t->tex_obj)){
+ /* check format */
+ if ((dst_t->width >= src_t->width)
+ && (dst_t->height >= src_t->height)
+ && (dst_t->format == src_t->format)){
+ dst_t->sub_width = src_t->sub_width;
+ dst_t->sub_height = src_t->sub_height;
+ return;
+ }
+ }
+ /* not initialized, so we need to create a new one */
+ else {
+ glGenTextures(1, (GLuint*)&dst_t->tex_obj);
+ }
+
+ /* setup header */
+ dst_t->width = src_t->width;
+ dst_t->height = src_t->height;
+ dst_t->format = src_t->format;
+ dst_t->sub_width = src_t->sub_width;
+ dst_t->sub_height = src_t->sub_height;
+
+ /* setup packet methods */
+ _pdp_tex_init_methods(dst);
+
+ /* init description */
+ dst->desc = _pdp_tex_get_description(dst);
+
+}
+static void _pdp_tex_copy(t_pdp *dst, t_pdp *src)
+{
+ /* texture copying is inefficient. for the tex extensions there is no analogy
+ for "efficient in-place processing"
+ this means the pdp_packet_register_rw() call should be avoided
+ this inconsistency should be tucked away in a texture base class */
+
+ /* todo: use texture combining extensions for this */
+
+ post("WARNING: fanout is not yet implemented correctly for texture packets");
+
+ /* not implemented yet, just a call to the clone method */
+ _pdp_tex_clone(dst, src);
+}
+
+static void _pdp_tex_cleanup(t_pdp *dst)
+{
+ t_texture *t = _pdp_tex_info(dst);
+ glDeleteTextures(1, (GLuint*)&t->tex_obj);
+ t->tex_obj = -1; /* is this value guaranteed to be invalid? */
+}
+
+
+/* texture constructors */
+
+/* reuse a texture, or create a "dummy" == packet with everything except a valid texture object */
+static int _pdp_packet_texture_old_or_dummy(u32 width, u32 height, s32 format)
+{
+ int p = -1;
+ t_pdp *h;
+ t_texture *t;
+
+ int p2_w = _round_to_pow_2(width);
+ int p2_h = _round_to_pow_2(height);
+
+
+ /* try to reuse a texture packet or get a new one */
+ p = pdp_packet_reuse(_pdp_get_tex_description_from_params(p2_w, p2_h, format));
+ if (-1 == p) p = pdp_packet_brandnew(PDP_TEXTURE, 0);
+ if (-1 == p) return -1;
+
+ h = pdp_packet_header(p);
+ t = _pdp_tex_info(h);
+
+ /* check if alloc succeded */
+ if (!h) return -1;
+
+ /* check if tex is already initialized */
+ if (pdp_packet_texture_isvalid(p)){
+ /* check format */
+ if ((t->width >= width) && (t->height >= height) && (t->format == format)){
+ //post("pdp_packet_new_tex: reused");
+ t->sub_width = width;
+ t->sub_height = height;
+ return p;
+ }
+ post("ERROR: pdp_packet_new_texture: pdp_packet_reuse returned wrong type");
+ }
+
+ /* determine the texture dims * setup rest of data struct */
+ t->width = 64;
+ t->height = 64;
+ while (t->width < width) t->width <<= 1;
+ while (t->height < height) t->height <<= 1;
+
+ t->format = format;
+ t->sub_width = width;
+ t->sub_height = height;
+
+ _pdp_tex_init_methods(h);
+
+
+ /* init the texture */
+ //_tex_init_obj(t);
+
+ /* init description */
+ h->desc = _pdp_tex_get_description(h);
+
+
+ return p;
+}
+
+/* don't call this method on a non-texture object! */
+static void _pdp_packet_gentexture(int p)
+{
+ t_texture *t;
+ if (!pdp_packet_texture_isvalid(p)){
+ /* not initialized, so we need to create a new one */
+ // post("generating texture");
+ t = (t_texture *)pdp_packet_subheader(p);
+
+ /* create the texture object */
+ glGenTextures(1, (GLuint *)&t->tex_obj);
+
+ /* init the texture */
+ _tex_init_obj(t);
+
+ }
+}
+
+int pdp_packet_new_texture(u32 width, u32 height, s32 format)
+{
+ t_texture *t;
+ int p = _pdp_packet_texture_old_or_dummy(width, height, format);
+
+ //post("WARNING: pdp_packet_new_texture: this method should not be called outside the 3dp thread");
+
+ if (p == -1) return -1;
+ _pdp_packet_gentexture(p);
+ return p;
+}
+
+
+/* high level texture packet operators */
+
+/* make a texture the current texture context */
+void pdp_packet_texture_make_current(int packet)
+{
+ t_texture *t = pdp_packet_texture_info(packet);
+ if (!t) return;
+ glBindTexture(GL_TEXTURE_2D, t->tex_obj);
+}
+
+void pdp_packet_texture_make_current_enable(int packet)
+{
+ glEnable(GL_TEXTURE_2D);
+ pdp_packet_texture_make_current(packet);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+}
+
+float pdp_packet_texture_fracx(int packet)
+{
+ t_texture *t = pdp_packet_texture_info(packet);
+ if (!t) return 0.0;
+ return (float)t->sub_width/t->width;
+}
+
+float pdp_packet_texture_fracy(int packet)
+{
+ t_texture *t = pdp_packet_texture_info(packet);
+ if (!t) return 0.0;
+ return (float)t->sub_height/t->height;
+}
+
+u32 pdp_packet_texture_total_width(int packet)
+{
+ t_texture *t = pdp_packet_texture_info(packet);
+ if (!t) return 0;
+ return t->width;
+
+}
+u32 pdp_packet_texture_total_height(int packet)
+{
+ t_texture *t = pdp_packet_texture_info(packet);
+ if (!t) return 0;
+ return t->height;
+
+}
+
+u32 pdp_packet_texture_sub_width(int packet)
+{
+ t_texture *t = pdp_packet_texture_info(packet);
+ if (!t) return 0;
+ return t->sub_width;
+
+}
+u32 pdp_packet_texture_sub_height(int packet)
+{
+ t_texture *t = pdp_packet_texture_info(packet);
+ if (!t) return 0;
+ return t->sub_height;
+}
+
+float pdp_packet_texture_sub_aspect(int packet)
+{
+ t_texture *t = pdp_packet_texture_info(packet);
+ if (!t) return 0;
+ return (float)t->sub_width/t->sub_height;
+}
+
+/* setup for 2d operation from texture dimensions */
+void pdp_packet_texture_setup_2d_context(int p)
+{
+ u32 w;
+ u32 h;
+ float asp;
+ if (!pdp_packet_texture_isvalid(p)) return;
+ w = pdp_packet_texture_sub_width(p);
+ h = pdp_packet_texture_sub_height(p);
+ asp = pdp_packet_texture_sub_aspect(p);
+
+ /* set the viewport to the size of the sub texture */
+ glViewport(0, 0, w, h);
+
+ /* set orthogonal projection, with a relative frame size of (2asp x 2) */
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ gluOrtho2D(0.0, 2*asp, 0, 2);
+
+ /* set the center of view */
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(asp, 1, 0);
+ glScalef(1,-1,1);
+}
+
+void pdp_texture_setup(void)
+{
+ t_pdp_conversion_program *program;
+
+ /* setup packet class */
+ texture_class = pdp_class_new(pdp_gensym("texture/*/*"), 0);
+ texture_class->cleanup = _pdp_tex_cleanup;
+ texture_class->reinit = _pdp_tex_reinit;
+ texture_class->clone = _pdp_tex_clone;
+ texture_class->copy = _pdp_tex_copy;
+
+ /* init command list */
+ pdp_dpd_commandfactory_init(&_tex_cf, sizeof(t_texture_command));
+
+
+
+ /* setup programs */
+ program = pdp_conversion_program_new(_pdp_packet_texture_convert_bitmap_to_texture, 0);
+ pdp_type_register_conversion(pdp_gensym("bitmap/*/*"), pdp_gensym("texture/*/*"), program);
+
+ /* this is a hack to use until the type conversion system has a proper search algo */
+ program = pdp_conversion_program_new(_pdp_packet_texture_convert_image_to_texture, 0);
+ pdp_type_register_conversion(pdp_gensym("image/*/*"), pdp_gensym("texture/*/*"), program);
+
+
+ program = pdp_conversion_program_new(_pdp_packet_texture_convert_texture_to_bitmap, 0);
+ pdp_type_register_conversion(pdp_gensym("texture/*/*"), pdp_gensym("bitmap/*/*"), program);
+
+}
+
+/* all symbols are C-style */
+#ifdef __cplusplus
+}
+#endif