From 9aa1e112850a11854caa2198393dbd910e226151 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Mart=C3=ADn?= Date: Sun, 7 Sep 2003 21:51:37 +0000 Subject: Updating pdp version to 0.12.2 svn path=/trunk/externals/pdp/; revision=942 --- opengl/system/pdp_texture.c | 541 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 541 insertions(+) create mode 100644 opengl/system/pdp_texture.c (limited to 'opengl/system/pdp_texture.c') 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 + * + * 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 +#include +#include +#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; iwidth*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 -- cgit v1.2.1