[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Gnash-commit] gnash ./ChangeLog backend/Makefile.am backend/r...
From: |
Rob Savoye |
Subject: |
[Gnash-commit] gnash ./ChangeLog backend/Makefile.am backend/r... |
Date: |
Sun, 26 Feb 2006 15:49:30 +0000 |
CVSROOT: /sources/gnash
Module name: gnash
Branch:
Changes by: Rob Savoye <address@hidden> 06/02/26 15:49:30
Modified files:
. : ChangeLog
backend : Makefile.am render_handler_ogl.cpp
doc : omf.make
libamf : Makefile.am
libbase : Makefile.am component_hackery.cpp config.cpp
container.cpp container.h demo.cpp demo.h
dlmalloc.c dlmalloc.h file_util.cpp file_util.h
image.cpp image_filters.cpp jpeg.cpp membuf.cpp
membuf.h ogl.cpp png_helper.cpp postscript.cpp
test_ogl.cpp triangulate_float.cpp
triangulate_sint32.cpp tu_file.cpp
tu_file_SDL.cpp tu_random.cpp tu_swap.h
tu_timer.cpp tu_types.cpp utf8.cpp utility.cpp
utility.h zlib_adapter.cpp
libgeometry : Makefile.am axial_box.cpp axial_box.h
collision.cpp collision.h kd_tree_dynamic.cpp
kd_tree_dynamic.h
macros : jpeg.m4 opengl.m4 png.m4 pthreads.m4 sdl.m4
server : Makefile.am
utilities : Makefile.am
Log message:
* libbase/dlmalloc.h: Include stdlib.h instead of the depreciated
malloc.h.
* libbase/tu_swap.h: OpenBSD defines swap macros with the same
name as these functions, so use our implementation intead.
* macros/pthread.h: Reqwrite to handle weird NetBSD pth versus
Pthread problem.
* macros/sdl.m4: Throw out compile test for something simpler and
more portable.
* utilities/Makefile.am: Add pthread header and library.
* server/Makefile.am: Add pthread header and library.
* backend/Makefile.am: Add pthread header and library.
* libbase/container.h: Add ugly NetBSD specific hack so it'll use
pthread, not Pth if both are installed.
* libgeometry/kd_tree_dynamic.cp: Include stdio so __sputc() is
defined on NetBSD.
CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/ChangeLog.diff?tr1=1.159&tr2=1.160&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/backend/Makefile.am.diff?tr1=1.14&tr2=1.15&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/backend/render_handler_ogl.cpp.diff?tr1=1.6&tr2=1.7&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/doc/omf.make.diff?tr1=1.6&tr2=1.7&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libamf/Makefile.am.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libbase/Makefile.am.diff?tr1=1.11&tr2=1.12&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libbase/component_hackery.cpp.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libbase/config.cpp.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libbase/container.cpp.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libbase/container.h.diff?tr1=1.6&tr2=1.7&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libbase/demo.cpp.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libbase/demo.h.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libbase/dlmalloc.c.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libbase/dlmalloc.h.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libbase/file_util.cpp.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libbase/file_util.h.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libbase/image.cpp.diff?tr1=1.4&tr2=1.5&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libbase/image_filters.cpp.diff?tr1=1.3&tr2=1.4&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libbase/jpeg.cpp.diff?tr1=1.3&tr2=1.4&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libbase/membuf.cpp.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libbase/membuf.h.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libbase/ogl.cpp.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libbase/png_helper.cpp.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libbase/postscript.cpp.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libbase/test_ogl.cpp.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libbase/triangulate_float.cpp.diff?tr1=1.3&tr2=1.4&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libbase/triangulate_sint32.cpp.diff?tr1=1.3&tr2=1.4&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libbase/tu_file.cpp.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libbase/tu_file_SDL.cpp.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libbase/tu_random.cpp.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libbase/tu_swap.h.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libbase/tu_timer.cpp.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libbase/tu_types.cpp.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libbase/utf8.cpp.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libbase/utility.cpp.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libbase/utility.h.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libbase/zlib_adapter.cpp.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libgeometry/Makefile.am.diff?tr1=1.9&tr2=1.10&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libgeometry/axial_box.cpp.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libgeometry/axial_box.h.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libgeometry/collision.cpp.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libgeometry/collision.h.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libgeometry/kd_tree_dynamic.cpp.diff?tr1=1.4&tr2=1.5&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/libgeometry/kd_tree_dynamic.h.diff?tr1=1.3&tr2=1.4&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/macros/jpeg.m4.diff?tr1=1.7&tr2=1.8&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/macros/opengl.m4.diff?tr1=1.10&tr2=1.11&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/macros/png.m4.diff?tr1=1.9&tr2=1.10&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/macros/pthreads.m4.diff?tr1=1.4&tr2=1.5&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/macros/sdl.m4.diff?tr1=1.9&tr2=1.10&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/server/Makefile.am.diff?tr1=1.21&tr2=1.22&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/utilities/Makefile.am.diff?tr1=1.9&tr2=1.10&r1=text&r2=text
Patches:
Index: gnash/ChangeLog
diff -u gnash/ChangeLog:1.159 gnash/ChangeLog:1.160
--- gnash/ChangeLog:1.159 Sat Feb 25 15:27:35 2006
+++ gnash/ChangeLog Sun Feb 26 15:49:29 2006
@@ -1,9 +1,27 @@
+2006-02-26 Rob Savoye <address@hidden>
+
+ * libbase/dlmalloc.h: Include stdlib.h instead of the depreciated
+ malloc.h.
+ * libbase/tu_swap.h: OpenBSD defines swap macros with the same
+ name as these functions, so use our implementation intead.
+ * macros/pthread.h: Reqwrite to handle weird NetBSD pth versus
+ Pthread problem.
+ * macros/sdl.m4: Throw out compile test for something simpler and
+ more portable.
+ * utilities/Makefile.am: Add pthread header and library.
+ * server/Makefile.am: Add pthread header and library.
+ * backend/Makefile.am: Add pthread header and library.
+ * libbase/container.h: Add ugly NetBSD specific hack so it'll use
+ pthread, not Pth if both are installed.
+ * libgeometry/kd_tree_dynamic.cp: Include stdio so __sputc() is
+ defined on NetBSD.
+
2006-02-25 Jim Garrison <address@hidden>
* backend/render_handler_d3d.cpp: substituted array<> with
- std::vector<>
+ std::vector<>.
* backend/render_handler_xbox.cpp: substituted array<> with
- std::vector<>
+ std::vector<>.
* libbase/container.cpp: substituted array<> with std::vector<>
* server/morph.cpp: substituted array<> with std::vector<>
* server/morph.h: substituted array<> with std::vector<>
Index: gnash/backend/Makefile.am
diff -u gnash/backend/Makefile.am:1.14 gnash/backend/Makefile.am:1.15
--- gnash/backend/Makefile.am:1.14 Fri Feb 3 19:26:51 2006
+++ gnash/backend/Makefile.am Sun Feb 26 15:49:29 2006
@@ -33,12 +33,14 @@
$(OGG_LIBS) \
$(LIBXML_LIBS) \
$(SDL_LIBS) \
- $(SDL_CFLAGS) \
$(SDL_MIXER_LIBS) \
$(OPENGL_LIBS) \
+ $(GLEXT_LIBS) \
+ $(GTK2_LIBS) \
$(X_LIBS) \
$(DMALLOC_LIBS) \
- $(MP3_LIBS)
+ $(MP3_LIBS) \
+ $(PTHREAD_LIBS)
INCLUDES = -I.. \
-I$(top_srcdir) \
@@ -46,11 +48,16 @@
-I$(top_srcdir)/libbase \
-I$(top_srcdir)/backend \
-I$(top_srcdir)/libgeometry \
- $(SDL_CFLAGS) \
+ $(PTHREAD_CFLAGS) \
+ $(SDL_CFLAGS) \
$(SDL_MIXER_CFLAGS) \
$(LIBXML_CFLAGS) \
$(OPENGL_CFLAGS) \
+ $(GLEXT_CFLAGS) \
+ $(GTK2_CFLAGS) \
$(DMALLOC_CFLAGS) \
+ $(PNG_CFLAGS) \
+ $(JPEG_CFLAGS) \
$(MP3_CFLAGS) \
$(OGG_CFLAGS)
Index: gnash/backend/render_handler_ogl.cpp
diff -u gnash/backend/render_handler_ogl.cpp:1.6
gnash/backend/render_handler_ogl.cpp:1.7
--- gnash/backend/render_handler_ogl.cpp:1.6 Wed Feb 15 23:35:53 2006
+++ gnash/backend/render_handler_ogl.cpp Sun Feb 26 15:49:29 2006
@@ -397,47 +397,47 @@
}
// Old unused code. Might get revived someday.
- #if 0
- // See if we want to, and can, use multitexture
- // antialiasing.
- s_multitexture_antialias = false;
- if (m_enable_antialias)
- {
- int tex_units = 0;
- glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB,
&tex_units);
- if (tex_units >= 2)
- {
- s_multitexture_antialias = true;
- }
-
- // Make sure we have an edge texture
available.
- if (s_multitexture_antialias == true
- && s_edge_texture_id == 0)
- {
- // Very simple texture: 2
texels wide, 1 texel high.
- // Both texels are white; left
texel is all clear, right texel is all opaque.
- unsigned char edge_data[8] =
{ 255, 255, 255, 0, 255, 255, 255, 255 };
-
-
ogl::active_texture(GL_TEXTURE1_ARB);
- glEnable(GL_TEXTURE_2D);
- glGenTextures(1,
&s_edge_texture_id);
- glBindTexture(GL_TEXTURE_2D,
s_edge_texture_id);
-
- glTexParameteri(GL_TEXTURE_2D,
GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D,
GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D,
GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D,
GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-
- glTexImage2D(GL_TEXTURE_2D, 0,
GL_RGBA, 2, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, edge_data);
-
- glTexEnvf(GL_TEXTURE_ENV,
GL_TEXTURE_ENV_MODE, GL_MODULATE); // @@ should we use a 1D texture???
-
- glDisable(GL_TEXTURE_2D);
-
ogl::active_texture(GL_TEXTURE0_ARB);
- glDisable(GL_TEXTURE_2D);
- }
- }
- #endif // 0
+// #if 0
+// // See if we want to, and can, use multitexture
+// // antialiasing.
+// s_multitexture_antialias = false;
+// if (m_enable_antialias)
+// {
+// int tex_units = 0;
+// glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB,
&tex_units);
+// if (tex_units >= 2)
+// {
+// s_multitexture_antialias = true;
+// }
+
+// // Make sure we have an edge texture
available.
+// if (s_multitexture_antialias == true
+// && s_edge_texture_id == 0)
+// {
+// // Very simple texture: 2
texels wide, 1 texel high.
+// // Both texels are white; left
texel is all clear, right texel is all opaque.
+// unsigned char edge_data[8] =
{ 255, 255, 255, 0, 255, 255, 255, 255 };
+
+//
ogl::active_texture(GL_TEXTURE1_ARB);
+// glEnable(GL_TEXTURE_2D);
+// glGenTextures(1,
&s_edge_texture_id);
+// glBindTexture(GL_TEXTURE_2D,
s_edge_texture_id);
+
+// glTexParameteri(GL_TEXTURE_2D,
GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+// glTexParameteri(GL_TEXTURE_2D,
GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+// glTexParameteri(GL_TEXTURE_2D,
GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+// glTexParameteri(GL_TEXTURE_2D,
GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+// glTexImage2D(GL_TEXTURE_2D, 0,
GL_RGBA, 2, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, edge_data);
+
+// glTexEnvf(GL_TEXTURE_ENV,
GL_TEXTURE_ENV_MODE, GL_MODULATE); // @@ should we use a 1D texture???
+
+// glDisable(GL_TEXTURE_2D);
+//
ogl::active_texture(GL_TEXTURE0_ARB);
+// glDisable(GL_TEXTURE_2D);
+// }
+// }
+// #endif // 0
}
Index: gnash/doc/omf.make
diff -u gnash/doc/omf.make:1.6 gnash/doc/omf.make:1.7
--- gnash/doc/omf.make:1.6 Thu Feb 9 15:15:28 2006
+++ gnash/doc/omf.make Sun Feb 26 15:49:29 2006
@@ -33,7 +33,7 @@
omf_timestamp: $(omffile)
@for file in $(omffile); do \
- $(SCROLLINSTALL) $(docdir)/$(docname).xml $(srcdir)/$$file
$(srcdir)/$$file.out; \
+ $(SCROLLINSTALL) $(docdir)/$(docname).xml $(srcdir)/$$file
$$file.out; \
done
touch omf_timestamp
@@ -41,7 +41,7 @@
if GHELP
$(mkinstalldirs) $(DESTDIR)$(omf_dest_dir)
for file in $(omffile); do \
- $(INSTALL_DATA) $(srcdir)/$$file.out
$(DESTDIR)$(omf_dest_dir)/$$file; \
+ $(INSTALL_DATA) $$file.out $(DESTDIR)$(omf_dest_dir)/$$file; \
done
if test x"$(USER)" = x"root" ; then \
$(SCROLLUPDATE) -v -p $(DESTDIR)$(scrollkeeper_localstate_dir) -o
$(DESTDIR)$(omf_dest_dir);\
Index: gnash/libamf/Makefile.am
diff -u gnash/libamf/Makefile.am:1.2 gnash/libamf/Makefile.am:1.3
--- gnash/libamf/Makefile.am:1.2 Mon Feb 13 17:48:28 2006
+++ gnash/libamf/Makefile.am Sun Feb 26 15:49:29 2006
@@ -31,16 +31,15 @@
$(PNG_LIBS) \
$(LIBXML_LIBS) \
$(DMALLOC_LIBS) \
- $(MP3_LIBS) \
+ $(MAD_LIBS) \
$(OGG_LIBS)
# AM_LDFLAGS = $(OPENGL_LIBNS) $(SDL_LIBS)
lib_LTLIBRARIES = libgnashamf.la
-libgnashamf_la_SOURCES = amf.cpp
-
-noinst_HEADERS = amf.h
+libgnashamf_la_SOURCES = amf.cpp amfutf8.h amf.h
+# noinst_HEADERS = amf.h amfutf8.h
INCLUDES = -I.. -I$(srcdir) \
-I$(top_srcdir)/server
Index: gnash/libbase/Makefile.am
diff -u gnash/libbase/Makefile.am:1.11 gnash/libbase/Makefile.am:1.12
--- gnash/libbase/Makefile.am:1.11 Fri Feb 3 20:50:27 2006
+++ gnash/libbase/Makefile.am Sun Feb 26 15:49:29 2006
@@ -36,9 +36,10 @@
endif
INCLUDES = -I.. -I$(srcdir) \
- $(LIBPNG_INCLUDE) \
- $(ZLIB_INCLUDE) \
- $(JPEGLIB_INCLUDE) \
+ $(PTHREAD_CFLAGS) \
+ $(PNG_CFLAGS) \
+ $(ZLIB_CFLAGS) \
+ $(JPEG_CFLAGS) \
$(LIBXML_CFLAGS) \
$(OPENGL_CFLAGS) \
-I$(top_srcdir)
Index: gnash/libbase/component_hackery.cpp
diff -u gnash/libbase/component_hackery.cpp:1.1
gnash/libbase/component_hackery.cpp:1.2
--- gnash/libbase/component_hackery.cpp:1.1 Tue Dec 20 20:57:00 2005
+++ gnash/libbase/component_hackery.cpp Sun Feb 26 15:49:29 2006
@@ -1,47 +1,47 @@
-// Thatcher Ulrich <address@hidden> 2003 -*- coding: utf-8;-*-
-
-// This source code has been donated to the Public Domain. Do
-// whatever you want with it.
-
-
-#include <vector>
-
-
-class Component {
-// typedef vector<Component>::iterator;
-
- template< class interface >
- class iterator {
-
-
- operator++()
- {
- }
- };
-};
-
-
-class SpecialInterface : public Component {
- void DoStuff()
- {
- printf( "doing stuff.\n" );
- }
-};
-
-
-class Actor {
-
-};
-
-
-#define foreach( _decl, _p, _actor ) \
- for ( _decl _p, Component::iterator _i( _p ) =
_actor.components.get_first( _p ); _i != _actor.components.end(); ++ _i, _p =
*_i )
-
-
-
-foreach(SpecialInterface*, p, actors)
-{
- p->DoStuff();
- some_list.push_back( p );
-}
-
+// Thatcher Ulrich <address@hidden> 2003 -*- coding: utf-8;-*-
+
+// This source code has been donated to the Public Domain. Do
+// whatever you want with it.
+
+
+#include <vector>
+
+
+class Component {
+// typedef vector<Component>::iterator;
+
+ template< class interface >
+ class iterator {
+
+
+ operator++()
+ {
+ }
+ };
+};
+
+
+class SpecialInterface : public Component {
+ void DoStuff()
+ {
+ printf( "doing stuff.\n" );
+ }
+};
+
+
+class Actor {
+
+};
+
+
+#define foreach( _decl, _p, _actor ) \
+ for ( _decl _p, Component::iterator _i( _p ) =
_actor.components.get_first( _p ); _i != _actor.components.end(); ++ _i, _p =
*_i )
+
+
+
+foreach(SpecialInterface*, p, actors)
+{
+ p->DoStuff();
+ some_list.push_back( p );
+}
+
Index: gnash/libbase/config.cpp
diff -u gnash/libbase/config.cpp:1.1 gnash/libbase/config.cpp:1.2
--- gnash/libbase/config.cpp:1.1 Tue Dec 20 20:57:00 2005
+++ gnash/libbase/config.cpp Sun Feb 26 15:49:29 2006
@@ -1,449 +1,449 @@
-// config.cpp -- by Thatcher Ulrich <address@hidden> 22 July 2001
-
-// This source code has been donated to the Public Domain. Do
-// whatever you want with it.
-
-// Configuration glue. C++ interface to Lua scripting library.
-
-// @@ move/finish this later...
-#if 0
-
-
-#include "config.h"
-extern "C" {
-#include <lualib.h>
-}
-#include "utility.h"
-
-
-namespace config {
-
-
-static const int LUA_STACK_SIZE = 2048;
-
-
-static bool s_open = false;
-
-lua_State* L = NULL;
-int g_cfloat_tag = 0;
-
-
-static int cfloat_get( lua_State* L )
-// Lua CFunction which returns the value of the cfloat passed in on
-// the top of the Lua stack. Attach this to the "getglobal" event for
-// cfloats.
-{
- // arg 1: varname
- // arg 2: raw var value (in this case the cfloat*)
-
- cfloat* cf = static_cast<cfloat*>( lua_touserdata( L, 2 ) );
- lua_pushnumber( L, float( *cf ) );
-
- return 1;
-}
-
-
-static int cfloat_set( lua_State* L )
-// Lua CFunction which sets the value of the given cfloat to the given lua
-// number.
-{
- // arg 1: varname
- // arg 2: previous var value (in this case the cfloat*)
- // arg 3: new var value
-
- cfloat* cf = static_cast<cfloat*>( lua_touserdata( L, 2 ) );
- *cf = float(lua_tonumber( L, 3 ));
-
- return 0;
-}
-
-
-void open()
-// Initialize the config subsystem. ...
-{
- if ( s_open == true ) return;
-
- //
- // Initialize Lua.
- //
- L = lua_open( LUA_STACK_SIZE );
-
- // Init the standard Lua libs.
- lua_baselibopen( L );
- lua_iolibopen( L );
- lua_strlibopen( L );
- lua_mathlibopen( L );
-
- //
- // Attach the cfloat hooks
- //
-
- g_cfloat_tag = lua_newtag( config::L );
-
- lua_pushcfunction( config::L, cfloat_get );
- lua_settagmethod( config::L, config::g_cfloat_tag, "getglobal" );
// xxx is "getglobal" right?
-
- lua_pushcfunction( config::L, cfloat_set );
- lua_settagmethod( config::L, config::g_cfloat_tag, "setglobal" );
// xxx is "setglobal" right?
-
- // set tag methods for add, sub, mul, div, pow, unm, lt
-
- // gettable{ min, max, default, comment }
- // settable{ min, max, default, comment }
-
- s_open = true;
-}
-
-
-void close()
-// Close the config subsystem.
-{
- // Nothing really to do here.
-}
-
-
-}; // end namespace config
-
-
-
-//
-// cvar
-//
-
-
-void cvar::init( const char* name )
-// Initializes a chain of references to Lua strings, for looking up
-// the value of the specified name.
-//
-// The name can contain embedded '.' separators, to refer to values
-// within nested tables. For example, a name of
-// "player.spaceship.health" would refer to the "health" member of the
-// "player.spaceship" table (where the "player.spaceship" table is
-// found by looking up the "spaceship" member of the "player" table).
-{
- config::open();
-
- // Count the number of keys in the name (keys are separated by '.'
- // chars).
- m_lua_key_count = 1;
- const char* p = name;
- while (*p) {
- if (*p == '.') {
- m_lua_key_count++;
- }
- p++;
- }
-
- // Allocate array for references.
- m_lua_key_reference = new int[m_lua_key_count];
-
- // Now initialize the keys.
- const char* varname = name;
-
- int key_index = 0;
- p = name;
- while (*p) {
- if (*p == '.') {
- if (varname == p) {
- // null string for a key.
- // warning("something or other");
- assert(0); // TODO: recover somehow.
- }
-
- // Reference the name of the table.
- lua_pushlstring(config::L, varname, p - varname);
- m_lua_key_reference[key_index] = lua_ref(config::L, 1);
-
- key_index++;
- varname = p + 1;
- }
- p++;
- }
-
- // Get a reference to the last key name.
- assert(varname != p); // else...
- lua_pushlstring(config::L, varname, p - varname);
- m_lua_key_reference[key_index] = lua_ref(config::L, 1);
-}
-
-
-void cvar::push_table_and_key() const
-// Traverse our key names, and push the table and keyname of our value
-// onto the Lua stack.
-//
-// Creates empty tables if necessary to fill in missing links in the
-// chain.
-{
- lua_getglobals(config::L); // Start with the global table.
-
- // Chain through additional tables.
- int i;
- for (i = 0; i < m_lua_key_count - 1; i++) {
- lua_getref(config::L, m_lua_key_reference[i]);
- lua_gettable(config::L, -2);
-
- if (lua_isnil(config::L, -1)) {
- // Tablename is undefined, so create a new empty table
for it.
- lua_pop(config::L, 1); // pop the nil.
- lua_getref(config::L, m_lua_key_reference[i]);
- lua_newtable(config::L);
- lua_settable(config::L, -3);
-
- // Get the newly created table and put it on the top
- // of stack.
- lua_getref(config::L, m_lua_key_reference[i]);
- lua_gettable(config::L, -2);
- }
-
- lua_remove(config::L, -2); // previous table that we just
chained from
- }
-
- // push the final key, on top of the table we just pushed.
- lua_getref(config::L, m_lua_key_reference[i]);
-}
-
-
-cvar::cvar( const char* name )
-// Constructor; leaves existing value, if any (otherwise it's 'nil').
-{
- init(name);
-}
-
-
-cvar::cvar( const char* name, const cvalue& val )
-// Constructor; initializes to given Lua value.
-{
- init(name);
- *this = val; // invoke operator=(const cvalue& val)
-}
-
-
-cvar::cvar( const char* name, const char* val )
-// Constructor; initializes to given string value.
-{
- init(name);
- *this = val; // invoke operator=(const char*)
-}
-
-
-cvar::cvar( const char* name, float val )
-// Constructor; initializes to given float value.
-{
- init(name);
- *this = val; // invoke operator=(float f)
-}
-
-
-cvar::~cvar()
-// Destructor; make sure our references are released.
-{
- // drop lua references, so table & name can be gc'd if not
- // referenced elsewhere.
-
- for (int i = 0; i < m_lua_key_count; i++) {
- lua_unref(config::L, m_lua_key_reference[i]);
- }
-
- m_lua_key_count = 0;
- m_lua_key_reference = NULL;
-}
-
-
-#if 0
-const char* cvar::get_name() const
-// Return our name. The char[] storage is valid at least as long
-// as this variable is alive.
-{
- lua_getref( config::L, m_lua_name_reference );
- return lua_tostring( config::L, -1 );
-}
-#endif // 0
-
-
-cvar::operator float() const
-// Convert the variable to a float and return it.
-{
- push_table_and_key();
- lua_gettable( config::L, -2 ); // get the value of our variable from
the table.
- float f = float(lua_tonumber( config::L, -1 ));
- lua_pop( config::L, 2 ); // pop table & the number result.
-
- return f;
-}
-
-
-void cvar::operator=( float f )
-// Assign a float to this lua variable.
-{
- push_table_and_key();
- lua_pushnumber( config::L, f );
- lua_settable( config::L, -3 );
- lua_pop( config::L, 1 ); // pop the table.
-}
-
-
-cvar::operator const char*() const
-// Convert to a string.
-//
-// xxx there are garbage-collection issues here! Returned string
-// has no valid reference once stack is cleared!
-// Possible fixes:
-// - return some kind of proxy object that holds a locked Lua ref
-// - return a C++ "string" value; i.e. make a copy
-// - hold a locked reference in this instance; drop it on next call to this
conversion operator (blech).
-{
- push_table_and_key();
- lua_gettable( config::L, -2 ); // get the value of our variable from
the table.
- const char* c = lua_tostring( config::L, -1 );
- // TODO: grab a locked reference to the string! Or copy it!
- lua_pop( config::L, 2 ); // discard table & the string result.
-
- return c;
-}
-
-
-void cvar::operator=( const cvalue& val )
-// Assign a Lua value to this lua global variable.
-{
- push_table_and_key();
- val.lua_push();
- lua_settable( config::L, -3 );
- lua_pop( config::L, 1 ); // pop the table.
-}
-
-
-void cvar::operator=( const char* s )
-// Assign a string to this lua variable.
-{
- push_table_and_key();
- lua_pushstring( config::L, s );
- lua_settable( config::L, -3 );
- lua_pop( config::L, 1 ); // pop the table.
-}
-
-
-cvar::operator cvalue() const
-// Return a reference to our value.
-{
- push_table_and_key();
- cvalue c = cvalue::lua_stacktop_reference();
- lua_pop( config::L, 1 ); // pop the table.
-
- return c;
-}
-
-
-// void operator=( const cvar c );
-
-
-
-//
-// cvalue
-//
-
-
-cvalue::cvalue( const char* lua_constructor )
-// Evaluates the given code and takes a reference to the result.
-{
- config::open();
-
- lua_dostring( config::L, lua_constructor ); // @@ could check for
error return codes, presence of return value, etc.
- m_lua_ref = lua_ref( config::L, 1 );
-}
-
-
-cvalue::cvalue( const cvalue& c )
-{
- lua_getref( config::L, c.m_lua_ref );
- m_lua_ref = lua_ref( config::L, 1 );
-}
-
-
-cvalue::cvalue()
-// Creates an reference to nothing. Use this only in special
-// circumstances; i.e. when you're about to set m_lua_ref manually.
-{
- config::open();
- m_lua_ref = LUA_NOREF;
-}
-
-
-cvalue cvalue::lua_stacktop_reference()
-// Factory function; pops the value off the top of the Lua stack, and
-// return a cvalue that references the popped value.
-{
- cvalue c;
- c.m_lua_ref = lua_ref( config::L, 1 );
- return c;
-}
-
-
-cvalue::~cvalue()
-// Drop our Lua reference, to allow our value to be gc'd.
-{
- lua_unref( config::L, m_lua_ref );
- m_lua_ref = LUA_NOREF;
-}
-
-
-void cvalue::lua_push() const
-// Push our value onto the top of the Lua stack.
-{
- assert( m_lua_ref != LUA_NOREF );
- lua_getref( config::L, m_lua_ref );
-}
-
-
-void cvalue::operator=( const char* str )
-// Transfer our reference to the given string.
-{
- lua_unref( config::L, m_lua_ref );
- lua_pushstring( config::L, str );
- m_lua_ref = lua_ref( config::L, 1 );
-}
-
-
-void cvalue::operator=( const cvalue& c )
-// Reference the thing that c references.
-{
- lua_unref( config::L, m_lua_ref );
- lua_getref( config::L, c.m_lua_ref );
- m_lua_ref = lua_ref( config::L, 1 );
-}
-
-
-cvalue::operator float() const
-// Converts this Lua value to a number, and returns it.
-{
- lua_getref( config::L, m_lua_ref );
- float f = float(lua_tonumber( config::L, -1 ));
- lua_pop( config::L, 1 );
- return f;
-}
-
-
-cvalue::operator const char*() const
-// Converts this Lua value to a string, and returns it.
-{
- lua_getref( config::L, m_lua_ref );
- const char* str = lua_tostring( config::L, -1 );
- lua_pop( config::L, 1 ); // @@ I'm pretty sure this imperils the
string, if we just had to do a tostring() conversion! Look into this, and/or
make a copy of the string.
- return str;
-}
-
-
-cvalue cvalue::get( const char* index )
-// Does a table lookup. *this should be a Lua table, and index is its
-// key.
-{
- lua_getref( config::L, m_lua_ref );
- lua_pushstring( config::L, index );
- lua_gettable( config::L, -2 );
- cvalue c = cvalue::lua_stacktop_reference(); // references the value
on the top of the Lua stack.
- lua_pop( config::L, 1 );
-
- return c;
-}
-
-
-#endif // 0
+// config.cpp -- by Thatcher Ulrich <address@hidden> 22 July 2001
+
+// This source code has been donated to the Public Domain. Do
+// whatever you want with it.
+
+// Configuration glue. C++ interface to Lua scripting library.
+
+// @@ move/finish this later...
+#if 0
+
+
+#include "config.h"
+extern "C" {
+#include <lualib.h>
+}
+#include "utility.h"
+
+
+namespace config {
+
+
+static const int LUA_STACK_SIZE = 2048;
+
+
+static bool s_open = false;
+
+lua_State* L = NULL;
+int g_cfloat_tag = 0;
+
+
+static int cfloat_get( lua_State* L )
+// Lua CFunction which returns the value of the cfloat passed in on
+// the top of the Lua stack. Attach this to the "getglobal" event for
+// cfloats.
+{
+ // arg 1: varname
+ // arg 2: raw var value (in this case the cfloat*)
+
+ cfloat* cf = static_cast<cfloat*>( lua_touserdata( L, 2 ) );
+ lua_pushnumber( L, float( *cf ) );
+
+ return 1;
+}
+
+
+static int cfloat_set( lua_State* L )
+// Lua CFunction which sets the value of the given cfloat to the given lua
+// number.
+{
+ // arg 1: varname
+ // arg 2: previous var value (in this case the cfloat*)
+ // arg 3: new var value
+
+ cfloat* cf = static_cast<cfloat*>( lua_touserdata( L, 2 ) );
+ *cf = float(lua_tonumber( L, 3 ));
+
+ return 0;
+}
+
+
+void open()
+// Initialize the config subsystem. ...
+{
+ if ( s_open == true ) return;
+
+ //
+ // Initialize Lua.
+ //
+ L = lua_open( LUA_STACK_SIZE );
+
+ // Init the standard Lua libs.
+ lua_baselibopen( L );
+ lua_iolibopen( L );
+ lua_strlibopen( L );
+ lua_mathlibopen( L );
+
+ //
+ // Attach the cfloat hooks
+ //
+
+ g_cfloat_tag = lua_newtag( config::L );
+
+ lua_pushcfunction( config::L, cfloat_get );
+ lua_settagmethod( config::L, config::g_cfloat_tag, "getglobal" );
// xxx is "getglobal" right?
+
+ lua_pushcfunction( config::L, cfloat_set );
+ lua_settagmethod( config::L, config::g_cfloat_tag, "setglobal" );
// xxx is "setglobal" right?
+
+ // set tag methods for add, sub, mul, div, pow, unm, lt
+
+ // gettable{ min, max, default, comment }
+ // settable{ min, max, default, comment }
+
+ s_open = true;
+}
+
+
+void close()
+// Close the config subsystem.
+{
+ // Nothing really to do here.
+}
+
+
+}; // end namespace config
+
+
+
+//
+// cvar
+//
+
+
+void cvar::init( const char* name )
+// Initializes a chain of references to Lua strings, for looking up
+// the value of the specified name.
+//
+// The name can contain embedded '.' separators, to refer to values
+// within nested tables. For example, a name of
+// "player.spaceship.health" would refer to the "health" member of the
+// "player.spaceship" table (where the "player.spaceship" table is
+// found by looking up the "spaceship" member of the "player" table).
+{
+ config::open();
+
+ // Count the number of keys in the name (keys are separated by '.'
+ // chars).
+ m_lua_key_count = 1;
+ const char* p = name;
+ while (*p) {
+ if (*p == '.') {
+ m_lua_key_count++;
+ }
+ p++;
+ }
+
+ // Allocate array for references.
+ m_lua_key_reference = new int[m_lua_key_count];
+
+ // Now initialize the keys.
+ const char* varname = name;
+
+ int key_index = 0;
+ p = name;
+ while (*p) {
+ if (*p == '.') {
+ if (varname == p) {
+ // null string for a key.
+ // warning("something or other");
+ assert(0); // TODO: recover somehow.
+ }
+
+ // Reference the name of the table.
+ lua_pushlstring(config::L, varname, p - varname);
+ m_lua_key_reference[key_index] = lua_ref(config::L, 1);
+
+ key_index++;
+ varname = p + 1;
+ }
+ p++;
+ }
+
+ // Get a reference to the last key name.
+ assert(varname != p); // else...
+ lua_pushlstring(config::L, varname, p - varname);
+ m_lua_key_reference[key_index] = lua_ref(config::L, 1);
+}
+
+
+void cvar::push_table_and_key() const
+// Traverse our key names, and push the table and keyname of our value
+// onto the Lua stack.
+//
+// Creates empty tables if necessary to fill in missing links in the
+// chain.
+{
+ lua_getglobals(config::L); // Start with the global table.
+
+ // Chain through additional tables.
+ int i;
+ for (i = 0; i < m_lua_key_count - 1; i++) {
+ lua_getref(config::L, m_lua_key_reference[i]);
+ lua_gettable(config::L, -2);
+
+ if (lua_isnil(config::L, -1)) {
+ // Tablename is undefined, so create a new empty table
for it.
+ lua_pop(config::L, 1); // pop the nil.
+ lua_getref(config::L, m_lua_key_reference[i]);
+ lua_newtable(config::L);
+ lua_settable(config::L, -3);
+
+ // Get the newly created table and put it on the top
+ // of stack.
+ lua_getref(config::L, m_lua_key_reference[i]);
+ lua_gettable(config::L, -2);
+ }
+
+ lua_remove(config::L, -2); // previous table that we just
chained from
+ }
+
+ // push the final key, on top of the table we just pushed.
+ lua_getref(config::L, m_lua_key_reference[i]);
+}
+
+
+cvar::cvar( const char* name )
+// Constructor; leaves existing value, if any (otherwise it's 'nil').
+{
+ init(name);
+}
+
+
+cvar::cvar( const char* name, const cvalue& val )
+// Constructor; initializes to given Lua value.
+{
+ init(name);
+ *this = val; // invoke operator=(const cvalue& val)
+}
+
+
+cvar::cvar( const char* name, const char* val )
+// Constructor; initializes to given string value.
+{
+ init(name);
+ *this = val; // invoke operator=(const char*)
+}
+
+
+cvar::cvar( const char* name, float val )
+// Constructor; initializes to given float value.
+{
+ init(name);
+ *this = val; // invoke operator=(float f)
+}
+
+
+cvar::~cvar()
+// Destructor; make sure our references are released.
+{
+ // drop lua references, so table & name can be gc'd if not
+ // referenced elsewhere.
+
+ for (int i = 0; i < m_lua_key_count; i++) {
+ lua_unref(config::L, m_lua_key_reference[i]);
+ }
+
+ m_lua_key_count = 0;
+ m_lua_key_reference = NULL;
+}
+
+
+#if 0
+const char* cvar::get_name() const
+// Return our name. The char[] storage is valid at least as long
+// as this variable is alive.
+{
+ lua_getref( config::L, m_lua_name_reference );
+ return lua_tostring( config::L, -1 );
+}
+#endif // 0
+
+
+cvar::operator float() const
+// Convert the variable to a float and return it.
+{
+ push_table_and_key();
+ lua_gettable( config::L, -2 ); // get the value of our variable from
the table.
+ float f = float(lua_tonumber( config::L, -1 ));
+ lua_pop( config::L, 2 ); // pop table & the number result.
+
+ return f;
+}
+
+
+void cvar::operator=( float f )
+// Assign a float to this lua variable.
+{
+ push_table_and_key();
+ lua_pushnumber( config::L, f );
+ lua_settable( config::L, -3 );
+ lua_pop( config::L, 1 ); // pop the table.
+}
+
+
+cvar::operator const char*() const
+// Convert to a string.
+//
+// xxx there are garbage-collection issues here! Returned string
+// has no valid reference once stack is cleared!
+// Possible fixes:
+// - return some kind of proxy object that holds a locked Lua ref
+// - return a C++ "string" value; i.e. make a copy
+// - hold a locked reference in this instance; drop it on next call to this
conversion operator (blech).
+{
+ push_table_and_key();
+ lua_gettable( config::L, -2 ); // get the value of our variable from
the table.
+ const char* c = lua_tostring( config::L, -1 );
+ // TODO: grab a locked reference to the string! Or copy it!
+ lua_pop( config::L, 2 ); // discard table & the string result.
+
+ return c;
+}
+
+
+void cvar::operator=( const cvalue& val )
+// Assign a Lua value to this lua global variable.
+{
+ push_table_and_key();
+ val.lua_push();
+ lua_settable( config::L, -3 );
+ lua_pop( config::L, 1 ); // pop the table.
+}
+
+
+void cvar::operator=( const char* s )
+// Assign a string to this lua variable.
+{
+ push_table_and_key();
+ lua_pushstring( config::L, s );
+ lua_settable( config::L, -3 );
+ lua_pop( config::L, 1 ); // pop the table.
+}
+
+
+cvar::operator cvalue() const
+// Return a reference to our value.
+{
+ push_table_and_key();
+ cvalue c = cvalue::lua_stacktop_reference();
+ lua_pop( config::L, 1 ); // pop the table.
+
+ return c;
+}
+
+
+// void operator=( const cvar c );
+
+
+
+//
+// cvalue
+//
+
+
+cvalue::cvalue( const char* lua_constructor )
+// Evaluates the given code and takes a reference to the result.
+{
+ config::open();
+
+ lua_dostring( config::L, lua_constructor ); // @@ could check for
error return codes, presence of return value, etc.
+ m_lua_ref = lua_ref( config::L, 1 );
+}
+
+
+cvalue::cvalue( const cvalue& c )
+{
+ lua_getref( config::L, c.m_lua_ref );
+ m_lua_ref = lua_ref( config::L, 1 );
+}
+
+
+cvalue::cvalue()
+// Creates an reference to nothing. Use this only in special
+// circumstances; i.e. when you're about to set m_lua_ref manually.
+{
+ config::open();
+ m_lua_ref = LUA_NOREF;
+}
+
+
+cvalue cvalue::lua_stacktop_reference()
+// Factory function; pops the value off the top of the Lua stack, and
+// return a cvalue that references the popped value.
+{
+ cvalue c;
+ c.m_lua_ref = lua_ref( config::L, 1 );
+ return c;
+}
+
+
+cvalue::~cvalue()
+// Drop our Lua reference, to allow our value to be gc'd.
+{
+ lua_unref( config::L, m_lua_ref );
+ m_lua_ref = LUA_NOREF;
+}
+
+
+void cvalue::lua_push() const
+// Push our value onto the top of the Lua stack.
+{
+ assert( m_lua_ref != LUA_NOREF );
+ lua_getref( config::L, m_lua_ref );
+}
+
+
+void cvalue::operator=( const char* str )
+// Transfer our reference to the given string.
+{
+ lua_unref( config::L, m_lua_ref );
+ lua_pushstring( config::L, str );
+ m_lua_ref = lua_ref( config::L, 1 );
+}
+
+
+void cvalue::operator=( const cvalue& c )
+// Reference the thing that c references.
+{
+ lua_unref( config::L, m_lua_ref );
+ lua_getref( config::L, c.m_lua_ref );
+ m_lua_ref = lua_ref( config::L, 1 );
+}
+
+
+cvalue::operator float() const
+// Converts this Lua value to a number, and returns it.
+{
+ lua_getref( config::L, m_lua_ref );
+ float f = float(lua_tonumber( config::L, -1 ));
+ lua_pop( config::L, 1 );
+ return f;
+}
+
+
+cvalue::operator const char*() const
+// Converts this Lua value to a string, and returns it.
+{
+ lua_getref( config::L, m_lua_ref );
+ const char* str = lua_tostring( config::L, -1 );
+ lua_pop( config::L, 1 ); // @@ I'm pretty sure this imperils the
string, if we just had to do a tostring() conversion! Look into this, and/or
make a copy of the string.
+ return str;
+}
+
+
+cvalue cvalue::get( const char* index )
+// Does a table lookup. *this should be a Lua table, and index is its
+// key.
+{
+ lua_getref( config::L, m_lua_ref );
+ lua_pushstring( config::L, index );
+ lua_gettable( config::L, -2 );
+ cvalue c = cvalue::lua_stacktop_reference(); // references the value
on the top of the Lua stack.
+ lua_pop( config::L, 1 );
+
+ return c;
+}
+
+
+#endif // 0
Index: gnash/libbase/container.cpp
diff -u gnash/libbase/container.cpp:1.2 gnash/libbase/container.cpp:1.3
--- gnash/libbase/container.cpp:1.2 Sat Feb 25 15:27:35 2006
+++ gnash/libbase/container.cpp Sun Feb 26 15:49:29 2006
@@ -1,700 +1,700 @@
-// container.cpp -- Thatcher Ulrich <address@hidden> 2003
-
-// This source code has been donated to the Public Domain. Do
-// whatever you want with it.
-
-// Some non-inline implementation help for generic containers.
-
-
-#include "container.h"
-#include "utf8.h"
-#include "tu_random.h"
-#include <stdarg.h>
-
-
-void tu_string::append_wide_char(uint16 c)
-{
- char buf[8];
- int index = 0;
- utf8::encode_unicode_character(buf, &index, (uint32) c);
- buf[index] = 0;
-
- *this += buf;
-}
-
-
-void tu_string::append_wide_char(uint32 c)
-{
- char buf[8];
- int index = 0;
- utf8::encode_unicode_character(buf, &index, c);
- buf[index] = 0;
-
- *this += buf;
-}
-
-
-void tu_string::resize(int new_size)
-{
- assert(new_size >= 0);
-
- if (using_heap() == false)
- {
- if (new_size < 15)
- {
- // Stay with internal storage.
- m_local.m_size = (char) (new_size + 1);
- m_local.m_buffer[new_size] = 0; // terminate
- }
- else
- {
- // need to allocate heap buffer.
- int capacity = new_size + 1;
- // round up.
- capacity = (capacity + 15) & ~15;
- char* buf = (char*) tu_malloc(capacity);
- memset(buf, 0, capacity);
-
- // Copy existing data.
- strcpy(buf, m_local.m_buffer);
-
- // Set the heap state.
- m_heap.m_buffer = buf;
- m_heap.m_all_ones = char(~0);
- m_heap.m_size = new_size + 1;
- m_heap.m_capacity = capacity;
- }
- }
- else
- {
- // Currently using heap storage.
- if (new_size < 15)
- {
- // Switch to local storage.
-
- // Be sure to get stack copies of m_heap info, before
we overwrite it.
- char* old_buffer = m_heap.m_buffer;
- int old_capacity = m_heap.m_capacity;
- UNUSED(old_capacity);
-
- // Copy existing string info.
- m_local.m_size = (char) (new_size + 1);
- strncpy(m_local.m_buffer, old_buffer, 15);
- m_local.m_buffer[new_size] = 0; // ensure termination.
-
- tu_free(old_buffer, old_capacity);
- }
- else
- {
- // Changing size of heap buffer.
- int capacity = new_size + 1;
- // Round up.
- capacity = (capacity + 15) & ~15;
- if (capacity != m_heap.m_capacity) // @@ TODO
should use hysteresis when resizing
- {
- m_heap.m_buffer = (char*)
tu_realloc(m_heap.m_buffer, capacity, m_heap.m_capacity);
- m_heap.m_capacity = capacity;
- }
- // else we're OK with existing buffer.
-
- m_heap.m_size = new_size + 1;
-
- // Ensure termination.
- m_heap.m_buffer[new_size] = 0;
- }
- }
-}
-
-
-template<class char_type>
-/*static*/ void encode_utf8_from_wchar_generic(tu_string* result, const
char_type* wstr)
-{
- const char_type* in = wstr;
-
- // First pass: compute the necessary string length.
- int bytes_needed = 0;
- char dummy[10];
- int offset;
- for (;;)
- {
- Uint32 uc = *in++;
- offset = 0;
- utf8::encode_unicode_character(dummy, &offset, uc);
- bytes_needed += offset;
-
- assert(offset <= 6);
-
- if (uc == 0)
- {
- break;
- }
- }
-
- // Second pass: transfer the data.
- result->resize(bytes_needed - 1); // resize() adds 1 for the \0
terminator
- in = wstr;
- char* out = &((*result)[0]);
- offset = 0;
- for (;;)
- {
- assert(offset < bytes_needed);
-
- Uint32 uc = *in++;
- utf8::encode_unicode_character(out, &offset, uc);
-
- assert(offset <= bytes_needed);
-
- if (uc == 0)
- {
- break;
- }
- }
-
- assert(offset == bytes_needed);
- assert((*result)[offset - 1] == 0);
- assert(result->length() == (int) strlen(result->c_str()));
-}
-
-
-void tu_string::encode_utf8_from_wchar(tu_string* result, const uint32* wstr)
-{
- encode_utf8_from_wchar_generic<uint32>(result, wstr);
-}
-
-
-void tu_string::encode_utf8_from_wchar(tu_string* result, const uint16* wstr)
-{
- encode_utf8_from_wchar_generic<uint16>(result, wstr);
-}
-
-
-/*static*/ int tu_string::stricmp(const char* a, const char* b)
-{
-#ifdef _WIN32
- return ::stricmp(a, b);
-#else
- return strcasecmp(a, b);
-#endif
-}
-
-
-uint32 tu_string::utf8_char_at(int index) const
-{
- const char* buf = get_buffer();
- uint32 c;
-
- do
- {
- c = utf8::decode_next_unicode_character(&buf);
- index--;
-
- if (c == 0)
- {
- // We've hit the end of the string; don't go further.
- assert(index == 0);
- return c;
- }
- }
- while (index >= 0);
-
- return c;
-}
-
-
-tu_string tu_string::utf8_to_upper() const
-{
- const char* buf = get_buffer();
- tu_string str;
- for (;;)
- {
- uint32 c = utf8::decode_next_unicode_character(&buf);
-
- if (c == 0)
- {
- // We've hit the end of the string; don't go further.
- return str;
- }
- str += toupper(c);
- }
-
- return str;
-}
-
-
-tu_string tu_string::utf8_to_lower() const
-{
- const char* buf = get_buffer();
- tu_string str;
- for (;;)
- {
- uint32 c = utf8::decode_next_unicode_character(&buf);
-
- if (c == 0) {
- // We've hit the end of the string; don't go further.
- return str;
- }
- str += tolower(c);
- }
-
- return str;
-}
-
-
-/*static*/ int tu_string::utf8_char_count(const char* buf, int buflen)
-{
- const char* p = buf;
- int length = 0;
-
- while (p - buf < buflen)
- {
- uint32 c = utf8::decode_next_unicode_character(&p);
- if (c == 0)
- {
- break;
- }
-
- length++;
- }
-
- return length;
-}
-
-
-tu_string tu_string::utf8_substring(int start, int end) const
-{
- assert(start <= end);
-
- if (start == end)
- {
- // Special case, always return empty string.
- return tu_string();
- }
-
- const char* p = get_buffer();
- int index = 0;
- const char* start_pointer = p;
- const char* end_pointer = p;
-
- for (;;)
- {
- if (index == start)
- {
- start_pointer = p;
- }
-
- uint32 c = utf8::decode_next_unicode_character(&p);
- index++;
-
- if (index == end)
- {
- end_pointer = p;
- break;
- }
-
- if (c == 0)
- {
- if (index < end)
- {
- assert(0);
- end_pointer = p;
- }
- break;
- }
- }
-
- if (end_pointer < start_pointer)
- {
- end_pointer = start_pointer;
- }
-
- return tu_string(start_pointer, end_pointer - start_pointer);
-}
-
-
-#ifdef _WIN32
-#define vsnprintf _vsnprintf
-#endif // _WIN32
-
-tu_string string_printf(const char* fmt, ...)
-// Handy sprintf wrapper.
-{
- static const int BUFFER_SIZE = 500;
- char s_buffer[BUFFER_SIZE];
-
- va_list ap;
- va_start(ap, fmt);
- vsnprintf(s_buffer, BUFFER_SIZE, fmt, ap);
- va_end(ap);
-
- return s_buffer;
-}
-
-
-
-#ifdef CONTAINER_UNIT_TEST
-
-
-// Compile this test case with something like:
-//
-// gcc container.cpp utf8.cpp tu_random.cpp -g -I.. -DCONTAINER_UNIT_TEST
-lstdc++ -o container_test
-//
-// or
-//
-// cl container.cpp utf8.cpp tu_random.cpp -Zi -Od -DCONTAINER_UNIT_TEST -I..
-
-
-void test_hash()
-{
- // Collect a bunch of random key/value pairs.
- std::vector<Uint32> data;
- for (int i = 0; i < 1000; i++)
- {
- data.push_back(tu_random::next_random());
- }
-
- // Push into hash.
- hash<Uint32, Uint32> h;
- {for (int i = 0; i < data.size() / 2; i++)
- {
- h.add(data[i*2], data[i*2 + 1]);
-
- // Verify the contents of the hash so far.
- for (int j = 0; j < i; j++)
- {
- Uint32 key = data[j*2];
- Uint32 val;
- bool got = h.get(key, &val);
- assert(got);
- assert(val == data[j*2 + 1]);
- }
- }}
-
- // Manually copy stuff over to h2, using iterator interface.
- hash<Uint32, Uint32> h2;
- {for (hash<Uint32, Uint32>::iterator it = h.begin(); it != h.end();
++it)
- {
- //printf("first = 0x%X, second = 0x%X\n", it->first,
it->second);//xxxxx
- assert(h.get(it->first, NULL) == true);
-
- h2.add(it->first, it->second);
-
- Uint32 val;
- bool got = h2.get(it->first, &val);
- assert(got);
- assert(val == it->second);
- }}
-
- // Verify the contents of h2.
- {for (int i = 0; i < data.size() / 2; i++)
- {
- Uint32 key = data[i*2];
- Uint32 val;
- bool got = h.get(key, &val);
- assert(got);
- assert(val == data[i*2 + 1]);
- }}
-
- h.clear();
- assert(h.size() == 0);
-
- // Verify that h really is missing the stuff it had before, and h2
really has it.
- {for (hash<Uint32, Uint32>::iterator it = h2.begin(); it != h2.end();
++it)
- {
- assert(h.get(it->first, NULL) == false);
- assert(h2.get(it->first, NULL) == true);
- assert(h.find(it->first) == h.end());
- assert(h2.find(it->first) != h2.end());
- }}
-}
-
-
-//#include <ext/hash_map>
-//#include <hash_map>
-//#include <map>
-
-void test_hash_speed()
-// Test function for hash performance of adding keys and doing lookup.
-{
-
-// Hash type, for doing comparative tests.
-//
-// tu_hash tests faster than the map and hash_map included with GCC
-// 3.3 as well as map and hash_map from MSVC7. In some cases, several
-// times faster. GCC's hash_map is the closest to tu_hash, but is
-// still 33% slower in my tests.
-
-// // tu's hash
-#define HASH hash<uint32, uint32 >
-#define HASH_ADD(h, k, v) h.add(k, v)
-
-// STL's hash
-//#define HASH __gnu_cxx::hash_map<uint32, uint32>
-//#define HASH std::hash_map<uint32, uint32>
-//#define HASH_ADD(h, k, v) h[k] = v
-
-// STL's map
-//#define HASH std::map<uint32, uint32>
-//#define HASH_ADD(h, k, v) h[k] = v
-
-// const int SIZE = 10000000;
- const int SIZE = 1000000;
-
- // Make an array of random numbers.
- std::vector<uint32> numbers;
- numbers.resize(SIZE);
-
- for (int i = 0, n = numbers.size(); i < n; i++)
- {
- numbers[i] = tu_random::next_random();
- }
-
- // Uniquify the array.
- HASH new_index;
- int next_new_index = 0;
- {for (int i = 0, n = numbers.size(); i < n; i++)
- {
- HASH::iterator it = new_index.find(numbers[i]);
- if (it == new_index.end())
- {
- // First time this number has been seen.
- HASH_ADD(new_index, numbers[i], next_new_index);
- next_new_index++;
- }
- else
- {
- // This number already appears in the list.
-// printf("duplicate entry %x, prev new index %d, current
array index %d\n",
-// numbers[i],
-// it->second,
-// i);
- }
- }}
-
- printf("next_new_index = %d\n", next_new_index);
-}
-
-
-void test_stringi()
-{
- tu_stringi a, b;
-
- // Equality.
- a = "this is a test";
- b = "This is a test";
- assert(a == b);
-
- b = "tHiS Is a tEsT";
- assert(a == b);
-
- a += "Hello";
- b += "hellO";
- assert(a == b);
-
- tu_string c(b);
- assert(a.to_tu_string() != c);
-
- // Ordering.
- a = "a";
- b = "B";
- assert(a < b);
-
- a = "b";
- b = "A";
- assert(a > b);
-}
-
-
-void test_stringi_hash()
-{
- stringi_hash<int> a;
-
- assert(a.is_empty());
-
- a.add("bobo", 1);
-
- assert(a.is_empty() == false);
-
- a.add("hello", 2);
- a.add("it's", 3);
- a.add("a", 4);
- a.add("beautiful day!", 5);
-
- int result = 0;
- a.get("boBO", &result);
- assert(result == 1);
-
- a.set("BObo", 2);
- a.get("bObO", &result);
- assert(result == 2);
-
- assert(a.is_empty() == false);
- a.clear();
- assert(a.is_empty() == true);
-
- // Hammer on one key that differs only by case.
- tu_stringi original_key("thisisatest");
- tu_stringi key(original_key);
- a.add(key, 1234567);
-
- int variations = 1 << key.length();
- for (int i = 0; i < variations; i++)
- {
- // Twiddle the case of the key.
- for (int c = 0; c < key.length(); c++)
- {
- if (i & (1 << c))
- {
- key[c] = toupper(key[c]);
- }
- else
- {
- key[c] = tolower(key[c]);
- }
- }
-
- a.set(key, 7654321);
-
- // Make sure original entry was modified.
- int value = 0;
- a.get(original_key, &value);
- assert(value == 7654321);
-
- // Make sure hash keys are preserving case.
- assert(a.find(key)->first.to_tu_string() ==
original_key.to_tu_string());
-
- // Make sure they're actually the same entry.
- assert(a.find(original_key) == a.find(key));
-
- a.set(original_key, 1234567);
- assert(a.find(key)->second == 1234567);
- }
-}
-
-
-void test_unicode()
-{
- tu_string a;
-
- tu_string::encode_utf8_from_wchar(&a, L"19 character string");
- assert(a.length() == 19);
-
- // TODO add some more tests; should test actual UTF-8 conversions.
-}
-
-
-
-int main()
-{
-#if 1
- printf("sizeof(tu_string) == %d\n", sizeof(tu_string));
-
- std::vector<tu_string> storage;
- storage.resize(2);
-
- tu_string& a = storage[0];
- tu_string& b = storage[1];
- a = "test1";
-
- printf("&a = 0x%X, &b = 0x%X\n", int(&a), int(&b));
-
- printf("%s\n", a.c_str());
-
- assert(a == "test1");
- assert(a.length() == 5);
-
- a += "2";
- assert(a == "test12");
-
- a += "this is some more text";
- assert(a.length() == 28);
-
- assert(a[2] == 's');
- assert(a[3] == 't');
- assert(a[4] == '1');
- assert(a[5] == '2');
- assert(a[7] == 'h');
- assert(a[28] == 0);
-
- assert(b.length() == 0);
- assert(b[0] == 0);
- assert(b.c_str()[0] == 0);
-
- tu_string c = a + b;
-
- assert(c.length() == a.length());
-
- c.resize(2);
- assert(c == "te");
- assert(c == tu_string("te"));
-
- assert(tu_string("fourscore and sevent") == "fourscore and sevent");
-
- b = "#sacrificial lamb";
-
- // Test growing & shrinking.
- a = "";
- for (int i = 0; i < 1000; i++)
- {
- assert(a.length() == i);
-
- if (i == 8)
- {
- assert(a == "01234567");
- }
- else if (i == 27)
- {
- assert(a == "012345678901234567890123456");
- }
-
- a.resize(a.length() + 1);
- a[a.length() - 1] = '0' + (i % 10);
- }
-
- {for (int i = 999; i >= 0; i--)
- {
- a.resize(a.length() - 1);
- assert(a.length() == i);
-
- if (i == 8)
- {
- assert(a == "01234567");
- }
- else if (i == 27)
- {
- assert(a == "012345678901234567890123456");
- }
- }}
-
- // Test larger shrinking across heap/local boundary.
- a = "this is a string longer than 16 characters";
- a = "short";
-
- // Test larger expand across heap/local boundary.
- a = "another longer string...";
-
- assert(b == "#sacrificial lamb");
-
- test_hash();
- test_stringi();
- test_stringi_hash();
-
- test_unicode();
-
- // TODO: unit tests for std::vector<>, string_hash<>
-#endif
-
- test_hash_speed();
-
- return 0;
-}
-
-
-#endif // CONTAINER_UNIT_TEST
-
-
-// Local Variables:
-// mode: C++
-// c-basic-offset: 8
-// tab-width: 8
-// indent-tabs-mode: t
-// End:
+// container.cpp -- Thatcher Ulrich <address@hidden> 2003
+
+// This source code has been donated to the Public Domain. Do
+// whatever you want with it.
+
+// Some non-inline implementation help for generic containers.
+
+
+#include "container.h"
+#include "utf8.h"
+#include "tu_random.h"
+#include <stdarg.h>
+
+
+void tu_string::append_wide_char(uint16 c)
+{
+ char buf[8];
+ int index = 0;
+ utf8::encode_unicode_character(buf, &index, (uint32) c);
+ buf[index] = 0;
+
+ *this += buf;
+}
+
+
+void tu_string::append_wide_char(uint32 c)
+{
+ char buf[8];
+ int index = 0;
+ utf8::encode_unicode_character(buf, &index, c);
+ buf[index] = 0;
+
+ *this += buf;
+}
+
+
+void tu_string::resize(int new_size)
+{
+ assert(new_size >= 0);
+
+ if (using_heap() == false)
+ {
+ if (new_size < 15)
+ {
+ // Stay with internal storage.
+ m_local.m_size = (char) (new_size + 1);
+ m_local.m_buffer[new_size] = 0; // terminate
+ }
+ else
+ {
+ // need to allocate heap buffer.
+ int capacity = new_size + 1;
+ // round up.
+ capacity = (capacity + 15) & ~15;
+ char* buf = (char*) tu_malloc(capacity);
+ memset(buf, 0, capacity);
+
+ // Copy existing data.
+ strcpy(buf, m_local.m_buffer);
+
+ // Set the heap state.
+ m_heap.m_buffer = buf;
+ m_heap.m_all_ones = char(~0);
+ m_heap.m_size = new_size + 1;
+ m_heap.m_capacity = capacity;
+ }
+ }
+ else
+ {
+ // Currently using heap storage.
+ if (new_size < 15)
+ {
+ // Switch to local storage.
+
+ // Be sure to get stack copies of m_heap info, before
we overwrite it.
+ char* old_buffer = m_heap.m_buffer;
+ int old_capacity = m_heap.m_capacity;
+ UNUSED(old_capacity);
+
+ // Copy existing string info.
+ m_local.m_size = (char) (new_size + 1);
+ strncpy(m_local.m_buffer, old_buffer, 15);
+ m_local.m_buffer[new_size] = 0; // ensure termination.
+
+ tu_free(old_buffer, old_capacity);
+ }
+ else
+ {
+ // Changing size of heap buffer.
+ int capacity = new_size + 1;
+ // Round up.
+ capacity = (capacity + 15) & ~15;
+ if (capacity != m_heap.m_capacity) // @@ TODO
should use hysteresis when resizing
+ {
+ m_heap.m_buffer = (char*)
tu_realloc(m_heap.m_buffer, capacity, m_heap.m_capacity);
+ m_heap.m_capacity = capacity;
+ }
+ // else we're OK with existing buffer.
+
+ m_heap.m_size = new_size + 1;
+
+ // Ensure termination.
+ m_heap.m_buffer[new_size] = 0;
+ }
+ }
+}
+
+
+template<class char_type>
+/*static*/ void encode_utf8_from_wchar_generic(tu_string* result, const
char_type* wstr)
+{
+ const char_type* in = wstr;
+
+ // First pass: compute the necessary string length.
+ int bytes_needed = 0;
+ char dummy[10];
+ int offset;
+ for (;;)
+ {
+ Uint32 uc = *in++;
+ offset = 0;
+ utf8::encode_unicode_character(dummy, &offset, uc);
+ bytes_needed += offset;
+
+ assert(offset <= 6);
+
+ if (uc == 0)
+ {
+ break;
+ }
+ }
+
+ // Second pass: transfer the data.
+ result->resize(bytes_needed - 1); // resize() adds 1 for the \0
terminator
+ in = wstr;
+ char* out = &((*result)[0]);
+ offset = 0;
+ for (;;)
+ {
+ assert(offset < bytes_needed);
+
+ Uint32 uc = *in++;
+ utf8::encode_unicode_character(out, &offset, uc);
+
+ assert(offset <= bytes_needed);
+
+ if (uc == 0)
+ {
+ break;
+ }
+ }
+
+ assert(offset == bytes_needed);
+ assert((*result)[offset - 1] == 0);
+ assert(result->length() == (int) strlen(result->c_str()));
+}
+
+
+void tu_string::encode_utf8_from_wchar(tu_string* result, const uint32* wstr)
+{
+ encode_utf8_from_wchar_generic<uint32>(result, wstr);
+}
+
+
+void tu_string::encode_utf8_from_wchar(tu_string* result, const uint16* wstr)
+{
+ encode_utf8_from_wchar_generic<uint16>(result, wstr);
+}
+
+
+/*static*/ int tu_string::stricmp(const char* a, const char* b)
+{
+#ifdef _WIN32
+ return ::stricmp(a, b);
+#else
+ return strcasecmp(a, b);
+#endif
+}
+
+
+uint32 tu_string::utf8_char_at(int index) const
+{
+ const char* buf = get_buffer();
+ uint32 c;
+
+ do
+ {
+ c = utf8::decode_next_unicode_character(&buf);
+ index--;
+
+ if (c == 0)
+ {
+ // We've hit the end of the string; don't go further.
+ assert(index == 0);
+ return c;
+ }
+ }
+ while (index >= 0);
+
+ return c;
+}
+
+
+tu_string tu_string::utf8_to_upper() const
+{
+ const char* buf = get_buffer();
+ tu_string str;
+ for (;;)
+ {
+ uint32 c = utf8::decode_next_unicode_character(&buf);
+
+ if (c == 0)
+ {
+ // We've hit the end of the string; don't go further.
+ return str;
+ }
+ str += toupper(c);
+ }
+
+ return str;
+}
+
+
+tu_string tu_string::utf8_to_lower() const
+{
+ const char* buf = get_buffer();
+ tu_string str;
+ for (;;)
+ {
+ uint32 c = utf8::decode_next_unicode_character(&buf);
+
+ if (c == 0) {
+ // We've hit the end of the string; don't go further.
+ return str;
+ }
+ str += tolower(c);
+ }
+
+ return str;
+}
+
+
+/*static*/ int tu_string::utf8_char_count(const char* buf, int buflen)
+{
+ const char* p = buf;
+ int length = 0;
+
+ while (p - buf < buflen)
+ {
+ uint32 c = utf8::decode_next_unicode_character(&p);
+ if (c == 0)
+ {
+ break;
+ }
+
+ length++;
+ }
+
+ return length;
+}
+
+
+tu_string tu_string::utf8_substring(int start, int end) const
+{
+ assert(start <= end);
+
+ if (start == end)
+ {
+ // Special case, always return empty string.
+ return tu_string();
+ }
+
+ const char* p = get_buffer();
+ int index = 0;
+ const char* start_pointer = p;
+ const char* end_pointer = p;
+
+ for (;;)
+ {
+ if (index == start)
+ {
+ start_pointer = p;
+ }
+
+ uint32 c = utf8::decode_next_unicode_character(&p);
+ index++;
+
+ if (index == end)
+ {
+ end_pointer = p;
+ break;
+ }
+
+ if (c == 0)
+ {
+ if (index < end)
+ {
+ assert(0);
+ end_pointer = p;
+ }
+ break;
+ }
+ }
+
+ if (end_pointer < start_pointer)
+ {
+ end_pointer = start_pointer;
+ }
+
+ return tu_string(start_pointer, end_pointer - start_pointer);
+}
+
+
+#ifdef _WIN32
+#define vsnprintf _vsnprintf
+#endif // _WIN32
+
+tu_string string_printf(const char* fmt, ...)
+// Handy sprintf wrapper.
+{
+ static const int BUFFER_SIZE = 500;
+ char s_buffer[BUFFER_SIZE];
+
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(s_buffer, BUFFER_SIZE, fmt, ap);
+ va_end(ap);
+
+ return s_buffer;
+}
+
+
+
+#ifdef CONTAINER_UNIT_TEST
+
+
+// Compile this test case with something like:
+//
+// gcc container.cpp utf8.cpp tu_random.cpp -g -I.. -DCONTAINER_UNIT_TEST
-lstdc++ -o container_test
+//
+// or
+//
+// cl container.cpp utf8.cpp tu_random.cpp -Zi -Od -DCONTAINER_UNIT_TEST -I..
+
+
+void test_hash()
+{
+ // Collect a bunch of random key/value pairs.
+ std::vector<Uint32> data;
+ for (int i = 0; i < 1000; i++)
+ {
+ data.push_back(tu_random::next_random());
+ }
+
+ // Push into hash.
+ hash<Uint32, Uint32> h;
+ {for (int i = 0; i < data.size() / 2; i++)
+ {
+ h.add(data[i*2], data[i*2 + 1]);
+
+ // Verify the contents of the hash so far.
+ for (int j = 0; j < i; j++)
+ {
+ Uint32 key = data[j*2];
+ Uint32 val;
+ bool got = h.get(key, &val);
+ assert(got);
+ assert(val == data[j*2 + 1]);
+ }
+ }}
+
+ // Manually copy stuff over to h2, using iterator interface.
+ hash<Uint32, Uint32> h2;
+ {for (hash<Uint32, Uint32>::iterator it = h.begin(); it != h.end();
++it)
+ {
+ //printf("first = 0x%X, second = 0x%X\n", it->first,
it->second);//xxxxx
+ assert(h.get(it->first, NULL) == true);
+
+ h2.add(it->first, it->second);
+
+ Uint32 val;
+ bool got = h2.get(it->first, &val);
+ assert(got);
+ assert(val == it->second);
+ }}
+
+ // Verify the contents of h2.
+ {for (int i = 0; i < data.size() / 2; i++)
+ {
+ Uint32 key = data[i*2];
+ Uint32 val;
+ bool got = h.get(key, &val);
+ assert(got);
+ assert(val == data[i*2 + 1]);
+ }}
+
+ h.clear();
+ assert(h.size() == 0);
+
+ // Verify that h really is missing the stuff it had before, and h2
really has it.
+ {for (hash<Uint32, Uint32>::iterator it = h2.begin(); it != h2.end();
++it)
+ {
+ assert(h.get(it->first, NULL) == false);
+ assert(h2.get(it->first, NULL) == true);
+ assert(h.find(it->first) == h.end());
+ assert(h2.find(it->first) != h2.end());
+ }}
+}
+
+
+//#include <ext/hash_map>
+//#include <hash_map>
+//#include <map>
+
+void test_hash_speed()
+// Test function for hash performance of adding keys and doing lookup.
+{
+
+// Hash type, for doing comparative tests.
+//
+// tu_hash tests faster than the map and hash_map included with GCC
+// 3.3 as well as map and hash_map from MSVC7. In some cases, several
+// times faster. GCC's hash_map is the closest to tu_hash, but is
+// still 33% slower in my tests.
+
+// // tu's hash
+#define HASH hash<uint32, uint32 >
+#define HASH_ADD(h, k, v) h.add(k, v)
+
+// STL's hash
+//#define HASH __gnu_cxx::hash_map<uint32, uint32>
+//#define HASH std::hash_map<uint32, uint32>
+//#define HASH_ADD(h, k, v) h[k] = v
+
+// STL's map
+//#define HASH std::map<uint32, uint32>
+//#define HASH_ADD(h, k, v) h[k] = v
+
+// const int SIZE = 10000000;
+ const int SIZE = 1000000;
+
+ // Make an array of random numbers.
+ std::vector<uint32> numbers;
+ numbers.resize(SIZE);
+
+ for (int i = 0, n = numbers.size(); i < n; i++)
+ {
+ numbers[i] = tu_random::next_random();
+ }
+
+ // Uniquify the array.
+ HASH new_index;
+ int next_new_index = 0;
+ {for (int i = 0, n = numbers.size(); i < n; i++)
+ {
+ HASH::iterator it = new_index.find(numbers[i]);
+ if (it == new_index.end())
+ {
+ // First time this number has been seen.
+ HASH_ADD(new_index, numbers[i], next_new_index);
+ next_new_index++;
+ }
+ else
+ {
+ // This number already appears in the list.
+// printf("duplicate entry %x, prev new index %d, current
array index %d\n",
+// numbers[i],
+// it->second,
+// i);
+ }
+ }}
+
+ printf("next_new_index = %d\n", next_new_index);
+}
+
+
+void test_stringi()
+{
+ tu_stringi a, b;
+
+ // Equality.
+ a = "this is a test";
+ b = "This is a test";
+ assert(a == b);
+
+ b = "tHiS Is a tEsT";
+ assert(a == b);
+
+ a += "Hello";
+ b += "hellO";
+ assert(a == b);
+
+ tu_string c(b);
+ assert(a.to_tu_string() != c);
+
+ // Ordering.
+ a = "a";
+ b = "B";
+ assert(a < b);
+
+ a = "b";
+ b = "A";
+ assert(a > b);
+}
+
+
+void test_stringi_hash()
+{
+ stringi_hash<int> a;
+
+ assert(a.is_empty());
+
+ a.add("bobo", 1);
+
+ assert(a.is_empty() == false);
+
+ a.add("hello", 2);
+ a.add("it's", 3);
+ a.add("a", 4);
+ a.add("beautiful day!", 5);
+
+ int result = 0;
+ a.get("boBO", &result);
+ assert(result == 1);
+
+ a.set("BObo", 2);
+ a.get("bObO", &result);
+ assert(result == 2);
+
+ assert(a.is_empty() == false);
+ a.clear();
+ assert(a.is_empty() == true);
+
+ // Hammer on one key that differs only by case.
+ tu_stringi original_key("thisisatest");
+ tu_stringi key(original_key);
+ a.add(key, 1234567);
+
+ int variations = 1 << key.length();
+ for (int i = 0; i < variations; i++)
+ {
+ // Twiddle the case of the key.
+ for (int c = 0; c < key.length(); c++)
+ {
+ if (i & (1 << c))
+ {
+ key[c] = toupper(key[c]);
+ }
+ else
+ {
+ key[c] = tolower(key[c]);
+ }
+ }
+
+ a.set(key, 7654321);
+
+ // Make sure original entry was modified.
+ int value = 0;
+ a.get(original_key, &value);
+ assert(value == 7654321);
+
+ // Make sure hash keys are preserving case.
+ assert(a.find(key)->first.to_tu_string() ==
original_key.to_tu_string());
+
+ // Make sure they're actually the same entry.
+ assert(a.find(original_key) == a.find(key));
+
+ a.set(original_key, 1234567);
+ assert(a.find(key)->second == 1234567);
+ }
+}
+
+
+void test_unicode()
+{
+ tu_string a;
+
+ tu_string::encode_utf8_from_wchar(&a, L"19 character string");
+ assert(a.length() == 19);
+
+ // TODO add some more tests; should test actual UTF-8 conversions.
+}
+
+
+
+int main()
+{
+#if 1
+ printf("sizeof(tu_string) == %d\n", sizeof(tu_string));
+
+ std::vector<tu_string> storage;
+ storage.resize(2);
+
+ tu_string& a = storage[0];
+ tu_string& b = storage[1];
+ a = "test1";
+
+ printf("&a = 0x%X, &b = 0x%X\n", int(&a), int(&b));
+
+ printf("%s\n", a.c_str());
+
+ assert(a == "test1");
+ assert(a.length() == 5);
+
+ a += "2";
+ assert(a == "test12");
+
+ a += "this is some more text";
+ assert(a.length() == 28);
+
+ assert(a[2] == 's');
+ assert(a[3] == 't');
+ assert(a[4] == '1');
+ assert(a[5] == '2');
+ assert(a[7] == 'h');
+ assert(a[28] == 0);
+
+ assert(b.length() == 0);
+ assert(b[0] == 0);
+ assert(b.c_str()[0] == 0);
+
+ tu_string c = a + b;
+
+ assert(c.length() == a.length());
+
+ c.resize(2);
+ assert(c == "te");
+ assert(c == tu_string("te"));
+
+ assert(tu_string("fourscore and sevent") == "fourscore and sevent");
+
+ b = "#sacrificial lamb";
+
+ // Test growing & shrinking.
+ a = "";
+ for (int i = 0; i < 1000; i++)
+ {
+ assert(a.length() == i);
+
+ if (i == 8)
+ {
+ assert(a == "01234567");
+ }
+ else if (i == 27)
+ {
+ assert(a == "012345678901234567890123456");
+ }
+
+ a.resize(a.length() + 1);
+ a[a.length() - 1] = '0' + (i % 10);
+ }
+
+ {for (int i = 999; i >= 0; i--)
+ {
+ a.resize(a.length() - 1);
+ assert(a.length() == i);
+
+ if (i == 8)
+ {
+ assert(a == "01234567");
+ }
+ else if (i == 27)
+ {
+ assert(a == "012345678901234567890123456");
+ }
+ }}
+
+ // Test larger shrinking across heap/local boundary.
+ a = "this is a string longer than 16 characters";
+ a = "short";
+
+ // Test larger expand across heap/local boundary.
+ a = "another longer string...";
+
+ assert(b == "#sacrificial lamb");
+
+ test_hash();
+ test_stringi();
+ test_stringi_hash();
+
+ test_unicode();
+
+ // TODO: unit tests for std::vector<>, string_hash<>
+#endif
+
+ test_hash_speed();
+
+ return 0;
+}
+
+
+#endif // CONTAINER_UNIT_TEST
+
+
+// Local Variables:
+// mode: C++
+// c-basic-offset: 8
+// tab-width: 8
+// indent-tabs-mode: t
+// End:
Index: gnash/libbase/container.h
diff -u gnash/libbase/container.h:1.6 gnash/libbase/container.h:1.7
--- gnash/libbase/container.h:1.6 Sat Feb 25 03:54:03 2006
+++ gnash/libbase/container.h Sun Feb 26 15:49:29 2006
@@ -12,12 +12,26 @@
#ifndef CONTAINER_H
#define CONTAINER_H
+// FIXME: This ugly hack is for NetBSD, which seems to have a
+// preprocessor problem, and won't define anything sensible like
+// NETBSD we can use. Basically the problem is NetBSD has two thread
+// implementations. One if the older pth library in /usr/pkg, and the
+// other (the one we want to use) is /usr/pkg/phtread. Even with the
+// corrent paths supplied, this one file barfs with GCC 3.3.3 on
+// NetBSD, so screw it, and just hack it for now. We hope this entire
+// file will be gond soon anyway.
+#define _LIB_PTHREAD_ 1
+#define _LIB_PTHREAD_TYPES_H 1
+#include <sys/types.h>
+#include <pthread.h>
+clock_t clock __P((void));
+size_t strftime __P((char *, size_t, const char *, const struct tm *));
#include "tu_config.h"
#include "utility.h"
#include <stdlib.h>
-#include <string.h> // for strcmp and friends
-#include <new> // for placement new
+#include <cstring> // for strcmp and friends
+//#include <new> // for placement new
#include <vector>
Index: gnash/libbase/demo.cpp
diff -u gnash/libbase/demo.cpp:1.1 gnash/libbase/demo.cpp:1.2
--- gnash/libbase/demo.cpp:1.1 Tue Dec 20 20:57:00 2005
+++ gnash/libbase/demo.cpp Sun Feb 26 15:49:29 2006
@@ -1,127 +1,127 @@
-// demo.cpp -- Thatcher Ulrich <http://tulrich.com> 2005
-
-// This source code has been donated to the Public Domain. Do
-// whatever you want with it.
-
-// Some helper code for making graphical demos. Covers OpenGL/SDL
-// initialization, and some basic viewport navigation.
-
-
-#include "tu_config.h"
-#include "demo.h"
-#include "ogl.h"
-#include "SDL.h"
-
-
-namespace demo
-{
- void init_video(int width, int height, int depth)
- {
- // Display.
- // Initialize the SDL subsystems we're using.
- if (SDL_Init(SDL_INIT_VIDEO /* | SDL_INIT_JOYSTICK |
SDL_INIT_CDROM | SDL_INIT_AUDIO*/))
- {
- fprintf(stderr, "Unable to init SDL: %s\n",
SDL_GetError());
- exit(1);
- }
- atexit(SDL_Quit);
-
- SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
-
- // Set the video mode.
- if (SDL_SetVideoMode(width, height, depth, SDL_OPENGL) == 0)
- {
- fprintf(stderr, "SDL_SetVideoMode() failed.");
- exit(1);
- }
-
- ogl::open();
- }
-
-
- bool update_nav2d(nav2d_state* state)
- {
- // Handle input.
- SDL_Event event;
- while (SDL_PollEvent(&event))
- {
- switch (event.type)
- {
- case SDL_KEYDOWN:
- {
- int key = event.key.keysym.sym;
-
- if (key == SDLK_q || key == SDLK_ESCAPE)
- {
- return true;
- } else if (key == SDLK_EQUALS) {
- state->m_scale *= 0.5f;
- } else if (key == SDLK_MINUS) {
- state->m_scale *= 2.0f;
- }
- break;
- }
-
- case SDL_MOUSEMOTION:
- {
- int new_x = (int) (event.motion.x);
- int new_y = (int) (event.motion.y);
- state->m_mouse_dx = new_x - state->m_mouse_x;
- state->m_mouse_dy = new_y - state->m_mouse_y;
- if (state->m_mouse_buttons & 2) {
- // Left drag: move.
- state->m_center_x -= state->m_mouse_dx
* state->m_scale;
- state->m_center_y += state->m_mouse_dy
* state->m_scale;
- }
- state->m_mouse_x = new_x;
- state->m_mouse_y = new_y;
- break;
- }
-
- case SDL_MOUSEBUTTONDOWN:
- case SDL_MOUSEBUTTONUP:
- {
- int mask = 1 << (event.button.button);
- if (event.button.state == SDL_PRESSED)
- {
- state->m_mouse_buttons |= mask;
- }
- else
- {
- state->m_mouse_buttons &= ~mask;
- }
- break;
- }
-
- case SDL_QUIT:
- return true;
- break;
-
- default:
- break;
- }
- }
-
- return false;
- }
-
-
- void set_nav2d_viewport(const nav2d_state& state)
- {
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glOrtho(state.m_center_x - 500 * state.m_scale,
state.m_center_x + 500 * state.m_scale,
- state.m_center_y - 500 * state.m_scale,
state.m_center_y + 500 * state.m_scale, -1, 1);
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- }
-}
-
-
-// Local Variables:
-// mode: C++
-// c-basic-offset: 8
-// tab-width: 8
-// indent-tabs-mode: t
-// End:
-
+// demo.cpp -- Thatcher Ulrich <http://tulrich.com> 2005
+
+// This source code has been donated to the Public Domain. Do
+// whatever you want with it.
+
+// Some helper code for making graphical demos. Covers OpenGL/SDL
+// initialization, and some basic viewport navigation.
+
+
+#include "tu_config.h"
+#include "demo.h"
+#include "ogl.h"
+#include "SDL.h"
+
+
+namespace demo
+{
+ void init_video(int width, int height, int depth)
+ {
+ // Display.
+ // Initialize the SDL subsystems we're using.
+ if (SDL_Init(SDL_INIT_VIDEO /* | SDL_INIT_JOYSTICK |
SDL_INIT_CDROM | SDL_INIT_AUDIO*/))
+ {
+ fprintf(stderr, "Unable to init SDL: %s\n",
SDL_GetError());
+ exit(1);
+ }
+ atexit(SDL_Quit);
+
+ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+
+ // Set the video mode.
+ if (SDL_SetVideoMode(width, height, depth, SDL_OPENGL) == 0)
+ {
+ fprintf(stderr, "SDL_SetVideoMode() failed.");
+ exit(1);
+ }
+
+ ogl::open();
+ }
+
+
+ bool update_nav2d(nav2d_state* state)
+ {
+ // Handle input.
+ SDL_Event event;
+ while (SDL_PollEvent(&event))
+ {
+ switch (event.type)
+ {
+ case SDL_KEYDOWN:
+ {
+ int key = event.key.keysym.sym;
+
+ if (key == SDLK_q || key == SDLK_ESCAPE)
+ {
+ return true;
+ } else if (key == SDLK_EQUALS) {
+ state->m_scale *= 0.5f;
+ } else if (key == SDLK_MINUS) {
+ state->m_scale *= 2.0f;
+ }
+ break;
+ }
+
+ case SDL_MOUSEMOTION:
+ {
+ int new_x = (int) (event.motion.x);
+ int new_y = (int) (event.motion.y);
+ state->m_mouse_dx = new_x - state->m_mouse_x;
+ state->m_mouse_dy = new_y - state->m_mouse_y;
+ if (state->m_mouse_buttons & 2) {
+ // Left drag: move.
+ state->m_center_x -= state->m_mouse_dx
* state->m_scale;
+ state->m_center_y += state->m_mouse_dy
* state->m_scale;
+ }
+ state->m_mouse_x = new_x;
+ state->m_mouse_y = new_y;
+ break;
+ }
+
+ case SDL_MOUSEBUTTONDOWN:
+ case SDL_MOUSEBUTTONUP:
+ {
+ int mask = 1 << (event.button.button);
+ if (event.button.state == SDL_PRESSED)
+ {
+ state->m_mouse_buttons |= mask;
+ }
+ else
+ {
+ state->m_mouse_buttons &= ~mask;
+ }
+ break;
+ }
+
+ case SDL_QUIT:
+ return true;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return false;
+ }
+
+
+ void set_nav2d_viewport(const nav2d_state& state)
+ {
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(state.m_center_x - 500 * state.m_scale,
state.m_center_x + 500 * state.m_scale,
+ state.m_center_y - 500 * state.m_scale,
state.m_center_y + 500 * state.m_scale, -1, 1);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ }
+}
+
+
+// Local Variables:
+// mode: C++
+// c-basic-offset: 8
+// tab-width: 8
+// indent-tabs-mode: t
+// End:
+
Index: gnash/libbase/demo.h
diff -u gnash/libbase/demo.h:1.1 gnash/libbase/demo.h:1.2
--- gnash/libbase/demo.h:1.1 Tue Dec 20 20:57:00 2005
+++ gnash/libbase/demo.h Sun Feb 26 15:49:29 2006
@@ -1,75 +1,75 @@
-// demo.h -- Thatcher Ulrich <http://tulrich.com> 2005
-
-// This source code has been donated to the Public Domain. Do
-// whatever you want with it.
-
-// Some helper code for making graphical demos. Covers OpenGL/SDL
-// initialization, and some basic viewport navigation.
-
-
-#ifndef DEMO_H
-#define DEMO_H
-
-
-#include "tu_config.h"
-
-
-namespace demo
-{
- // Open an OpenGL window with the given dimensions.
- void init_video(int width, int height, int depth);
-
- // A state object you can use to manage 2D scrolling & zooming.
- struct nav2d_state
- {
- // 2d viewport state.
- float m_center_x;
- float m_center_y;
- float m_scale;
-
- // Current mouse state.
- int m_mouse_x;
- int m_mouse_y;
- int m_mouse_buttons;
-
- // Change in mouse position in pixels, this frame.
- int m_mouse_dx;
- int m_mouse_dy;
-
- nav2d_state()
- :
- m_center_x(0),
- m_center_y(0),
- m_scale(1),
- m_mouse_x(0),
- m_mouse_y(0),
- m_mouse_buttons(0),
- m_mouse_dx(0),
- m_mouse_dy(0)
- {
- }
- };
-
- // Checks and processes the SDL message queue. Returns true
- // if the user wants to exit.
- //
- // TODO: do some kind of callback registry for handling misc
- // app-specific inputs
- bool update_nav2d(nav2d_state* state);
-
- // Sets the OpenGL projection & modelview according to the 2d
- // view state.
- void set_nav2d_viewport(const nav2d_state& state);
-}
-
-
-#endif // DEMO_H
-
-
-// Local Variables:
-// mode: C++
-// c-basic-offset: 8
-// tab-width: 8
-// indent-tabs-mode: t
-// End:
-
+// demo.h -- Thatcher Ulrich <http://tulrich.com> 2005
+
+// This source code has been donated to the Public Domain. Do
+// whatever you want with it.
+
+// Some helper code for making graphical demos. Covers OpenGL/SDL
+// initialization, and some basic viewport navigation.
+
+
+#ifndef DEMO_H
+#define DEMO_H
+
+
+#include "tu_config.h"
+
+
+namespace demo
+{
+ // Open an OpenGL window with the given dimensions.
+ void init_video(int width, int height, int depth);
+
+ // A state object you can use to manage 2D scrolling & zooming.
+ struct nav2d_state
+ {
+ // 2d viewport state.
+ float m_center_x;
+ float m_center_y;
+ float m_scale;
+
+ // Current mouse state.
+ int m_mouse_x;
+ int m_mouse_y;
+ int m_mouse_buttons;
+
+ // Change in mouse position in pixels, this frame.
+ int m_mouse_dx;
+ int m_mouse_dy;
+
+ nav2d_state()
+ :
+ m_center_x(0),
+ m_center_y(0),
+ m_scale(1),
+ m_mouse_x(0),
+ m_mouse_y(0),
+ m_mouse_buttons(0),
+ m_mouse_dx(0),
+ m_mouse_dy(0)
+ {
+ }
+ };
+
+ // Checks and processes the SDL message queue. Returns true
+ // if the user wants to exit.
+ //
+ // TODO: do some kind of callback registry for handling misc
+ // app-specific inputs
+ bool update_nav2d(nav2d_state* state);
+
+ // Sets the OpenGL projection & modelview according to the 2d
+ // view state.
+ void set_nav2d_viewport(const nav2d_state& state);
+}
+
+
+#endif // DEMO_H
+
+
+// Local Variables:
+// mode: C++
+// c-basic-offset: 8
+// tab-width: 8
+// indent-tabs-mode: t
+// End:
+
Index: gnash/libbase/dlmalloc.c
diff -u gnash/libbase/dlmalloc.c:1.1 gnash/libbase/dlmalloc.c:1.2
--- gnash/libbase/dlmalloc.c:1.1 Tue Dec 20 21:13:18 2005
+++ gnash/libbase/dlmalloc.c Sun Feb 26 15:49:29 2006
@@ -1470,7 +1470,7 @@
========================================================================
*/
-/* #include "malloc.h" */
+/* #include "stdlib.h" */
/* --------------------- public wrappers ---------------------- */
Index: gnash/libbase/dlmalloc.h
diff -u gnash/libbase/dlmalloc.h:1.1 gnash/libbase/dlmalloc.h:1.2
--- gnash/libbase/dlmalloc.h:1.1 Tue Dec 20 20:57:00 2005
+++ gnash/libbase/dlmalloc.h Sun Feb 26 15:49:29 2006
@@ -35,7 +35,7 @@
#ifdef __MACH__
#include <memory.h>
#else
-#include <malloc.h> /* tulrich */
+#include <stdlib.h> /* tulrich */
#endif
#ifdef USE_DL_MALLOC
Index: gnash/libbase/file_util.cpp
diff -u gnash/libbase/file_util.cpp:1.1 gnash/libbase/file_util.cpp:1.2
--- gnash/libbase/file_util.cpp:1.1 Tue Dec 20 20:57:00 2005
+++ gnash/libbase/file_util.cpp Sun Feb 26 15:49:29 2006
@@ -1,54 +1,54 @@
-// file_util.cpp -- Thatcher Ulrich <address@hidden> 2005
-
-// This source code has been donated to the Public Domain. Do
-// whatever you want with it.
-
-// A file class that can be customized with callbacks.
-
-
-#include "file_util.h"
-#include "utility.h"
-#include <string.h>
-
-
-static const char* reverse_scan(const char* begin, const char* end, char c)
-// Scans in reverse, from *(end-1) through *begin, until it finds a
-// character matching c. If none is found, returns end, else returns
-// a pointer to the char.
-{
- assert(begin <= end);
-
- const char* p = end;
- while (p > begin) {
- p--;
- if (*p == c) {
- return p;
- }
- }
-
- return end;
-}
-
-
-const char* file_util::get_extension(const char* path)
-{
- int len = strlen(path);
- const char* last_dot = reverse_scan(path, path + len, '.');
- const char* last_slash = reverse_scan(last_dot, path + len, '/');
-
- if (last_dot[0] && last_slash[0] == 0) {
- return last_dot + 1;
- }
-
- // No apparent file extension, return an empty string.
- return path + len;
-}
-
-
-
-// Local Variables:
-// mode: C++
-// c-basic-offset: 8
-// tab-width: 8
-// indent-tabs-mode: t
-// End:
+// file_util.cpp -- Thatcher Ulrich <address@hidden> 2005
+
+// This source code has been donated to the Public Domain. Do
+// whatever you want with it.
+
+// A file class that can be customized with callbacks.
+
+
+#include "file_util.h"
+#include "utility.h"
+#include <string.h>
+
+
+static const char* reverse_scan(const char* begin, const char* end, char c)
+// Scans in reverse, from *(end-1) through *begin, until it finds a
+// character matching c. If none is found, returns end, else returns
+// a pointer to the char.
+{
+ assert(begin <= end);
+
+ const char* p = end;
+ while (p > begin) {
+ p--;
+ if (*p == c) {
+ return p;
+ }
+ }
+
+ return end;
+}
+
+
+const char* file_util::get_extension(const char* path)
+{
+ int len = strlen(path);
+ const char* last_dot = reverse_scan(path, path + len, '.');
+ const char* last_slash = reverse_scan(last_dot, path + len, '/');
+
+ if (last_dot[0] && last_slash[0] == 0) {
+ return last_dot + 1;
+ }
+
+ // No apparent file extension, return an empty string.
+ return path + len;
+}
+
+
+
+// Local Variables:
+// mode: C++
+// c-basic-offset: 8
+// tab-width: 8
+// indent-tabs-mode: t
+// End:
Index: gnash/libbase/file_util.h
diff -u gnash/libbase/file_util.h:1.1 gnash/libbase/file_util.h:1.2
--- gnash/libbase/file_util.h:1.1 Tue Dec 20 20:57:00 2005
+++ gnash/libbase/file_util.h Sun Feb 26 15:49:29 2006
@@ -1,36 +1,36 @@
-// file_util.h -- Thatcher Ulrich 2005
-
-// This source code has been donated to the Public Domain. Do
-// whatever you want with it.
-
-// Misc file-handling utilities.
-
-
-#ifndef FILE_UTIL_H
-#define FILE_UTIL_H
-
-
-#include "tu_config.h"
-
-
-namespace file_util {
- // Return a pointer to the file extension. This is the last
- // bit of the filename after the last '.'. If there's no '.',
- // or it appears before the last '/', then the return value
- // points to an empty string.
- //
- // Does not point to the '.' itself;
- // i.e. get_extension("test.txt") will return "txt".
- const char* get_extension(const char* path);
-}
-
-
-#endif // FILE_UTIL_H
-
-
-// Local Variables:
-// mode: C++
-// c-basic-offset: 8
-// tab-width: 8
-// indent-tabs-mode: t
-// End:
+// file_util.h -- Thatcher Ulrich 2005
+
+// This source code has been donated to the Public Domain. Do
+// whatever you want with it.
+
+// Misc file-handling utilities.
+
+
+#ifndef FILE_UTIL_H
+#define FILE_UTIL_H
+
+
+#include "tu_config.h"
+
+
+namespace file_util {
+ // Return a pointer to the file extension. This is the last
+ // bit of the filename after the last '.'. If there's no '.',
+ // or it appears before the last '/', then the return value
+ // points to an empty string.
+ //
+ // Does not point to the '.' itself;
+ // i.e. get_extension("test.txt") will return "txt".
+ const char* get_extension(const char* path);
+}
+
+
+#endif // FILE_UTIL_H
+
+
+// Local Variables:
+// mode: C++
+// c-basic-offset: 8
+// tab-width: 8
+// indent-tabs-mode: t
+// End:
Index: gnash/libbase/image.cpp
diff -u gnash/libbase/image.cpp:1.4 gnash/libbase/image.cpp:1.5
--- gnash/libbase/image.cpp:1.4 Wed Feb 15 13:53:27 2006
+++ gnash/libbase/image.cpp Sun Feb 26 15:49:29 2006
@@ -1,528 +1,528 @@
-// image.cpp -- Thatcher Ulrich <address@hidden> 2002
-
-// This source code has been donated to the Public Domain. Do
-// whatever you want with it.
-
-// Handy image utilities for RGB surfaces.
-
-#include "image.h"
-
-#include "container.h"
-#include "utility.h"
-#include "jpeg.h"
-#include "tu_file.h"
-#include <stdlib.h>
-#include <string.h>
-
-
-namespace image
-{
- //
- // image_base
- //
- image_base::image_base(Uint8* data, int width, int height, int pitch)
- :
- m_data(data),
- m_width(width),
- m_height(height),
- m_pitch(pitch)
- {
- }
-
-
- Uint8* scanline(image_base* surf, int y)
- {
- assert(surf);
- assert(y >= 0 && y < surf->m_height);
- return ((Uint8*) surf->m_data) + surf->m_pitch * y;
- }
-
-
- const Uint8* scanline(const image_base* surf, int y)
- {
- assert(surf);
- assert(y >= 0 && y < surf->m_height);
- return ((const Uint8*) surf->m_data) + surf->m_pitch * y;
- }
-
-
- //
- // rgb
- //
-
- rgb::rgb(int width, int height)
- :
- image_base(
- 0,
- width,
- height,
- (width * 3 + 3) & ~3) // round pitch up to nearest
4-byte boundary
- {
- assert(width > 0);
- assert(height > 0);
- assert(m_pitch >= m_width * 3);
- assert((m_pitch & 3) == 0);
-
-// m_data = (Uint8*) dlmalloc(m_pitch * m_height);
- m_data = new Uint8[m_pitch * m_height];
- }
-
- rgb::~rgb()
- {
- if (m_data) {
-// dlfree(m_data);
- delete [] m_data;
- m_data = 0;
- }
- }
-
-
- rgb* create_rgb(int width, int height)
- // Create an system-memory rgb surface. The data order is
- // packed 24-bit, RGBRGB..., regardless of the endian-ness of
- // the CPU.
- {
- rgb* s = new rgb(width, height);
-
- return s;
- }
-
-
- //
- // rgba
- //
-
-
- rgba::rgba(int width, int height)
- :
- image_base(0, width, height, width * 4)
- {
- assert(width > 0);
- assert(height > 0);
- assert(m_pitch >= m_width * 4);
- assert((m_pitch & 3) == 0);
-
-// m_data = (Uint8*) dlmalloc(m_pitch * m_height);
- m_data = new Uint8[m_pitch * m_height];
- }
-
- rgba::~rgba()
- {
- if (m_data) {
-// dlfree(m_data);
- delete [] m_data;
- m_data = 0;
- }
- }
-
-
- rgba* create_rgba(int width, int height)
- // Create an system-memory rgb surface. The data order is
- // packed 32-bit, RGBARGBA..., regardless of the endian-ness
- // of the CPU.
- {
- rgba* s = new rgba(width, height);
-
- return s;
- }
-
-
- void rgba::set_pixel(int x, int y, Uint8 r, Uint8 g, Uint8 b, Uint8
a)
- // Set the pixel at the given position.
- {
- assert(x >= 0 && x < m_width);
- assert(y >= 0 && y < m_height);
-
- Uint8* data = scanline(this, y) + 4 * x;
-
- data[0] = r;
- data[1] = g;
- data[2] = b;
- data[3] = a;
- }
-
-
- //
- // alpha
- //
-
-
- alpha* create_alpha(int width, int height)
- // Create an system-memory 8-bit alpha surface.
- {
- alpha* s = new alpha(width, height);
-
- return s;
- }
-
-
- alpha::alpha(int width, int height)
- :
- image_base(0, width, height, width)
- {
- assert(width > 0);
- assert(height > 0);
-
-// m_data = (Uint8*) dlmalloc(m_pitch * m_height);
- m_data = new Uint8[m_pitch * m_height];
- }
-
-
- alpha::~alpha()
- {
- if (m_data) {
-// dlfree(m_data);
- delete [] m_data;
- m_data = 0;
- }
- }
-
-
- void alpha::set_pixel(int x, int y, Uint8 a)
- // Set the pixel at the given position.
- {
- assert(x >= 0 && x < m_width);
- assert(y >= 0 && y < m_height);
-
- Uint8* data = scanline(this, y) + x;
-
- data[0] = a;
- }
-
-
- bool alpha::operator==(const alpha& a) const
- // Bitwise content comparison.
- {
- if (m_width != a.m_width
- || m_height != a.m_height)
- {
- return false;
- }
-
- for (int j = 0, n = m_height; j < n; j++)
- {
- if (memcmp(scanline(this, j), scanline(&a, j), m_width))
- {
- // Mismatch.
- return false;
- }
- }
-
- // Images are identical.
- return true;
- }
-
-
- unsigned int alpha::compute_hash() const
- // Compute a hash code based on image contents. Can be useful
- // for comparing images.
- {
- unsigned int h = bernstein_hash(&m_width, sizeof(m_width));
- h = bernstein_hash(&m_height, sizeof(m_height), h);
-
- for (int i = 0, n = m_height; i < n; i++)
- {
- h = bernstein_hash(scanline(this, i), m_width, h);
- }
-
- return h;
- }
-
-
- //
- // utility
- //
-
-
- void write_jpeg(tu_file* out, rgb* image, int quality)
- // Write the given image to the given out stream, in jpeg format.
- {
- jpeg::output* j_out = jpeg::output::create(out,
image->m_width, image->m_height, quality);
-
- for (int y = 0; y < image->m_height; y++) {
- j_out->write_scanline(scanline(image, y));
- }
-
- delete j_out;
- }
-
-
- rgb* read_jpeg(const char* filename)
- // Create and read a new image from the given filename, if possible.
- {
- tu_file in(filename, "rb"); // file automatically closes
when 'in' goes out of scope.
- if (! in.get_error())
- {
- rgb* im = read_jpeg(&in);
- return im;
- }
- else
- {
- return NULL;
- }
- }
-
-
- rgb* read_jpeg(tu_file* in)
- // Create and read a new image from the stream.
- {
- jpeg::input* j_in = jpeg::input::create(in);
- if (j_in == NULL) return NULL;
-
- rgb* im = image::create_rgb(j_in->get_width(),
j_in->get_height());
-
- for (int y = 0; y < j_in->get_height(); y++)
- {
- j_in->read_scanline(scanline(im, y));
- }
-
- delete j_in;
-
- return im;
- }
-
-
- rgb* read_swf_jpeg2(tu_file* in)
- // Create and read a new image from the stream. Image is in
- // SWF JPEG2-style format (the encoding tables come first in a
- // separate "stream" -- otherwise it's just normal JPEG). The
- // IJG documentation describes this as "abbreviated" format.
- {
- jpeg::input* j_in =
jpeg::input::create_swf_jpeg2_header_only(in);
- if (j_in == NULL) return NULL;
+// image.cpp -- Thatcher Ulrich <address@hidden> 2002
+
+// This source code has been donated to the Public Domain. Do
+// whatever you want with it.
+
+// Handy image utilities for RGB surfaces.
+
+#include "image.h"
+
+#include "container.h"
+#include "utility.h"
+#include "jpeg.h"
+#include "tu_file.h"
+#include <stdlib.h>
+#include <string.h>
+
+
+namespace image
+{
+ //
+ // image_base
+ //
+ image_base::image_base(Uint8* data, int width, int height, int pitch)
+ :
+ m_data(data),
+ m_width(width),
+ m_height(height),
+ m_pitch(pitch)
+ {
+ }
+
+
+ Uint8* scanline(image_base* surf, int y)
+ {
+ assert(surf);
+ assert(y >= 0 && y < surf->m_height);
+ return ((Uint8*) surf->m_data) + surf->m_pitch * y;
+ }
+
+
+ const Uint8* scanline(const image_base* surf, int y)
+ {
+ assert(surf);
+ assert(y >= 0 && y < surf->m_height);
+ return ((const Uint8*) surf->m_data) + surf->m_pitch * y;
+ }
+
+
+ //
+ // rgb
+ //
+
+ rgb::rgb(int width, int height)
+ :
+ image_base(
+ 0,
+ width,
+ height,
+ (width * 3 + 3) & ~3) // round pitch up to nearest
4-byte boundary
+ {
+ assert(width > 0);
+ assert(height > 0);
+ assert(m_pitch >= m_width * 3);
+ assert((m_pitch & 3) == 0);
+
+// m_data = (Uint8*) dlmalloc(m_pitch * m_height);
+ m_data = new Uint8[m_pitch * m_height];
+ }
+
+ rgb::~rgb()
+ {
+ if (m_data) {
+// dlfree(m_data);
+ delete [] m_data;
+ m_data = 0;
+ }
+ }
+
+
+ rgb* create_rgb(int width, int height)
+ // Create an system-memory rgb surface. The data order is
+ // packed 24-bit, RGBRGB..., regardless of the endian-ness of
+ // the CPU.
+ {
+ rgb* s = new rgb(width, height);
+
+ return s;
+ }
+
+
+ //
+ // rgba
+ //
+
+
+ rgba::rgba(int width, int height)
+ :
+ image_base(0, width, height, width * 4)
+ {
+ assert(width > 0);
+ assert(height > 0);
+ assert(m_pitch >= m_width * 4);
+ assert((m_pitch & 3) == 0);
+
+// m_data = (Uint8*) dlmalloc(m_pitch * m_height);
+ m_data = new Uint8[m_pitch * m_height];
+ }
+
+ rgba::~rgba()
+ {
+ if (m_data) {
+// dlfree(m_data);
+ delete [] m_data;
+ m_data = 0;
+ }
+ }
+
+
+ rgba* create_rgba(int width, int height)
+ // Create an system-memory rgb surface. The data order is
+ // packed 32-bit, RGBARGBA..., regardless of the endian-ness
+ // of the CPU.
+ {
+ rgba* s = new rgba(width, height);
+
+ return s;
+ }
+
+
+ void rgba::set_pixel(int x, int y, Uint8 r, Uint8 g, Uint8 b, Uint8
a)
+ // Set the pixel at the given position.
+ {
+ assert(x >= 0 && x < m_width);
+ assert(y >= 0 && y < m_height);
+
+ Uint8* data = scanline(this, y) + 4 * x;
+
+ data[0] = r;
+ data[1] = g;
+ data[2] = b;
+ data[3] = a;
+ }
+
+
+ //
+ // alpha
+ //
+
+
+ alpha* create_alpha(int width, int height)
+ // Create an system-memory 8-bit alpha surface.
+ {
+ alpha* s = new alpha(width, height);
+
+ return s;
+ }
+
+
+ alpha::alpha(int width, int height)
+ :
+ image_base(0, width, height, width)
+ {
+ assert(width > 0);
+ assert(height > 0);
+
+// m_data = (Uint8*) dlmalloc(m_pitch * m_height);
+ m_data = new Uint8[m_pitch * m_height];
+ }
+
+
+ alpha::~alpha()
+ {
+ if (m_data) {
+// dlfree(m_data);
+ delete [] m_data;
+ m_data = 0;
+ }
+ }
+
+
+ void alpha::set_pixel(int x, int y, Uint8 a)
+ // Set the pixel at the given position.
+ {
+ assert(x >= 0 && x < m_width);
+ assert(y >= 0 && y < m_height);
+
+ Uint8* data = scanline(this, y) + x;
+
+ data[0] = a;
+ }
+
+
+ bool alpha::operator==(const alpha& a) const
+ // Bitwise content comparison.
+ {
+ if (m_width != a.m_width
+ || m_height != a.m_height)
+ {
+ return false;
+ }
+
+ for (int j = 0, n = m_height; j < n; j++)
+ {
+ if (memcmp(scanline(this, j), scanline(&a, j), m_width))
+ {
+ // Mismatch.
+ return false;
+ }
+ }
+
+ // Images are identical.
+ return true;
+ }
+
+
+ unsigned int alpha::compute_hash() const
+ // Compute a hash code based on image contents. Can be useful
+ // for comparing images.
+ {
+ unsigned int h = bernstein_hash(&m_width, sizeof(m_width));
+ h = bernstein_hash(&m_height, sizeof(m_height), h);
+
+ for (int i = 0, n = m_height; i < n; i++)
+ {
+ h = bernstein_hash(scanline(this, i), m_width, h);
+ }
+
+ return h;
+ }
+
+
+ //
+ // utility
+ //
+
+
+ void write_jpeg(tu_file* out, rgb* image, int quality)
+ // Write the given image to the given out stream, in jpeg format.
+ {
+ jpeg::output* j_out = jpeg::output::create(out,
image->m_width, image->m_height, quality);
+
+ for (int y = 0; y < image->m_height; y++) {
+ j_out->write_scanline(scanline(image, y));
+ }
+
+ delete j_out;
+ }
+
+
+ rgb* read_jpeg(const char* filename)
+ // Create and read a new image from the given filename, if possible.
+ {
+ tu_file in(filename, "rb"); // file automatically closes
when 'in' goes out of scope.
+ if (! in.get_error())
+ {
+ rgb* im = read_jpeg(&in);
+ return im;
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+
+
+ rgb* read_jpeg(tu_file* in)
+ // Create and read a new image from the stream.
+ {
+ jpeg::input* j_in = jpeg::input::create(in);
+ if (j_in == NULL) return NULL;
+
+ rgb* im = image::create_rgb(j_in->get_width(),
j_in->get_height());
+
+ for (int y = 0; y < j_in->get_height(); y++)
+ {
+ j_in->read_scanline(scanline(im, y));
+ }
+
+ delete j_in;
+
+ return im;
+ }
+
+
+ rgb* read_swf_jpeg2(tu_file* in)
+ // Create and read a new image from the stream. Image is in
+ // SWF JPEG2-style format (the encoding tables come first in a
+ // separate "stream" -- otherwise it's just normal JPEG). The
+ // IJG documentation describes this as "abbreviated" format.
+ {
+ jpeg::input* j_in =
jpeg::input::create_swf_jpeg2_header_only(in);
+ if (j_in == NULL) return NULL;
rgb* im = read_swf_jpeg2_with_tables(j_in);
-
- delete j_in;
-
+
+ delete j_in;
+
return im;
- }
-
-
- rgb* read_swf_jpeg2_with_tables(jpeg::input* j_in)
- // Create and read a new image, using a input object that
- // already has tables loaded.
- {
- assert(j_in);
-
- j_in->start_image();
-
- rgb* im = image::create_rgb(j_in->get_width(),
j_in->get_height());
-
- for (int y = 0; y < j_in->get_height(); y++) {
- j_in->read_scanline(scanline(im, y));
- }
-
- j_in->finish_image();
-
- return im;
- }
-
-
- rgba* read_swf_jpeg3(tu_file* in)
- // For reading SWF JPEG3-style image data, like ordinary JPEG,
- // but stores the data in rgba format.
- {
- jpeg::input* j_in =
jpeg::input::create_swf_jpeg2_header_only(in);
- if (j_in == NULL) return NULL;
-
- j_in->start_image();
-
- rgba* im = image::create_rgba(j_in->get_width(),
j_in->get_height());
-
- Uint8* line = new Uint8[3*j_in->get_width()];
-
- for (int y = 0; y < j_in->get_height(); y++)
- {
- j_in->read_scanline(line);
-
- Uint8* data = scanline(im, y);
- for (int x = 0; x < j_in->get_width(); x++)
- {
- data[4*x+0] = line[3*x+0];
- data[4*x+1] = line[3*x+1];
- data[4*x+2] = line[3*x+2];
- data[4*x+3] = 255;
- }
- }
-
- delete [] line;
-
- j_in->finish_image();
- delete j_in;
-
- return im;
- }
-
-
- void write_tga(tu_file* out, rgba* im)
- // Write a 32-bit Targa format bitmap. Dead simple, no compression.
- {
- out->write_byte(0);
- out->write_byte(0);
- out->write_byte(2); /* uncompressed RGB */
- out->write_le16(0);
- out->write_le16(0);
- out->write_byte(0);
- out->write_le16(0); /* X origin */
- out->write_le16(0); /* y origin */
- out->write_le16(im->m_width);
- out->write_le16(im->m_height);
- out->write_byte(32); /* 32 bit bitmap */
- out->write_byte(0);
-
- for (int y = 0; y < im->m_height; y++)
- {
- uint8* p = scanline(im, y);
- for (int x = 0; x < im->m_width; x++)
- {
- out->write_byte(p[x * 4]);
- out->write_byte(p[x * 4 + 1]);
- out->write_byte(p[x * 4 + 2]);
- out->write_byte(p[x * 4 + 3]);
- }
- }
- }
-
-
-#if 0
- SDL_Surface* create_SDL_Surface(rgb* image)
- // Steal *image's data to create an SDL_Surface.
- //
- // DELETES image!!!
- {
- assert(image->m_pitch < 65536); // SDL_Surface only uses Uint16
for pitch!!!
-
- SDL_Surface* s = SDL_CreateRGBSurfaceFrom(image->m_data,
- image->m_width,
image->m_height, 24, image->m_pitch,
-
SDL_SwapLE32(0x0FF),
-
SDL_SwapLE32(0x0FF00),
-
SDL_SwapLE32(0x0FF0000),
- 0);
-
- // s owns *image's data now -- invalidate *image.
- image->m_data = 0;
- image->m_height = 0;
- image->m_width = 0;
- image->m_pitch = 0;
- delete image;
-
- assert(s->pixels);
- assert(s->format->BytesPerPixel == 3);
- assert(s->format->BitsPerPixel == 24);
-
- return s;
- }
-#endif // 0
-
- void make_next_miplevel(rgb* image)
- // Fast, in-place resample. For making mip-maps. Munges the
- // input image to produce the output image.
- {
- assert(image->m_data);
-
- int new_w = image->m_width >> 1;
- int new_h = image->m_height >> 1;
- if (new_w < 1) new_w = 1;
- if (new_h < 1) new_h = 1;
-
- int new_pitch = new_w * 3;
- // Round pitch up to the nearest 4-byte boundary.
- new_pitch = (new_pitch + 3) & ~3;
-
- if (new_w * 2 != image->m_width || new_h * 2 !=
image->m_height)
- {
- // Image can't be shrunk along (at least) one
- // of its dimensions, so don't bother
- // resampling. Technically we should, but
- // it's pretty useless at this point. Just
- // change the image dimensions and leave the
- // existing pixels.
- }
- else
- {
- // Resample. Simple average 2x2 --> 1, in-place.
- int pitch = image->m_pitch;
- for (int j = 0; j < new_h; j++) {
- Uint8* out = ((Uint8*) image->m_data) + j *
new_pitch;
- Uint8* in = ((Uint8*) image->m_data) + (j <<
1) * pitch;
- for (int i = 0; i < new_w; i++) {
- int r, g, b;
- r = (*(in + 0) + *(in + 3) + *(in + 0 +
pitch) + *(in + 3 + pitch));
- g = (*(in + 1) + *(in + 4) + *(in + 1 +
pitch) + *(in + 4 + pitch));
- b = (*(in + 2) + *(in + 5) + *(in + 2 +
pitch) + *(in + 5 + pitch));
- *(out + 0) = r >> 2;
- *(out + 1) = g >> 2;
- *(out + 2) = b >> 2;
- out += 3;
- in += 6;
- }
- }
- }
-
- // Munge image's members to reflect the shrunken image.
- image->m_width = new_w;
- image->m_height = new_h;
- image->m_pitch = new_pitch;
- }
-
-
- void make_next_miplevel(rgba* image)
- // Fast, in-place resample. For making mip-maps. Munges the
- // input image to produce the output image.
- {
- assert(image->m_data);
-
- int new_w = image->m_width >> 1;
- int new_h = image->m_height >> 1;
- if (new_w < 1) new_w = 1;
- if (new_h < 1) new_h = 1;
-
- int new_pitch = new_w * 4;
-
- if (new_w * 2 != image->m_width || new_h * 2 !=
image->m_height)
- {
- // Image can't be shrunk along (at least) one
- // of its dimensions, so don't bother
- // resampling. Technically we should, but
- // it's pretty useless at this point. Just
- // change the image dimensions and leave the
- // existing pixels.
- }
- else
- {
- // Resample. Simple average 2x2 --> 1, in-place.
- int pitch = image->m_pitch;
- for (int j = 0; j < new_h; j++) {
- Uint8* out = ((Uint8*) image->m_data) + j *
new_pitch;
- Uint8* in = ((Uint8*) image->m_data) + (j <<
1) * pitch;
- for (int i = 0; i < new_w; i++) {
- int r, g, b, a;
- r = (*(in + 0) + *(in + 4) + *(in + 0 +
pitch) + *(in + 4 + pitch));
- g = (*(in + 1) + *(in + 5) + *(in + 1 +
pitch) + *(in + 5 + pitch));
- b = (*(in + 2) + *(in + 6) + *(in + 2 +
pitch) + *(in + 6 + pitch));
- a = (*(in + 3) + *(in + 7) + *(in + 3 +
pitch) + *(in + 7 + pitch));
- *(out + 0) = r >> 2;
- *(out + 1) = g >> 2;
- *(out + 2) = b >> 2;
- *(out + 3) = a >> 2;
- out += 4;
- in += 8;
- }
- }
- }
-
- // Munge image's members to reflect the shrunken image.
- image->m_width = new_w;
- image->m_height = new_h;
- image->m_pitch = new_pitch;
- }
-};
-
-
-// Local Variables:
-// mode: C++
-// c-basic-offset: 8
-// tab-width: 8
-// indent-tabs-mode: t
-// End:
+ }
+
+
+ rgb* read_swf_jpeg2_with_tables(jpeg::input* j_in)
+ // Create and read a new image, using a input object that
+ // already has tables loaded.
+ {
+ assert(j_in);
+
+ j_in->start_image();
+
+ rgb* im = image::create_rgb(j_in->get_width(),
j_in->get_height());
+
+ for (int y = 0; y < j_in->get_height(); y++) {
+ j_in->read_scanline(scanline(im, y));
+ }
+
+ j_in->finish_image();
+
+ return im;
+ }
+
+
+ rgba* read_swf_jpeg3(tu_file* in)
+ // For reading SWF JPEG3-style image data, like ordinary JPEG,
+ // but stores the data in rgba format.
+ {
+ jpeg::input* j_in =
jpeg::input::create_swf_jpeg2_header_only(in);
+ if (j_in == NULL) return NULL;
+
+ j_in->start_image();
+
+ rgba* im = image::create_rgba(j_in->get_width(),
j_in->get_height());
+
+ Uint8* line = new Uint8[3*j_in->get_width()];
+
+ for (int y = 0; y < j_in->get_height(); y++)
+ {
+ j_in->read_scanline(line);
+
+ Uint8* data = scanline(im, y);
+ for (int x = 0; x < j_in->get_width(); x++)
+ {
+ data[4*x+0] = line[3*x+0];
+ data[4*x+1] = line[3*x+1];
+ data[4*x+2] = line[3*x+2];
+ data[4*x+3] = 255;
+ }
+ }
+
+ delete [] line;
+
+ j_in->finish_image();
+ delete j_in;
+
+ return im;
+ }
+
+
+ void write_tga(tu_file* out, rgba* im)
+ // Write a 32-bit Targa format bitmap. Dead simple, no compression.
+ {
+ out->write_byte(0);
+ out->write_byte(0);
+ out->write_byte(2); /* uncompressed RGB */
+ out->write_le16(0);
+ out->write_le16(0);
+ out->write_byte(0);
+ out->write_le16(0); /* X origin */
+ out->write_le16(0); /* y origin */
+ out->write_le16(im->m_width);
+ out->write_le16(im->m_height);
+ out->write_byte(32); /* 32 bit bitmap */
+ out->write_byte(0);
+
+ for (int y = 0; y < im->m_height; y++)
+ {
+ uint8* p = scanline(im, y);
+ for (int x = 0; x < im->m_width; x++)
+ {
+ out->write_byte(p[x * 4]);
+ out->write_byte(p[x * 4 + 1]);
+ out->write_byte(p[x * 4 + 2]);
+ out->write_byte(p[x * 4 + 3]);
+ }
+ }
+ }
+
+
+#if 0
+ SDL_Surface* create_SDL_Surface(rgb* image)
+ // Steal *image's data to create an SDL_Surface.
+ //
+ // DELETES image!!!
+ {
+ assert(image->m_pitch < 65536); // SDL_Surface only uses Uint16
for pitch!!!
+
+ SDL_Surface* s = SDL_CreateRGBSurfaceFrom(image->m_data,
+ image->m_width,
image->m_height, 24, image->m_pitch,
+
SDL_SwapLE32(0x0FF),
+
SDL_SwapLE32(0x0FF00),
+
SDL_SwapLE32(0x0FF0000),
+ 0);
+
+ // s owns *image's data now -- invalidate *image.
+ image->m_data = 0;
+ image->m_height = 0;
+ image->m_width = 0;
+ image->m_pitch = 0;
+ delete image;
+
+ assert(s->pixels);
+ assert(s->format->BytesPerPixel == 3);
+ assert(s->format->BitsPerPixel == 24);
+
+ return s;
+ }
+#endif // 0
+
+ void make_next_miplevel(rgb* image)
+ // Fast, in-place resample. For making mip-maps. Munges the
+ // input image to produce the output image.
+ {
+ assert(image->m_data);
+
+ int new_w = image->m_width >> 1;
+ int new_h = image->m_height >> 1;
+ if (new_w < 1) new_w = 1;
+ if (new_h < 1) new_h = 1;
+
+ int new_pitch = new_w * 3;
+ // Round pitch up to the nearest 4-byte boundary.
+ new_pitch = (new_pitch + 3) & ~3;
+
+ if (new_w * 2 != image->m_width || new_h * 2 !=
image->m_height)
+ {
+ // Image can't be shrunk along (at least) one
+ // of its dimensions, so don't bother
+ // resampling. Technically we should, but
+ // it's pretty useless at this point. Just
+ // change the image dimensions and leave the
+ // existing pixels.
+ }
+ else
+ {
+ // Resample. Simple average 2x2 --> 1, in-place.
+ int pitch = image->m_pitch;
+ for (int j = 0; j < new_h; j++) {
+ Uint8* out = ((Uint8*) image->m_data) + j *
new_pitch;
+ Uint8* in = ((Uint8*) image->m_data) + (j <<
1) * pitch;
+ for (int i = 0; i < new_w; i++) {
+ int r, g, b;
+ r = (*(in + 0) + *(in + 3) + *(in + 0 +
pitch) + *(in + 3 + pitch));
+ g = (*(in + 1) + *(in + 4) + *(in + 1 +
pitch) + *(in + 4 + pitch));
+ b = (*(in + 2) + *(in + 5) + *(in + 2 +
pitch) + *(in + 5 + pitch));
+ *(out + 0) = r >> 2;
+ *(out + 1) = g >> 2;
+ *(out + 2) = b >> 2;
+ out += 3;
+ in += 6;
+ }
+ }
+ }
+
+ // Munge image's members to reflect the shrunken image.
+ image->m_width = new_w;
+ image->m_height = new_h;
+ image->m_pitch = new_pitch;
+ }
+
+
+ void make_next_miplevel(rgba* image)
+ // Fast, in-place resample. For making mip-maps. Munges the
+ // input image to produce the output image.
+ {
+ assert(image->m_data);
+
+ int new_w = image->m_width >> 1;
+ int new_h = image->m_height >> 1;
+ if (new_w < 1) new_w = 1;
+ if (new_h < 1) new_h = 1;
+
+ int new_pitch = new_w * 4;
+
+ if (new_w * 2 != image->m_width || new_h * 2 !=
image->m_height)
+ {
+ // Image can't be shrunk along (at least) one
+ // of its dimensions, so don't bother
+ // resampling. Technically we should, but
+ // it's pretty useless at this point. Just
+ // change the image dimensions and leave the
+ // existing pixels.
+ }
+ else
+ {
+ // Resample. Simple average 2x2 --> 1, in-place.
+ int pitch = image->m_pitch;
+ for (int j = 0; j < new_h; j++) {
+ Uint8* out = ((Uint8*) image->m_data) + j *
new_pitch;
+ Uint8* in = ((Uint8*) image->m_data) + (j <<
1) * pitch;
+ for (int i = 0; i < new_w; i++) {
+ int r, g, b, a;
+ r = (*(in + 0) + *(in + 4) + *(in + 0 +
pitch) + *(in + 4 + pitch));
+ g = (*(in + 1) + *(in + 5) + *(in + 1 +
pitch) + *(in + 5 + pitch));
+ b = (*(in + 2) + *(in + 6) + *(in + 2 +
pitch) + *(in + 6 + pitch));
+ a = (*(in + 3) + *(in + 7) + *(in + 3 +
pitch) + *(in + 7 + pitch));
+ *(out + 0) = r >> 2;
+ *(out + 1) = g >> 2;
+ *(out + 2) = b >> 2;
+ *(out + 3) = a >> 2;
+ out += 4;
+ in += 8;
+ }
+ }
+ }
+
+ // Munge image's members to reflect the shrunken image.
+ image->m_width = new_w;
+ image->m_height = new_h;
+ image->m_pitch = new_pitch;
+ }
+};
+
+
+// Local Variables:
+// mode: C++
+// c-basic-offset: 8
+// tab-width: 8
+// indent-tabs-mode: t
+// End:
Index: gnash/libbase/image_filters.cpp
diff -u gnash/libbase/image_filters.cpp:1.3 gnash/libbase/image_filters.cpp:1.4
--- gnash/libbase/image_filters.cpp:1.3 Sat Feb 25 03:54:03 2006
+++ gnash/libbase/image_filters.cpp Sun Feb 26 15:49:30 2006
@@ -1,825 +1,825 @@
-// image_filters.cpp -- Original code by Dale Schumacher, public domain 1991
-
-// See _Graphics Gems III_ "General Filtered Image Rescaling", Dale A.
Schumacher
-
-// Modifications by Thatcher Ulrich <address@hidden> 2002
-
-// This source code has been donated to the Public Domain. Do
-// whatever you want with it.
-
-// A series of image rescaling functions. tulrich: Mostly I just
-// converted from K&R C to C-like C++, changed the interfaces a bit,
-// etc.
-
-
-#include "image.h"
-#include "utility.h"
-#include "container.h"
-#include "tu_math.h"
-#include <stdio.h>
-#include <string.h>
-
-
-namespace {
-// anonymous namespace to hold local stuff.
-
-
-inline void* my_calloc(int count, int size)
-{
- void* mem = (void*) new char[count * size];
- memset(mem, 0, count * size);
- return mem;
-}
-
-
-inline void my_cfree(void* mem)
-{
- delete [] (char*) mem;
-}
-
-
-void get_row(Uint8* row, image::rgb* image, int x0, int xsize, int y)
-// Copy RGB data from the specified row into the given buffer.
-{
- y = iclamp(y, 0, image->m_height - 1);
- int x1 = x0 + xsize - 1;
- if (x1 >= image->m_width) {
- // clip, then extend.
- int extra_pixels = x1 - image->m_width + 1;
- Uint8* p = ((Uint8*) image->m_data) + (y * image->m_pitch);
- memcpy(row, p + x0 * 3, (3 * (image->m_width - x0)));
- // repeat last pixel
- p = p + (image->m_width - 1) * 3;
- Uint8* q = row + (image->m_width - x0) * 3;
- while (extra_pixels > 0) {
- *(q + 0) = *(p + 0);
- *(q + 1) = *(p + 1);
- *(q + 2) = *(p + 2);
- q += 3;
- extra_pixels--;
- }
- }
- else
- {
- memcpy(row, ((Uint8*) image->m_data) + (y * image->m_pitch) +
x0 * 3, (3 * xsize));
- }
-}
-
-
-void get_row(Uint8* row, image::rgba* image, int x0, int xsize, int y)
-// Copy RGBA data from the specified row into the given buffer.
-{
- y = iclamp(y, 0, image->m_height - 1);
- int x1 = x0 + xsize - 1;
- if (x1 >= image->m_width) {
- // clip, then extend.
- int extra_pixels = x1 - image->m_width + 1;
- Uint8* p = ((Uint8*) image->m_data) + (y * image->m_pitch);
- memcpy(row, p + x0 * 4, (4 * (image->m_width - x0)));
- // repeat last pixel
- p = p + (image->m_width - 1) * 4;
- Uint8* q = row + (image->m_width - x0) * 4;
- while (extra_pixels > 0) {
- *(q + 0) = *(p + 0);
- *(q + 1) = *(p + 1);
- *(q + 2) = *(p + 2);
- *(q + 3) = *(p + 3);
- q += 4;
- extra_pixels--;
- }
- }
- else
- {
- memcpy(row, ((Uint8*) image->m_data) + (y * image->m_pitch) +
x0 * 4, (4 * xsize));
- }
-}
-
-
-void get_column(Uint8* column, image::rgb* image, int x)
-// Copy RGB data from the specified column into the given buffer.
-{
- int i, d;
- Uint8* p;
-
- if ((x < 0) || (x >= image->m_width)) {
- assert(0);
- x = iclamp(x, 0, image->m_width - 1);
- }
-
- d = image->m_pitch;
- for (i = image->m_height, p = ((Uint8*) image->m_data) + x * 3; i-- >
0; p += d) {
- *column++ = *p;
- *column++ = *(p + 1);
- *column++ = *(p + 2);
- }
-}
-
-
-void get_column(Uint8* column, image::rgba* image, int x)
-// Copy RGBA data from the specified column into the given buffer.
-{
- int i, d;
- Uint8* p;
-
- if ((x < 0) || (x >= image->m_width)) {
- assert(0);
- x = iclamp(x, 0, image->m_width - 1);
- }
-
- d = image->m_pitch;
- for (i = image->m_height, p = ((Uint8*) image->m_data) + x * 4; i-- >
0; p += d) {
- *column++ = *p;
- *column++ = *(p + 1);
- *column++ = *(p + 2);
- *column++ = *(p + 3);
- }
-}
-
-
-void put_pixel(image::rgb* image, int x, int y, float r, float g, float b)
-// Clamp {r, g, b} to [0,255], and write pixel data to the given image
-// at (x, y).
-{
- static image::rgb* im = NULL;
- static int yy = -1;
- static Uint8* p = NULL;
-
- if ((x < 0) || (x >= image->m_width) || (y < 0) || (y >=
image->m_height)) {
- assert(0);
- return;
- }
- if ((im != image) || (yy != y)) {
- im = image;
- yy = y;
- p = ((Uint8*) image->m_data) + (y * image->m_pitch);
- }
- p[x * 3 + 0] = iclamp(frnd(r), 0, 255);
- p[x * 3 + 1] = iclamp(frnd(g), 0, 255);
- p[x * 3 + 2] = iclamp(frnd(b), 0, 255);
-}
-
-
-void put_pixel(image::rgba* image, int x, int y, float r, float g, float b,
float a)
-// Clamp {r, g, b, a} to [0,255], and write pixel data to the given image
-// at (x, y).
-{
- static image::rgba* im = NULL;
- static int yy = -1;
- static Uint8* p = NULL;
-
- if ((x < 0) || (x >= image->m_width) || (y < 0) || (y >=
image->m_height)) {
- assert(0);
- return;
- }
- if ((im != image) || (yy != y)) {
- im = image;
- yy = y;
- p = ((Uint8*) image->m_data) + (y * image->m_pitch);
- }
- p[x * 4 + 0] = iclamp(frnd(r), 0, 255);
- p[x * 4 + 1] = iclamp(frnd(g), 0, 255);
- p[x * 4 + 2] = iclamp(frnd(b), 0, 255);
- p[x * 4 + 3] = iclamp(frnd(a), 0, 255);
-}
-
-
-/*
- * filter function definitions
- */
-
-
-// SOME_CUBIC
-
-#define cubic_filter_support (1.0f)
-
-float cubic_filter(float t)
-// Cubix approximation to the central hump of Sinc.
-{
- /* f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1 */
- if(t < 0.0f) t = -t;
- if(t < 1.0f) return((2.0f * t - 3.0f) * t * t + 1.0f);
- return(0.0f);
-}
-
-
-// BOX
-
-#define box_support (0.5f)
-
-float box_filter(float t)
-{
- if((t > -0.5) && (t <= 0.5)) return(1.0);
- return(0.0);
-}
-
-
-// TRIANGLE
-
-#define triangle_support (1.0)
-
-float triangle_filter(float t)
-{
- if(t < 0.0f) t = -t;
- if(t < 1.0f) return(1.0f - t);
- return(0.0f);
-}
-
-
-// BELL
-
-#define bell_support (1.5)
-
-float bell_filter(float t)
-/* box (*) box (*) box */
-{
- if(t < 0) t = -t;
- if(t < 0.5f) return(0.75f - (t * t));
- if(t < 1.5f) {
- t = (t - 1.5f);
- return(0.5f * (t * t));
- }
- return(0.0f);
-}
-
-
-// B_SPLINE
-
-#define B_spline_support (2.0f)
-
-float B_spline_filter(float t)
-/* box (*) box (*) box (*) box */
-{
- float tt;
-
- if(t < 0.0f) t = -t;
- if(t < 1.0f) {
- tt = t * t;
- return((0.5f * tt * t) - tt + (2.0f / 3.0f));
- } else if (t < 2.0f) {
- t = 2.0f - t;
- return((1.0f / 6.0f) * (t * t * t));
- }
- return(0.0f);
-}
-
-
-// LANCZOS3
-
-float sinc(float x)
-{
- x *= (float) M_PI;
- if (x != 0.0f) return(sinf(x) / x);
- return(1.0f);
-}
-
-#define Lanczos3_support (3.0f)
-
-float Lanczos3_filter(float t)
-{
- if (t < 0.0f) t = -t;
- if (t < 3.0f) return(sinc(t) * sinc(t/3.0f));
- return(0.0f);
-}
-
-
-// MITCHELL
-
-#define Mitchell_support (2.0f)
-
-#define B (1.0f / 3.0f)
-#define C (1.0f / 3.0f)
-
-float Mitchell_filter(float t)
-{
- float tt;
-
- tt = t * t;
- if (t < 0.0f) t = -t;
- if (t < 1.0f) {
- t = (((12.0f - 9.0f * B - 6.0f * C) * (t * tt))
- + ((-18.0f + 12.0f * B + 6.0f * C) * tt)
- + (6.0f - 2.0f * B));
- return(t / 6.0f);
- } else if(t < 2.0f) {
- t = (((-1.0f * B - 6.0f * C) * (t * tt))
- + ((6.0f * B + 30.0f * C) * tt)
- + ((-12.0f * B - 48.0f * C) * t)
- + (8.0f * B + 24 * C));
- return(t / 6.0f);
- }
- return(0.0f);
-}
-
-
-struct CONTRIB {
- int pixel;
- float weight;
-
- CONTRIB()
- : pixel(0), weight(0.f)
- {
- }
-
- CONTRIB(int p, float w)
- : pixel(p), weight(w)
- {
- }
-};
-
-
-}; // end anonymous namespace
-
-
-namespace image {
-
-
-enum filter_type {
- FILTER0 = 0,
- BOX = FILTER0,
- TRIANGLE,
- BELL,
- B_SPLINE,
- SOME_CUBIC, // Cubic approximation of Sinc's hump (but no tails).
- LANCZOS3,
- MITCHELL, // This one is alleged to be pretty nice.
-
- FILTER_COUNT
-};
-
-struct {
- float (*filter_function)(float);
- float support;
-} filter_table[] =
-{
- { box_filter, box_support },
- { triangle_filter, triangle_support },
- { bell_filter, bell_support },
- { B_spline_filter, B_spline_support },
- { cubic_filter, cubic_filter_support },
- { Lanczos3_filter, Lanczos3_support },
- { Mitchell_filter, Mitchell_support },
-};
-
-
-// TODO: experiment with different filter functions.
-filter_type default_type = TRIANGLE;
-
-
-void resample(image::rgb* out, int out_x0, int out_y0, int out_x1, int
out_y1,
- image::rgb* in, float in_x0, float in_y0, float in_x1, float
in_y1)
-// Rescale the specified portion of the input image into the specified
-// portion of the output image. Coordinates are *inclusive*.
-{
- assert(out_x0 <= out_x1);
- assert(out_y0 <= out_y1);
- assert(out_x0 >= 0 && out_x0 < out->m_width);
- assert(out_x1 >= 0 && out_x1 < out->m_width);
- assert(out_y0 >= 0 && out_y0 < out->m_height);
- assert(out_y1 >= 0 && out_y1 < out->m_height);
-
- float (*filter_function)(float);
- float support;
-
- // Pick a filter function & support.
- assert(default_type >= FILTER0 && default_type < FILTER_COUNT);
- filter_function = filter_table[default_type].filter_function;
- support = filter_table[default_type].support;
-
-
- image::rgb* tmp; /* intermediate image */
- float xscale, yscale; /* zoom scale factors */
- int i, k; /* loop variables */
- unsigned int j; /* loop variables */
- int n; /* pixel number */
- float center; int left, right; /* filter calculation variables */
- float width, fscale, weight; /* filter calculation variables */
- Uint8* raster; /* a row or column of pixels */
-
- std::vector< std::vector<CONTRIB> > contrib;
-
- int out_width = out_x1 - out_x0 + 1;
- int out_height = out_y1 - out_y0 + 1;
- assert(out_width > 0);
- assert(out_height > 0);
-
- float in_width = in_x1 - in_x0;
- float in_height = in_y1 - in_y0;
- assert(in_width > 0);
- assert(in_height > 0);
-
- int in_window_w = int(ceilf(in_x1) - floorf(in_x0) + 1);
- int in_window_h = int(ceilf(in_y1) - floorf(in_y0) + 1);
-
- /* create intermediate image to hold horizontal zoom */
- tmp = image::create_rgb(out_width, in_window_h);
- xscale = (float) (out_width - 1) / in_width;
- yscale = (float) (out_height - 1) / in_height;
-
- // xxxx protect against division by 0
- if (yscale == 0) { yscale = 1.0f; }
- if (xscale == 0) { xscale = 1.0f; }
-
- /* pre-calculate filter contributions for a row */
- contrib.resize(tmp->m_width);
- if(xscale < 1.0f) {
- width = support / xscale;
- fscale = 1.0f / xscale;
- for (i = 0; i < tmp->m_width; ++i) {
- contrib[i].resize(0);
-
- center = (float) i / xscale;
- left = int(ceilf(center - width));
- right = int(floorf(center + width));
- for (k = left; k <= right; ++k) {
- weight = center - (float) k;
- weight = (*filter_function)(weight / fscale) /
fscale;
- n = iclamp(k, 0, in_window_w - 1);
- contrib[i].push_back(CONTRIB(n, weight));
- }
- }
- } else {
- for (i = 0; i < tmp->m_width; ++i) {
- contrib[i].resize(0);
- center = (float) i / xscale;
- left = int(ceilf(center - support));
- right = int(floorf(center + support));
- for(k = left; k <= right; ++k) {
- weight = center - (float) k;
- weight = (*filter_function)(weight);
- n = iclamp(k, 0, in_window_w - 1);
- contrib[i].push_back(CONTRIB(n, weight));
- }
- }
- }
-
- /* apply filter to zoom horizontally from src to tmp */
- raster = (Uint8*) my_calloc(in_window_w, 3);
- for (k = 0; k < tmp->m_height; ++k) {
- get_row(raster, in, int(floorf(in_x0)), in_window_w, k);
- for (i = 0; i < tmp->m_width; ++i) {
- float red = 0.0f;
- float green = 0.0f;
- float blue = 0.0f;
- for(j = 0; j < contrib[i].size(); ++j) {
- int pixel = contrib[i][j].pixel;
- red += raster[pixel * 3 + 0] *
contrib[i][j].weight;
- green += raster[pixel * 3 + 1] *
contrib[i][j].weight;
- blue += raster[pixel * 3 + 2] *
contrib[i][j].weight;
- }
- put_pixel(tmp, i, k, red, green, blue);
- }
- }
- my_cfree(raster);
-
- contrib.resize(out_height);
-
- if (yscale < 1.0f) {
- width = support / yscale;
- fscale = 1.0f / yscale;
- for (i = 0; i < out_height; ++i) {
- contrib[i].resize(0);
-
- center = (float) i / yscale;
- left = int(ceilf(center - width));
- right = int(floorf(center + width));
- for (k = left; k <= right; ++k) {
- weight = center - (float) k;
- weight = (*filter_function)(weight / fscale) /
fscale;
- n = iclamp(k, 0, tmp->m_height - 1);
- contrib[i].push_back(CONTRIB(n, weight));
- }
- }
- } else {
- for (i = 0; i < out_height; ++i) {
- contrib[i].resize(0);
- center = (float) i / yscale;
- left = int(ceilf(center - support));
- right = int(floorf(center + support));
- for(k = left; k <= right; ++k) {
- weight = center - (float) k;
- weight = (*filter_function)(weight);
- n = iclamp(k, 0, tmp->m_height - 1);
- contrib[i].push_back(CONTRIB(n, weight));
- }
- }
- }
-
- /* apply filter to zoom vertically from tmp to dst */
- raster = (Uint8*) my_calloc(tmp->m_height, 3);
- for (k = 0; k < tmp->m_width; ++k) {
- get_column(raster, tmp, k);
- for (i = 0; i < out_height; ++i) {
- float red = 0.0f;
- float green = 0.0f;
- float blue = 0.0f;
- for (j = 0; j < contrib[i].size(); ++j) {
- int pixel = contrib[i][j].pixel;
- red += raster[pixel * 3 + 0] *
contrib[i][j].weight;
- green += raster[pixel * 3 + 1] *
contrib[i][j].weight;
- blue += raster[pixel * 3 + 2] *
contrib[i][j].weight;
- }
- put_pixel(out, k + out_x0, i + out_y0, red, green,
blue);
- }
- }
- my_cfree(raster);
-
- contrib.resize(0);
-
- delete tmp;
-}
-
-
-void resample(image::rgba* out, int out_x0, int out_y0, int out_x1, int
out_y1,
- image::rgba* in, float in_x0, float in_y0, float in_x1, float
in_y1)
-// Rescale the specified portion of the input image into the specified
-// portion of the output image. Coordinates are *inclusive*.
-//
-// Same as above, but with an alpha channel.
-{
- assert(out_x0 <= out_x1);
- assert(out_y0 <= out_y1);
- assert(out_x0 >= 0 && out_x0 < out->m_width);
- assert(out_x1 >= 0 && out_x1 < out->m_width);
- assert(out_y0 >= 0 && out_y0 < out->m_height);
- assert(out_y1 >= 0 && out_y1 < out->m_height);
-
- float (*filter_function)(float);
- float support;
-
- // Pick a filter function & support.
- assert(default_type >= FILTER0 && default_type < FILTER_COUNT);
- filter_function = filter_table[default_type].filter_function;
- support = filter_table[default_type].support;
-
-
- image::rgba* tmp; /* intermediate image */
- float xscale, yscale; /* zoom scale factors */
- int i, k; /* loop variables */
- unsigned int j; /* loop variables */
- int n; /* pixel number */
- float center; int left, right; /* filter calculation variables */
- float width, fscale, weight; /* filter calculation variables */
- Uint8* raster; /* a row or column of pixels */
-
- std::vector< std::vector<CONTRIB> > contrib;
-
- int out_width = out_x1 - out_x0 + 1;
- int out_height = out_y1 - out_y0 + 1;
- assert(out_width > 0);
- assert(out_height > 0);
-
- float in_width = in_x1 - in_x0;
- float in_height = in_y1 - in_y0;
- assert(in_width > 0);
- assert(in_height > 0);
-
- int in_window_w = int(ceilf(in_x1) - floorf(in_x0) + 1);
- int in_window_h = int(ceilf(in_y1) - floorf(in_y0) + 1);
-
- /* create intermediate image to hold horizontal zoom */
- tmp = image::create_rgba(out_width, in_window_h);
- xscale = (float) (out_width - 1) / in_width;
- yscale = (float) (out_height - 1) / in_height;
-
- // xxxx protect against division by 0
- if (yscale == 0) { yscale = 1.0f; }
- if (xscale == 0) { xscale = 1.0f; }
-
- /* pre-calculate filter contributions for a row */
- contrib.resize(tmp->m_width);
- if(xscale < 1.0f) {
- width = support / xscale;
- fscale = 1.0f / xscale;
- for (i = 0; i < tmp->m_width; ++i) {
- contrib[i].resize(0);
-
- center = (float) i / xscale;
- left = int(ceilf(center - width));
- right = int(floorf(center + width));
- for (k = left; k <= right; ++k) {
- weight = center - (float) k;
- weight = (*filter_function)(weight / fscale) /
fscale;
- n = iclamp(k, 0, in_window_w - 1);
- contrib[i].push_back(CONTRIB(n, weight));
- }
- }
- } else {
- for (i = 0; i < tmp->m_width; ++i) {
- contrib[i].resize(0);
- center = (float) i / xscale;
- left = int(ceilf(center - support));
- right = int(floorf(center + support));
- for(k = left; k <= right; ++k) {
- weight = center - (float) k;
- weight = (*filter_function)(weight);
- n = iclamp(k, 0, in_window_w - 1);
- contrib[i].push_back(CONTRIB(n, weight));
- }
- }
- }
-
- /* apply filter to zoom horizontally from src to tmp */
- raster = (Uint8*) my_calloc(in_window_w, 4);
- for (k = 0; k < tmp->m_height; ++k) {
- get_row(raster, in, int(floorf(in_x0)), in_window_w, k);
- for (i = 0; i < tmp->m_width; ++i) {
- float red = 0.0f;
- float green = 0.0f;
- float blue = 0.0f;
- float alpha = 0.0f;
- for(j = 0; j < contrib[i].size(); ++j) {
- int pixel = contrib[i][j].pixel;
- red += raster[pixel * 4 + 0] *
contrib[i][j].weight;
- green += raster[pixel * 4 + 1] *
contrib[i][j].weight;
- blue += raster[pixel * 4 + 2] *
contrib[i][j].weight;
- alpha += raster[pixel * 4 + 3] *
contrib[i][j].weight;
- }
- put_pixel(tmp, i, k, red, green, blue, alpha);
- }
- }
- my_cfree(raster);
-
- contrib.resize(out_height);
-
- if (yscale < 1.0f) {
- width = support / yscale;
- fscale = 1.0f / yscale;
- for (i = 0; i < out_height; ++i) {
- contrib[i].resize(0);
-
- center = (float) i / yscale;
- left = int(ceilf(center - width));
- right = int(floorf(center + width));
- for (k = left; k <= right; ++k) {
- weight = center - (float) k;
- weight = (*filter_function)(weight / fscale) /
fscale;
- n = iclamp(k, 0, tmp->m_height - 1);
- contrib[i].push_back(CONTRIB(n, weight));
- }
- }
- } else {
- for (i = 0; i < out_height; ++i) {
- contrib[i].resize(0);
- center = (float) i / yscale;
- left = int(ceilf(center - support));
- right = int(floorf(center + support));
- for(k = left; k <= right; ++k) {
- weight = center - (float) k;
- weight = (*filter_function)(weight);
- n = iclamp(k, 0, tmp->m_height - 1);
- contrib[i].push_back(CONTRIB(n, weight));
- }
- }
- }
-
- /* apply filter to zoom vertically from tmp to dst */
- raster = (Uint8*) my_calloc(tmp->m_height, 4);
- for (k = 0; k < tmp->m_width; ++k) {
- get_column(raster, tmp, k);
- for (i = 0; i < out_height; ++i) {
- float red = 0.0f;
- float green = 0.0f;
- float blue = 0.0f;
- float alpha = 0.0f;
- for (j = 0; j < contrib[i].size(); ++j) {
- int pixel = contrib[i][j].pixel;
- red += raster[pixel * 4 + 0] *
contrib[i][j].weight;
- green += raster[pixel * 4 + 1] *
contrib[i][j].weight;
- blue += raster[pixel * 4 + 2] *
contrib[i][j].weight;
- alpha += raster[pixel * 4 + 3] *
contrib[i][j].weight;
- }
- put_pixel(out, k + out_x0, i + out_y0, red, green,
blue, alpha);
- }
- }
- my_cfree(raster);
-
- contrib.resize(0);
-
- delete tmp;
-}
-
-
-
-// tulrich: some interesting scaling code from Vitaly. Looks like a
-// fast bilinear scale using fixed point. I haven't validated this
-// myself. Note: I would see about losing the sax & say arrays, and
-// fold that stuff directly into the pixel loops, to get rid of the
-// mallocs.
-
-void zoom(image::rgba* src, image::rgba* dst)
-{
- typedef struct
- {
- Uint8 r;
- Uint8 g;
- Uint8 b;
- Uint8 a;
- }
- rgba;
-
- int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy, ex, ey, t1, t2;
- rgba *c00, *c01, *c10, *c11, *sp, *csp, *dp;
- int sgap, dgap;
-
- /* For interpolation: assume source dimension is one pixel */
- /* smaller to avoid overflow on right and bottom edge. */
- sx = (int) (65536.0 * (float) (src->m_width - 1) / (float) dst->m_width);
- sy = (int) (65536.0 * (float) (src->m_height - 1) / (float)
dst->m_height);
-
- /* Allocate memory for row increments */
- sax = (int*) malloc ((dst->m_width + 1) * sizeof (Uint32));
- say = (int*) malloc ((dst->m_height + 1) * sizeof (Uint32));
-
- /* Precalculate row increments */
- csx = 0;
- csax = sax;
- for (x = 0; x <= dst->m_width; x++)
- {
- *csax = csx;
- csax++;
- csx &= 0xffff;
- csx += sx;
- }
- csy = 0;
- csay = say;
- for (y = 0; y <= dst->m_height; y++)
- {
- *csay = csy;
- csay++;
- csy &= 0xffff;
- csy += sy;
- }
-
- /* Pointer setup */
- sp = csp = (rgba *) src->m_data;
- dp = (rgba *) dst->m_data;
- sgap = src->m_pitch - src->m_width * 4;
- dgap = dst->m_pitch - dst->m_width * 4;
-
- /* Interpolating Zoom */
- /* Scan destination */
- csay = say;
- for (y = 0; y < dst->m_height; y++)
- {
- /* Setup color source pointers */
- c00 = csp;
- c01 = csp;
- c01++;
- c10 = (rgba *) ((Uint8 *) csp + src->m_pitch);
- c11 = c10;
- c11++;
- csax = sax;
- for (x = 0; x < dst->m_width; x++)
- {
- /* ABGR ordering */
- /* Interpolate colors */
- ex = (*csax & 0xffff);
- ey = (*csay & 0xffff);
- t1 = ((((c01->r - c00->r) * ex) >> 16) + c00->r) & 0xff;
- t2 = ((((c11->r - c10->r) * ex) >> 16) + c10->r) & 0xff;
- dp->r = (((t2 - t1) * ey) >> 16) + t1;
- t1 = ((((c01->g - c00->g) * ex) >> 16) + c00->g) & 0xff;
- t2 = ((((c11->g - c10->g) * ex) >> 16) + c10->g) & 0xff;
- dp->g = (((t2 - t1) * ey) >> 16) + t1;
- t1 = ((((c01->b - c00->b) * ex) >> 16) + c00->b) & 0xff;
- t2 = ((((c11->b - c10->b) * ex) >> 16) + c10->b) & 0xff;
- dp->b = (((t2 - t1) * ey) >> 16) + t1;
- t1 = ((((c01->a - c00->a) * ex) >> 16) + c00->a) & 0xff;
- t2 = ((((c11->a - c10->a) * ex) >> 16) + c10->a) & 0xff;
- dp->a = (((t2 - t1) * ey) >> 16) + t1;
-
- /* Advance source pointers */
- csax++;
- int sstep = (*csax >> 16);
- c00 += sstep;
- c01 += sstep;
- c10 += sstep;
- c11 += sstep;
- /* Advance destination pointer */
- dp++;
- }
- /* Advance source pointer */
- csay++;
- csp = (rgba *) ((Uint8 *) csp + (*csay >> 16) * src->m_pitch);
- /* Advance destination pointers */
- dp = (rgba *) ((Uint8 *) dp + dgap);
- }
-
- /* Remove temp arrays */
- free (sax);
- free (say);
-}
-
-
-
-} // end namespace image
-
-
-
-// Local Variables:
-// mode: C++
-// c-basic-offset: 8
-// tab-width: 8
-// indent-tabs-mode: t
-// End:
-
+// image_filters.cpp -- Original code by Dale Schumacher, public domain 1991
+
+// See _Graphics Gems III_ "General Filtered Image Rescaling", Dale A.
Schumacher
+
+// Modifications by Thatcher Ulrich <address@hidden> 2002
+
+// This source code has been donated to the Public Domain. Do
+// whatever you want with it.
+
+// A series of image rescaling functions. tulrich: Mostly I just
+// converted from K&R C to C-like C++, changed the interfaces a bit,
+// etc.
+
+
+#include "image.h"
+#include "utility.h"
+#include "container.h"
+#include "tu_math.h"
+#include <stdio.h>
+#include <string.h>
+
+
+namespace {
+// anonymous namespace to hold local stuff.
+
+
+inline void* my_calloc(int count, int size)
+{
+ void* mem = (void*) new char[count * size];
+ memset(mem, 0, count * size);
+ return mem;
+}
+
+
+inline void my_cfree(void* mem)
+{
+ delete [] (char*) mem;
+}
+
+
+void get_row(Uint8* row, image::rgb* image, int x0, int xsize, int y)
+// Copy RGB data from the specified row into the given buffer.
+{
+ y = iclamp(y, 0, image->m_height - 1);
+ int x1 = x0 + xsize - 1;
+ if (x1 >= image->m_width) {
+ // clip, then extend.
+ int extra_pixels = x1 - image->m_width + 1;
+ Uint8* p = ((Uint8*) image->m_data) + (y * image->m_pitch);
+ memcpy(row, p + x0 * 3, (3 * (image->m_width - x0)));
+ // repeat last pixel
+ p = p + (image->m_width - 1) * 3;
+ Uint8* q = row + (image->m_width - x0) * 3;
+ while (extra_pixels > 0) {
+ *(q + 0) = *(p + 0);
+ *(q + 1) = *(p + 1);
+ *(q + 2) = *(p + 2);
+ q += 3;
+ extra_pixels--;
+ }
+ }
+ else
+ {
+ memcpy(row, ((Uint8*) image->m_data) + (y * image->m_pitch) +
x0 * 3, (3 * xsize));
+ }
+}
+
+
+void get_row(Uint8* row, image::rgba* image, int x0, int xsize, int y)
+// Copy RGBA data from the specified row into the given buffer.
+{
+ y = iclamp(y, 0, image->m_height - 1);
+ int x1 = x0 + xsize - 1;
+ if (x1 >= image->m_width) {
+ // clip, then extend.
+ int extra_pixels = x1 - image->m_width + 1;
+ Uint8* p = ((Uint8*) image->m_data) + (y * image->m_pitch);
+ memcpy(row, p + x0 * 4, (4 * (image->m_width - x0)));
+ // repeat last pixel
+ p = p + (image->m_width - 1) * 4;
+ Uint8* q = row + (image->m_width - x0) * 4;
+ while (extra_pixels > 0) {
+ *(q + 0) = *(p + 0);
+ *(q + 1) = *(p + 1);
+ *(q + 2) = *(p + 2);
+ *(q + 3) = *(p + 3);
+ q += 4;
+ extra_pixels--;
+ }
+ }
+ else
+ {
+ memcpy(row, ((Uint8*) image->m_data) + (y * image->m_pitch) +
x0 * 4, (4 * xsize));
+ }
+}
+
+
+void get_column(Uint8* column, image::rgb* image, int x)
+// Copy RGB data from the specified column into the given buffer.
+{
+ int i, d;
+ Uint8* p;
+
+ if ((x < 0) || (x >= image->m_width)) {
+ assert(0);
+ x = iclamp(x, 0, image->m_width - 1);
+ }
+
+ d = image->m_pitch;
+ for (i = image->m_height, p = ((Uint8*) image->m_data) + x * 3; i-- >
0; p += d) {
+ *column++ = *p;
+ *column++ = *(p + 1);
+ *column++ = *(p + 2);
+ }
+}
+
+
+void get_column(Uint8* column, image::rgba* image, int x)
+// Copy RGBA data from the specified column into the given buffer.
+{
+ int i, d;
+ Uint8* p;
+
+ if ((x < 0) || (x >= image->m_width)) {
+ assert(0);
+ x = iclamp(x, 0, image->m_width - 1);
+ }
+
+ d = image->m_pitch;
+ for (i = image->m_height, p = ((Uint8*) image->m_data) + x * 4; i-- >
0; p += d) {
+ *column++ = *p;
+ *column++ = *(p + 1);
+ *column++ = *(p + 2);
+ *column++ = *(p + 3);
+ }
+}
+
+
+void put_pixel(image::rgb* image, int x, int y, float r, float g, float b)
+// Clamp {r, g, b} to [0,255], and write pixel data to the given image
+// at (x, y).
+{
+ static image::rgb* im = NULL;
+ static int yy = -1;
+ static Uint8* p = NULL;
+
+ if ((x < 0) || (x >= image->m_width) || (y < 0) || (y >=
image->m_height)) {
+ assert(0);
+ return;
+ }
+ if ((im != image) || (yy != y)) {
+ im = image;
+ yy = y;
+ p = ((Uint8*) image->m_data) + (y * image->m_pitch);
+ }
+ p[x * 3 + 0] = iclamp(frnd(r), 0, 255);
+ p[x * 3 + 1] = iclamp(frnd(g), 0, 255);
+ p[x * 3 + 2] = iclamp(frnd(b), 0, 255);
+}
+
+
+void put_pixel(image::rgba* image, int x, int y, float r, float g, float b,
float a)
+// Clamp {r, g, b, a} to [0,255], and write pixel data to the given image
+// at (x, y).
+{
+ static image::rgba* im = NULL;
+ static int yy = -1;
+ static Uint8* p = NULL;
+
+ if ((x < 0) || (x >= image->m_width) || (y < 0) || (y >=
image->m_height)) {
+ assert(0);
+ return;
+ }
+ if ((im != image) || (yy != y)) {
+ im = image;
+ yy = y;
+ p = ((Uint8*) image->m_data) + (y * image->m_pitch);
+ }
+ p[x * 4 + 0] = iclamp(frnd(r), 0, 255);
+ p[x * 4 + 1] = iclamp(frnd(g), 0, 255);
+ p[x * 4 + 2] = iclamp(frnd(b), 0, 255);
+ p[x * 4 + 3] = iclamp(frnd(a), 0, 255);
+}
+
+
+/*
+ * filter function definitions
+ */
+
+
+// SOME_CUBIC
+
+#define cubic_filter_support (1.0f)
+
+float cubic_filter(float t)
+// Cubix approximation to the central hump of Sinc.
+{
+ /* f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1 */
+ if(t < 0.0f) t = -t;
+ if(t < 1.0f) return((2.0f * t - 3.0f) * t * t + 1.0f);
+ return(0.0f);
+}
+
+
+// BOX
+
+#define box_support (0.5f)
+
+float box_filter(float t)
+{
+ if((t > -0.5) && (t <= 0.5)) return(1.0);
+ return(0.0);
+}
+
+
+// TRIANGLE
+
+#define triangle_support (1.0)
+
+float triangle_filter(float t)
+{
+ if(t < 0.0f) t = -t;
+ if(t < 1.0f) return(1.0f - t);
+ return(0.0f);
+}
+
+
+// BELL
+
+#define bell_support (1.5)
+
+float bell_filter(float t)
+/* box (*) box (*) box */
+{
+ if(t < 0) t = -t;
+ if(t < 0.5f) return(0.75f - (t * t));
+ if(t < 1.5f) {
+ t = (t - 1.5f);
+ return(0.5f * (t * t));
+ }
+ return(0.0f);
+}
+
+
+// B_SPLINE
+
+#define B_spline_support (2.0f)
+
+float B_spline_filter(float t)
+/* box (*) box (*) box (*) box */
+{
+ float tt;
+
+ if(t < 0.0f) t = -t;
+ if(t < 1.0f) {
+ tt = t * t;
+ return((0.5f * tt * t) - tt + (2.0f / 3.0f));
+ } else if (t < 2.0f) {
+ t = 2.0f - t;
+ return((1.0f / 6.0f) * (t * t * t));
+ }
+ return(0.0f);
+}
+
+
+// LANCZOS3
+
+float sinc(float x)
+{
+ x *= (float) M_PI;
+ if (x != 0.0f) return(sinf(x) / x);
+ return(1.0f);
+}
+
+#define Lanczos3_support (3.0f)
+
+float Lanczos3_filter(float t)
+{
+ if (t < 0.0f) t = -t;
+ if (t < 3.0f) return(sinc(t) * sinc(t/3.0f));
+ return(0.0f);
+}
+
+
+// MITCHELL
+
+#define Mitchell_support (2.0f)
+
+#define B (1.0f / 3.0f)
+#define C (1.0f / 3.0f)
+
+float Mitchell_filter(float t)
+{
+ float tt;
+
+ tt = t * t;
+ if (t < 0.0f) t = -t;
+ if (t < 1.0f) {
+ t = (((12.0f - 9.0f * B - 6.0f * C) * (t * tt))
+ + ((-18.0f + 12.0f * B + 6.0f * C) * tt)
+ + (6.0f - 2.0f * B));
+ return(t / 6.0f);
+ } else if(t < 2.0f) {
+ t = (((-1.0f * B - 6.0f * C) * (t * tt))
+ + ((6.0f * B + 30.0f * C) * tt)
+ + ((-12.0f * B - 48.0f * C) * t)
+ + (8.0f * B + 24 * C));
+ return(t / 6.0f);
+ }
+ return(0.0f);
+}
+
+
+struct CONTRIB {
+ int pixel;
+ float weight;
+
+ CONTRIB()
+ : pixel(0), weight(0.f)
+ {
+ }
+
+ CONTRIB(int p, float w)
+ : pixel(p), weight(w)
+ {
+ }
+};
+
+
+}; // end anonymous namespace
+
+
+namespace image {
+
+
+enum filter_type {
+ FILTER0 = 0,
+ BOX = FILTER0,
+ TRIANGLE,
+ BELL,
+ B_SPLINE,
+ SOME_CUBIC, // Cubic approximation of Sinc's hump (but no tails).
+ LANCZOS3,
+ MITCHELL, // This one is alleged to be pretty nice.
+
+ FILTER_COUNT
+};
+
+struct {
+ float (*filter_function)(float);
+ float support;
+} filter_table[] =
+{
+ { box_filter, box_support },
+ { triangle_filter, triangle_support },
+ { bell_filter, bell_support },
+ { B_spline_filter, B_spline_support },
+ { cubic_filter, cubic_filter_support },
+ { Lanczos3_filter, Lanczos3_support },
+ { Mitchell_filter, Mitchell_support },
+};
+
+
+// TODO: experiment with different filter functions.
+filter_type default_type = TRIANGLE;
+
+
+void resample(image::rgb* out, int out_x0, int out_y0, int out_x1, int
out_y1,
+ image::rgb* in, float in_x0, float in_y0, float in_x1, float
in_y1)
+// Rescale the specified portion of the input image into the specified
+// portion of the output image. Coordinates are *inclusive*.
+{
+ assert(out_x0 <= out_x1);
+ assert(out_y0 <= out_y1);
+ assert(out_x0 >= 0 && out_x0 < out->m_width);
+ assert(out_x1 >= 0 && out_x1 < out->m_width);
+ assert(out_y0 >= 0 && out_y0 < out->m_height);
+ assert(out_y1 >= 0 && out_y1 < out->m_height);
+
+ float (*filter_function)(float);
+ float support;
+
+ // Pick a filter function & support.
+ assert(default_type >= FILTER0 && default_type < FILTER_COUNT);
+ filter_function = filter_table[default_type].filter_function;
+ support = filter_table[default_type].support;
+
+
+ image::rgb* tmp; /* intermediate image */
+ float xscale, yscale; /* zoom scale factors */
+ int i, k; /* loop variables */
+ unsigned int j; /* loop variables */
+ int n; /* pixel number */
+ float center; int left, right; /* filter calculation variables */
+ float width, fscale, weight; /* filter calculation variables */
+ Uint8* raster; /* a row or column of pixels */
+
+ std::vector< std::vector<CONTRIB> > contrib;
+
+ int out_width = out_x1 - out_x0 + 1;
+ int out_height = out_y1 - out_y0 + 1;
+ assert(out_width > 0);
+ assert(out_height > 0);
+
+ float in_width = in_x1 - in_x0;
+ float in_height = in_y1 - in_y0;
+ assert(in_width > 0);
+ assert(in_height > 0);
+
+ int in_window_w = int(ceilf(in_x1) - floorf(in_x0) + 1);
+ int in_window_h = int(ceilf(in_y1) - floorf(in_y0) + 1);
+
+ /* create intermediate image to hold horizontal zoom */
+ tmp = image::create_rgb(out_width, in_window_h);
+ xscale = (float) (out_width - 1) / in_width;
+ yscale = (float) (out_height - 1) / in_height;
+
+ // xxxx protect against division by 0
+ if (yscale == 0) { yscale = 1.0f; }
+ if (xscale == 0) { xscale = 1.0f; }
+
+ /* pre-calculate filter contributions for a row */
+ contrib.resize(tmp->m_width);
+ if(xscale < 1.0f) {
+ width = support / xscale;
+ fscale = 1.0f / xscale;
+ for (i = 0; i < tmp->m_width; ++i) {
+ contrib[i].resize(0);
+
+ center = (float) i / xscale;
+ left = int(ceilf(center - width));
+ right = int(floorf(center + width));
+ for (k = left; k <= right; ++k) {
+ weight = center - (float) k;
+ weight = (*filter_function)(weight / fscale) /
fscale;
+ n = iclamp(k, 0, in_window_w - 1);
+ contrib[i].push_back(CONTRIB(n, weight));
+ }
+ }
+ } else {
+ for (i = 0; i < tmp->m_width; ++i) {
+ contrib[i].resize(0);
+ center = (float) i / xscale;
+ left = int(ceilf(center - support));
+ right = int(floorf(center + support));
+ for(k = left; k <= right; ++k) {
+ weight = center - (float) k;
+ weight = (*filter_function)(weight);
+ n = iclamp(k, 0, in_window_w - 1);
+ contrib[i].push_back(CONTRIB(n, weight));
+ }
+ }
+ }
+
+ /* apply filter to zoom horizontally from src to tmp */
+ raster = (Uint8*) my_calloc(in_window_w, 3);
+ for (k = 0; k < tmp->m_height; ++k) {
+ get_row(raster, in, int(floorf(in_x0)), in_window_w, k);
+ for (i = 0; i < tmp->m_width; ++i) {
+ float red = 0.0f;
+ float green = 0.0f;
+ float blue = 0.0f;
+ for(j = 0; j < contrib[i].size(); ++j) {
+ int pixel = contrib[i][j].pixel;
+ red += raster[pixel * 3 + 0] *
contrib[i][j].weight;
+ green += raster[pixel * 3 + 1] *
contrib[i][j].weight;
+ blue += raster[pixel * 3 + 2] *
contrib[i][j].weight;
+ }
+ put_pixel(tmp, i, k, red, green, blue);
+ }
+ }
+ my_cfree(raster);
+
+ contrib.resize(out_height);
+
+ if (yscale < 1.0f) {
+ width = support / yscale;
+ fscale = 1.0f / yscale;
+ for (i = 0; i < out_height; ++i) {
+ contrib[i].resize(0);
+
+ center = (float) i / yscale;
+ left = int(ceilf(center - width));
+ right = int(floorf(center + width));
+ for (k = left; k <= right; ++k) {
+ weight = center - (float) k;
+ weight = (*filter_function)(weight / fscale) /
fscale;
+ n = iclamp(k, 0, tmp->m_height - 1);
+ contrib[i].push_back(CONTRIB(n, weight));
+ }
+ }
+ } else {
+ for (i = 0; i < out_height; ++i) {
+ contrib[i].resize(0);
+ center = (float) i / yscale;
+ left = int(ceilf(center - support));
+ right = int(floorf(center + support));
+ for(k = left; k <= right; ++k) {
+ weight = center - (float) k;
+ weight = (*filter_function)(weight);
+ n = iclamp(k, 0, tmp->m_height - 1);
+ contrib[i].push_back(CONTRIB(n, weight));
+ }
+ }
+ }
+
+ /* apply filter to zoom vertically from tmp to dst */
+ raster = (Uint8*) my_calloc(tmp->m_height, 3);
+ for (k = 0; k < tmp->m_width; ++k) {
+ get_column(raster, tmp, k);
+ for (i = 0; i < out_height; ++i) {
+ float red = 0.0f;
+ float green = 0.0f;
+ float blue = 0.0f;
+ for (j = 0; j < contrib[i].size(); ++j) {
+ int pixel = contrib[i][j].pixel;
+ red += raster[pixel * 3 + 0] *
contrib[i][j].weight;
+ green += raster[pixel * 3 + 1] *
contrib[i][j].weight;
+ blue += raster[pixel * 3 + 2] *
contrib[i][j].weight;
+ }
+ put_pixel(out, k + out_x0, i + out_y0, red, green,
blue);
+ }
+ }
+ my_cfree(raster);
+
+ contrib.resize(0);
+
+ delete tmp;
+}
+
+
+void resample(image::rgba* out, int out_x0, int out_y0, int out_x1, int
out_y1,
+ image::rgba* in, float in_x0, float in_y0, float in_x1, float
in_y1)
+// Rescale the specified portion of the input image into the specified
+// portion of the output image. Coordinates are *inclusive*.
+//
+// Same as above, but with an alpha channel.
+{
+ assert(out_x0 <= out_x1);
+ assert(out_y0 <= out_y1);
+ assert(out_x0 >= 0 && out_x0 < out->m_width);
+ assert(out_x1 >= 0 && out_x1 < out->m_width);
+ assert(out_y0 >= 0 && out_y0 < out->m_height);
+ assert(out_y1 >= 0 && out_y1 < out->m_height);
+
+ float (*filter_function)(float);
+ float support;
+
+ // Pick a filter function & support.
+ assert(default_type >= FILTER0 && default_type < FILTER_COUNT);
+ filter_function = filter_table[default_type].filter_function;
+ support = filter_table[default_type].support;
+
+
+ image::rgba* tmp; /* intermediate image */
+ float xscale, yscale; /* zoom scale factors */
+ int i, k; /* loop variables */
+ unsigned int j; /* loop variables */
+ int n; /* pixel number */
+ float center; int left, right; /* filter calculation variables */
+ float width, fscale, weight; /* filter calculation variables */
+ Uint8* raster; /* a row or column of pixels */
+
+ std::vector< std::vector<CONTRIB> > contrib;
+
+ int out_width = out_x1 - out_x0 + 1;
+ int out_height = out_y1 - out_y0 + 1;
+ assert(out_width > 0);
+ assert(out_height > 0);
+
+ float in_width = in_x1 - in_x0;
+ float in_height = in_y1 - in_y0;
+ assert(in_width > 0);
+ assert(in_height > 0);
+
+ int in_window_w = int(ceilf(in_x1) - floorf(in_x0) + 1);
+ int in_window_h = int(ceilf(in_y1) - floorf(in_y0) + 1);
+
+ /* create intermediate image to hold horizontal zoom */
+ tmp = image::create_rgba(out_width, in_window_h);
+ xscale = (float) (out_width - 1) / in_width;
+ yscale = (float) (out_height - 1) / in_height;
+
+ // xxxx protect against division by 0
+ if (yscale == 0) { yscale = 1.0f; }
+ if (xscale == 0) { xscale = 1.0f; }
+
+ /* pre-calculate filter contributions for a row */
+ contrib.resize(tmp->m_width);
+ if(xscale < 1.0f) {
+ width = support / xscale;
+ fscale = 1.0f / xscale;
+ for (i = 0; i < tmp->m_width; ++i) {
+ contrib[i].resize(0);
+
+ center = (float) i / xscale;
+ left = int(ceilf(center - width));
+ right = int(floorf(center + width));
+ for (k = left; k <= right; ++k) {
+ weight = center - (float) k;
+ weight = (*filter_function)(weight / fscale) /
fscale;
+ n = iclamp(k, 0, in_window_w - 1);
+ contrib[i].push_back(CONTRIB(n, weight));
+ }
+ }
+ } else {
+ for (i = 0; i < tmp->m_width; ++i) {
+ contrib[i].resize(0);
+ center = (float) i / xscale;
+ left = int(ceilf(center - support));
+ right = int(floorf(center + support));
+ for(k = left; k <= right; ++k) {
+ weight = center - (float) k;
+ weight = (*filter_function)(weight);
+ n = iclamp(k, 0, in_window_w - 1);
+ contrib[i].push_back(CONTRIB(n, weight));
+ }
+ }
+ }
+
+ /* apply filter to zoom horizontally from src to tmp */
+ raster = (Uint8*) my_calloc(in_window_w, 4);
+ for (k = 0; k < tmp->m_height; ++k) {
+ get_row(raster, in, int(floorf(in_x0)), in_window_w, k);
+ for (i = 0; i < tmp->m_width; ++i) {
+ float red = 0.0f;
+ float green = 0.0f;
+ float blue = 0.0f;
+ float alpha = 0.0f;
+ for(j = 0; j < contrib[i].size(); ++j) {
+ int pixel = contrib[i][j].pixel;
+ red += raster[pixel * 4 + 0] *
contrib[i][j].weight;
+ green += raster[pixel * 4 + 1] *
contrib[i][j].weight;
+ blue += raster[pixel * 4 + 2] *
contrib[i][j].weight;
+ alpha += raster[pixel * 4 + 3] *
contrib[i][j].weight;
+ }
+ put_pixel(tmp, i, k, red, green, blue, alpha);
+ }
+ }
+ my_cfree(raster);
+
+ contrib.resize(out_height);
+
+ if (yscale < 1.0f) {
+ width = support / yscale;
+ fscale = 1.0f / yscale;
+ for (i = 0; i < out_height; ++i) {
+ contrib[i].resize(0);
+
+ center = (float) i / yscale;
+ left = int(ceilf(center - width));
+ right = int(floorf(center + width));
+ for (k = left; k <= right; ++k) {
+ weight = center - (float) k;
+ weight = (*filter_function)(weight / fscale) /
fscale;
+ n = iclamp(k, 0, tmp->m_height - 1);
+ contrib[i].push_back(CONTRIB(n, weight));
+ }
+ }
+ } else {
+ for (i = 0; i < out_height; ++i) {
+ contrib[i].resize(0);
+ center = (float) i / yscale;
+ left = int(ceilf(center - support));
+ right = int(floorf(center + support));
+ for(k = left; k <= right; ++k) {
+ weight = center - (float) k;
+ weight = (*filter_function)(weight);
+ n = iclamp(k, 0, tmp->m_height - 1);
+ contrib[i].push_back(CONTRIB(n, weight));
+ }
+ }
+ }
+
+ /* apply filter to zoom vertically from tmp to dst */
+ raster = (Uint8*) my_calloc(tmp->m_height, 4);
+ for (k = 0; k < tmp->m_width; ++k) {
+ get_column(raster, tmp, k);
+ for (i = 0; i < out_height; ++i) {
+ float red = 0.0f;
+ float green = 0.0f;
+ float blue = 0.0f;
+ float alpha = 0.0f;
+ for (j = 0; j < contrib[i].size(); ++j) {
+ int pixel = contrib[i][j].pixel;
+ red += raster[pixel * 4 + 0] *
contrib[i][j].weight;
+ green += raster[pixel * 4 + 1] *
contrib[i][j].weight;
+ blue += raster[pixel * 4 + 2] *
contrib[i][j].weight;
+ alpha += raster[pixel * 4 + 3] *
contrib[i][j].weight;
+ }
+ put_pixel(out, k + out_x0, i + out_y0, red, green,
blue, alpha);
+ }
+ }
+ my_cfree(raster);
+
+ contrib.resize(0);
+
+ delete tmp;
+}
+
+
+
+// tulrich: some interesting scaling code from Vitaly. Looks like a
+// fast bilinear scale using fixed point. I haven't validated this
+// myself. Note: I would see about losing the sax & say arrays, and
+// fold that stuff directly into the pixel loops, to get rid of the
+// mallocs.
+
+void zoom(image::rgba* src, image::rgba* dst)
+{
+ typedef struct
+ {
+ Uint8 r;
+ Uint8 g;
+ Uint8 b;
+ Uint8 a;
+ }
+ rgba;
+
+ int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy, ex, ey, t1, t2;
+ rgba *c00, *c01, *c10, *c11, *sp, *csp, *dp;
+ int sgap, dgap;
+
+ /* For interpolation: assume source dimension is one pixel */
+ /* smaller to avoid overflow on right and bottom edge. */
+ sx = (int) (65536.0 * (float) (src->m_width - 1) / (float) dst->m_width);
+ sy = (int) (65536.0 * (float) (src->m_height - 1) / (float)
dst->m_height);
+
+ /* Allocate memory for row increments */
+ sax = (int*) malloc ((dst->m_width + 1) * sizeof (Uint32));
+ say = (int*) malloc ((dst->m_height + 1) * sizeof (Uint32));
+
+ /* Precalculate row increments */
+ csx = 0;
+ csax = sax;
+ for (x = 0; x <= dst->m_width; x++)
+ {
+ *csax = csx;
+ csax++;
+ csx &= 0xffff;
+ csx += sx;
+ }
+ csy = 0;
+ csay = say;
+ for (y = 0; y <= dst->m_height; y++)
+ {
+ *csay = csy;
+ csay++;
+ csy &= 0xffff;
+ csy += sy;
+ }
+
+ /* Pointer setup */
+ sp = csp = (rgba *) src->m_data;
+ dp = (rgba *) dst->m_data;
+ sgap = src->m_pitch - src->m_width * 4;
+ dgap = dst->m_pitch - dst->m_width * 4;
+
+ /* Interpolating Zoom */
+ /* Scan destination */
+ csay = say;
+ for (y = 0; y < dst->m_height; y++)
+ {
+ /* Setup color source pointers */
+ c00 = csp;
+ c01 = csp;
+ c01++;
+ c10 = (rgba *) ((Uint8 *) csp + src->m_pitch);
+ c11 = c10;
+ c11++;
+ csax = sax;
+ for (x = 0; x < dst->m_width; x++)
+ {
+ /* ABGR ordering */
+ /* Interpolate colors */
+ ex = (*csax & 0xffff);
+ ey = (*csay & 0xffff);
+ t1 = ((((c01->r - c00->r) * ex) >> 16) + c00->r) & 0xff;
+ t2 = ((((c11->r - c10->r) * ex) >> 16) + c10->r) & 0xff;
+ dp->r = (((t2 - t1) * ey) >> 16) + t1;
+ t1 = ((((c01->g - c00->g) * ex) >> 16) + c00->g) & 0xff;
+ t2 = ((((c11->g - c10->g) * ex) >> 16) + c10->g) & 0xff;
+ dp->g = (((t2 - t1) * ey) >> 16) + t1;
+ t1 = ((((c01->b - c00->b) * ex) >> 16) + c00->b) & 0xff;
+ t2 = ((((c11->b - c10->b) * ex) >> 16) + c10->b) & 0xff;
+ dp->b = (((t2 - t1) * ey) >> 16) + t1;
+ t1 = ((((c01->a - c00->a) * ex) >> 16) + c00->a) & 0xff;
+ t2 = ((((c11->a - c10->a) * ex) >> 16) + c10->a) & 0xff;
+ dp->a = (((t2 - t1) * ey) >> 16) + t1;
+
+ /* Advance source pointers */
+ csax++;
+ int sstep = (*csax >> 16);
+ c00 += sstep;
+ c01 += sstep;
+ c10 += sstep;
+ c11 += sstep;
+ /* Advance destination pointer */
+ dp++;
+ }
+ /* Advance source pointer */
+ csay++;
+ csp = (rgba *) ((Uint8 *) csp + (*csay >> 16) * src->m_pitch);
+ /* Advance destination pointers */
+ dp = (rgba *) ((Uint8 *) dp + dgap);
+ }
+
+ /* Remove temp arrays */
+ free (sax);
+ free (say);
+}
+
+
+
+} // end namespace image
+
+
+
+// Local Variables:
+// mode: C++
+// c-basic-offset: 8
+// tab-width: 8
+// indent-tabs-mode: t
+// End:
+
Index: gnash/libbase/jpeg.cpp
diff -u gnash/libbase/jpeg.cpp:1.3 gnash/libbase/jpeg.cpp:1.4
--- gnash/libbase/jpeg.cpp:1.3 Wed Feb 15 03:07:22 2006
+++ gnash/libbase/jpeg.cpp Sun Feb 26 15:49:30 2006
@@ -1,543 +1,543 @@
-// jpeg.cpp -- Thatcher Ulrich <address@hidden> 2002
-
-// This source code has been donated to the Public Domain. Do
-// whatever you want with it.
-
-// Wrapper for jpeg file operations. The actual work is done by the
-// IJG jpeg lib.
-
-
-#include "utility.h"
-#include "jpeg.h"
-#include "tu_file.h"
-#include <stdio.h>
-
-#if TU_CONFIG_LINK_TO_JPEGLIB
-
-extern "C" {
-#include <jpeglib.h>
-}
-
-
-namespace jpeg
-{
- // jpeglib data source constructors, for using tu_file* instead
- // of stdio for jpeg IO.
- void setup_rw_source(jpeg_decompress_struct* cinfo, tu_file*
instream);
- void setup_rw_dest(jpeg_compress_struct* cinfo, tu_file* outstream);
-
-
- // Helper object for reading jpeg image data. Basically a thin
- static const int IO_BUF_SIZE = 4096;
-
- // A jpeglib source manager that reads from a tu_file. Paraphrased
- // from IJG jpeglib jdatasrc.c.
- struct rw_source
- {
- struct jpeg_source_mgr m_pub; /* public fields */
-
- tu_file* m_in_stream; /* source stream */
- bool m_start_of_file; /* have we gotten any
data yet? */
- JOCTET m_buffer[IO_BUF_SIZE]; /* start of buffer */
-
- rw_source(tu_file* in)
- :
- m_in_stream(in),
- m_start_of_file(true)
- // Constructor. The caller is responsible for closing the
input stream
- // after it's done using us.
- {
- // fill in function pointers...
- m_pub.init_source = init_source;
- m_pub.fill_input_buffer = fill_input_buffer;
- m_pub.skip_input_data = skip_input_data;
- m_pub.resync_to_restart = jpeg_resync_to_restart;
// use default method
- m_pub.term_source = term_source;
- m_pub.bytes_in_buffer = 0;
- m_pub.next_input_byte = NULL;
- }
-
- static void init_source(j_decompress_ptr cinfo)
- {
- rw_source* src = (rw_source*) cinfo->src;
- src->m_start_of_file = true;
- }
-
- static boolean fill_input_buffer(j_decompress_ptr cinfo)
- // Read data into our input buffer. Client calls this
- // when it needs more data from the file.
- {
- rw_source* src = (rw_source*) cinfo->src;
-
- size_t bytes_read =
src->m_in_stream->read_bytes(src->m_buffer, IO_BUF_SIZE);
-
- if (bytes_read <= 0) {
- // Is the file completely empty?
- if (src->m_start_of_file) {
- // Treat this as a fatal error.
- throw "empty jpeg source stream.";
- }
- // warn("jpeg end-of-stream");
-
- // Insert a fake EOI marker.
- src->m_buffer[0] = (JOCTET) 0xFF;
- src->m_buffer[1] = (JOCTET) JPEG_EOI;
- bytes_read = 2;
- }
-
- // Hack to work around SWF bug: sometimes data
- // starts with FFD9FFD8, when it should be
- // FFD8FFD9!
- if (src->m_start_of_file && bytes_read >= 4)
- {
- if (src->m_buffer[0] == 0xFF
- && src->m_buffer[1] == 0xD9
- && src->m_buffer[2] == 0xFF
- && src->m_buffer[3] == 0xD8)
- {
- src->m_buffer[1] = 0xD8;
- src->m_buffer[3] = 0xD9;
- }
- }
-
- // Expose buffer state to clients.
- src->m_pub.next_input_byte = src->m_buffer;
- src->m_pub.bytes_in_buffer = bytes_read;
- src->m_start_of_file = false;
-
- return TRUE;
- }
-
- static void skip_input_data(j_decompress_ptr cinfo, long
num_bytes)
- // Called by client when it wants to advance past some
- // uninteresting data.
- {
- rw_source* src = (rw_source*) cinfo->src;
-
- // According to jpeg docs, large skips are
- // infrequent. So let's just do it the simple
- // way.
- if (num_bytes > 0) {
- while (num_bytes > (long)
src->m_pub.bytes_in_buffer) {
- num_bytes -= (long)
src->m_pub.bytes_in_buffer;
- fill_input_buffer(cinfo);
- }
- // Handle remainder.
- src->m_pub.next_input_byte += (size_t)
num_bytes;
- src->m_pub.bytes_in_buffer -= (size_t)
num_bytes;
- }
- }
-
- static void term_source(j_decompress_ptr cinfo)
- // Terminate the source. Make sure we get deleted.
- {
- /*rw_source* src = (rw_source*) cinfo->src;
- assert(src);
-
- // @@ it's kind of bogus to be deleting here
- // -- term_source happens at the end of
- // reading an image, but we're probably going
- // to want to init a source and use it to read
- // many images, without reallocating our
- // buffer.
- delete src;
- cinfo->src = NULL;*/
- }
-
-
- void discard_partial_buffer()
- {
- // Discard existing bytes in our buffer.
- m_pub.bytes_in_buffer = 0;
- m_pub.next_input_byte = NULL;
- }
- };
-
-
- void setup_rw_source(jpeg_decompress_struct* cinfo, tu_file*
instream)
- // Set up the given decompress object to read from the given
- // stream.
- {
- // assert(cinfo->src == NULL);
- cinfo->src = (jpeg_source_mgr*) (new rw_source(instream));
- }
-
-
- // A jpeglib destination manager that writes to a tu_file.
- // Paraphrased from IJG jpeglib jdatadst.c.
- struct rw_dest
- {
- struct jpeg_destination_mgr m_pub; /* public fields */
-
- tu_file* m_out_stream; /* source stream */
- JOCTET m_buffer[IO_BUF_SIZE]; /* start of buffer */
-
- rw_dest(tu_file* out)
- :
- m_out_stream(out)
- // Constructor. The caller is responsible for closing
- // the output stream after it's done using us.
- {
- // fill in function pointers...
- m_pub.init_destination = init_destination;
- m_pub.empty_output_buffer = empty_output_buffer;
- m_pub.term_destination = term_destination;
-
- m_pub.next_output_byte = m_buffer;
- m_pub.free_in_buffer = IO_BUF_SIZE;
- }
-
- static void init_destination(j_compress_ptr cinfo)
- {
- rw_dest* dest = (rw_dest*) cinfo->dest;
- assert(dest);
-
- dest->m_pub.next_output_byte = dest->m_buffer;
- dest->m_pub.free_in_buffer = IO_BUF_SIZE;
- }
-
- static boolean empty_output_buffer(j_compress_ptr cinfo)
- // Write the output buffer into the stream.
- {
- rw_dest* dest = (rw_dest*) cinfo->dest;
- assert(dest);
-
- if (dest->m_out_stream->write_bytes(dest->m_buffer,
IO_BUF_SIZE) != IO_BUF_SIZE)
- {
- // Error.
- // @@ bah, exceptions suck. TODO consider
alternatives.
- throw "jpeg::rw_dest couldn't write data.";
- }
-
- dest->m_pub.next_output_byte = dest->m_buffer;
- dest->m_pub.free_in_buffer = IO_BUF_SIZE;
-
- return TRUE;
- }
-
- static void term_destination(j_compress_ptr cinfo)
- // Terminate the destination. Flush any leftover
- // data, and make sure we get deleted.
- {
- rw_dest* dest = (rw_dest*) cinfo->dest;
- assert(dest);
-
- // Write any remaining data.
- int datacount = IO_BUF_SIZE -
dest->m_pub.free_in_buffer;
- if (datacount > 0) {
- if
(dest->m_out_stream->write_bytes(dest->m_buffer, datacount) != datacount)
- {
- // Error.
- throw "jpeg::rw_dest::term_destination
couldn't write data.";
- }
- }
-
- // Clean ourselves up.
- delete dest;
- cinfo->dest = NULL;
- }
- };
-
-
- void setup_rw_dest(j_compress_ptr cinfo, tu_file* outstream)
- // Set up the given compress object to write to the given
- // output stream.
- {
- cinfo->dest = (jpeg_destination_mgr*) (new rw_dest(outstream));
- }
-
-
- //
- // Error handler
- //
-
-
- void jpeg_error_exit(j_common_ptr cinfo)
- // Called when jpeglib has a fatal error.
- {
- assert(0);
- (*cinfo->err->output_message) (cinfo);
- tu_error_exit(1, "internal error in jpeglib");
- }
-
-
- static void setup_jpeg_err(jpeg_error_mgr* jerr)
- // Set up some error handlers for the jpeg lib.
- {
- // Set up defaults.
- jpeg_std_error(jerr);
-
- jerr->error_exit = jpeg_error_exit;
- }
-
-
- //
- // wrappers
- //
-
-
- struct input_impl : public input
- // Bascially this is a thin wrapper around jpeg_decompress
- // object.
- {
- // State needed for input.
- struct jpeg_decompress_struct m_cinfo;
- struct jpeg_error_mgr m_jerr;
-
- bool m_compressor_opened;
-
-
- enum SWF_DEFINE_BITS_JPEG2 { SWF_JPEG2 };
- enum SWF_DEFINE_BITS_JPEG2_HEADER_ONLY { SWF_JPEG2_HEADER_ONLY
};
-
- input_impl(tu_file* in)
- :
- m_compressor_opened(false)
- // Constructor. Read the header data from in, and
- // prepare to read data.
- {
- setup_jpeg_err(&m_jerr);
- m_cinfo.err = &m_jerr;
-
- // Initialize decompression object.
- jpeg_create_decompress(&m_cinfo);
-
- setup_rw_source(&m_cinfo, in);
-
- start_image();
- }
-
-
- input_impl(SWF_DEFINE_BITS_JPEG2_HEADER_ONLY e, tu_file* in)
- :
- m_compressor_opened(false)
- // The SWF file format stores JPEG images with the
- // encoding tables separate from the image data. This
- // constructor reads the encoding table only and keeps
- // them in this object. You need to call
- // start_image() and finish_image() around any calls
- // to get_width/height/components and read_scanline.
- {
- setup_jpeg_err(&m_jerr);
- m_cinfo.err = &m_jerr;
-
- // Initialize decompression object.
- jpeg_create_decompress(&m_cinfo);
-
- setup_rw_source(&m_cinfo, in);
-
- // Read the encoding tables.
- jpeg_read_header(&m_cinfo, FALSE);
-
- // Don't start reading any image data!
- // App does that manually using start_image.
- }
-
- ~input_impl()
- // Destructor. Clean up our jpeg reader state.
- {
- finish_image();
-
- rw_source* src = (rw_source*) m_cinfo.src;
- delete src;
- m_cinfo.src = NULL;
-
-
- jpeg_destroy_decompress(&m_cinfo);
- }
-
-
- void discard_partial_buffer()
- // Discard any data sitting in our input buffer. Use
- // this before/after reading headers or partial image
- // data, to avoid screwing up future reads.
- {
- rw_source* src = (rw_source*) m_cinfo.src;
-
- // We only have to discard the input buffer after
reading the tables.
- if (src)
- {
- src->discard_partial_buffer();
- }
- }
-
-
- void start_image()
- // This is something you can do with "abbreviated"
- // streams; i.e. if you constructed this inputter
- // using (SWF_JPEG2_HEADER_ONLY) to just load the
- // tables, or if you called finish_image() and want to
- // load another image using the existing tables.
- {
- assert(m_compressor_opened == false);
-
+// jpeg.cpp -- Thatcher Ulrich <address@hidden> 2002
+
+// This source code has been donated to the Public Domain. Do
+// whatever you want with it.
+
+// Wrapper for jpeg file operations. The actual work is done by the
+// IJG jpeg lib.
+
+
+#include "utility.h"
+#include "jpeg.h"
+#include "tu_file.h"
+#include <stdio.h>
+
+#if TU_CONFIG_LINK_TO_JPEGLIB
+
+extern "C" {
+#include <jpeglib.h>
+}
+
+
+namespace jpeg
+{
+ // jpeglib data source constructors, for using tu_file* instead
+ // of stdio for jpeg IO.
+ void setup_rw_source(jpeg_decompress_struct* cinfo, tu_file*
instream);
+ void setup_rw_dest(jpeg_compress_struct* cinfo, tu_file* outstream);
+
+
+ // Helper object for reading jpeg image data. Basically a thin
+ static const int IO_BUF_SIZE = 4096;
+
+ // A jpeglib source manager that reads from a tu_file. Paraphrased
+ // from IJG jpeglib jdatasrc.c.
+ struct rw_source
+ {
+ struct jpeg_source_mgr m_pub; /* public fields */
+
+ tu_file* m_in_stream; /* source stream */
+ bool m_start_of_file; /* have we gotten any
data yet? */
+ JOCTET m_buffer[IO_BUF_SIZE]; /* start of buffer */
+
+ rw_source(tu_file* in)
+ :
+ m_in_stream(in),
+ m_start_of_file(true)
+ // Constructor. The caller is responsible for closing the
input stream
+ // after it's done using us.
+ {
+ // fill in function pointers...
+ m_pub.init_source = init_source;
+ m_pub.fill_input_buffer = fill_input_buffer;
+ m_pub.skip_input_data = skip_input_data;
+ m_pub.resync_to_restart = jpeg_resync_to_restart;
// use default method
+ m_pub.term_source = term_source;
+ m_pub.bytes_in_buffer = 0;
+ m_pub.next_input_byte = NULL;
+ }
+
+ static void init_source(j_decompress_ptr cinfo)
+ {
+ rw_source* src = (rw_source*) cinfo->src;
+ src->m_start_of_file = true;
+ }
+
+ static boolean fill_input_buffer(j_decompress_ptr cinfo)
+ // Read data into our input buffer. Client calls this
+ // when it needs more data from the file.
+ {
+ rw_source* src = (rw_source*) cinfo->src;
+
+ size_t bytes_read =
src->m_in_stream->read_bytes(src->m_buffer, IO_BUF_SIZE);
+
+ if (bytes_read <= 0) {
+ // Is the file completely empty?
+ if (src->m_start_of_file) {
+ // Treat this as a fatal error.
+ throw "empty jpeg source stream.";
+ }
+ // warn("jpeg end-of-stream");
+
+ // Insert a fake EOI marker.
+ src->m_buffer[0] = (JOCTET) 0xFF;
+ src->m_buffer[1] = (JOCTET) JPEG_EOI;
+ bytes_read = 2;
+ }
+
+ // Hack to work around SWF bug: sometimes data
+ // starts with FFD9FFD8, when it should be
+ // FFD8FFD9!
+ if (src->m_start_of_file && bytes_read >= 4)
+ {
+ if (src->m_buffer[0] == 0xFF
+ && src->m_buffer[1] == 0xD9
+ && src->m_buffer[2] == 0xFF
+ && src->m_buffer[3] == 0xD8)
+ {
+ src->m_buffer[1] = 0xD8;
+ src->m_buffer[3] = 0xD9;
+ }
+ }
+
+ // Expose buffer state to clients.
+ src->m_pub.next_input_byte = src->m_buffer;
+ src->m_pub.bytes_in_buffer = bytes_read;
+ src->m_start_of_file = false;
+
+ return TRUE;
+ }
+
+ static void skip_input_data(j_decompress_ptr cinfo, long
num_bytes)
+ // Called by client when it wants to advance past some
+ // uninteresting data.
+ {
+ rw_source* src = (rw_source*) cinfo->src;
+
+ // According to jpeg docs, large skips are
+ // infrequent. So let's just do it the simple
+ // way.
+ if (num_bytes > 0) {
+ while (num_bytes > (long)
src->m_pub.bytes_in_buffer) {
+ num_bytes -= (long)
src->m_pub.bytes_in_buffer;
+ fill_input_buffer(cinfo);
+ }
+ // Handle remainder.
+ src->m_pub.next_input_byte += (size_t)
num_bytes;
+ src->m_pub.bytes_in_buffer -= (size_t)
num_bytes;
+ }
+ }
+
+ static void term_source(j_decompress_ptr cinfo)
+ // Terminate the source. Make sure we get deleted.
+ {
+ /*rw_source* src = (rw_source*) cinfo->src;
+ assert(src);
+
+ // @@ it's kind of bogus to be deleting here
+ // -- term_source happens at the end of
+ // reading an image, but we're probably going
+ // to want to init a source and use it to read
+ // many images, without reallocating our
+ // buffer.
+ delete src;
+ cinfo->src = NULL;*/
+ }
+
+
+ void discard_partial_buffer()
+ {
+ // Discard existing bytes in our buffer.
+ m_pub.bytes_in_buffer = 0;
+ m_pub.next_input_byte = NULL;
+ }
+ };
+
+
+ void setup_rw_source(jpeg_decompress_struct* cinfo, tu_file*
instream)
+ // Set up the given decompress object to read from the given
+ // stream.
+ {
+ // assert(cinfo->src == NULL);
+ cinfo->src = (jpeg_source_mgr*) (new rw_source(instream));
+ }
+
+
+ // A jpeglib destination manager that writes to a tu_file.
+ // Paraphrased from IJG jpeglib jdatadst.c.
+ struct rw_dest
+ {
+ struct jpeg_destination_mgr m_pub; /* public fields */
+
+ tu_file* m_out_stream; /* source stream */
+ JOCTET m_buffer[IO_BUF_SIZE]; /* start of buffer */
+
+ rw_dest(tu_file* out)
+ :
+ m_out_stream(out)
+ // Constructor. The caller is responsible for closing
+ // the output stream after it's done using us.
+ {
+ // fill in function pointers...
+ m_pub.init_destination = init_destination;
+ m_pub.empty_output_buffer = empty_output_buffer;
+ m_pub.term_destination = term_destination;
+
+ m_pub.next_output_byte = m_buffer;
+ m_pub.free_in_buffer = IO_BUF_SIZE;
+ }
+
+ static void init_destination(j_compress_ptr cinfo)
+ {
+ rw_dest* dest = (rw_dest*) cinfo->dest;
+ assert(dest);
+
+ dest->m_pub.next_output_byte = dest->m_buffer;
+ dest->m_pub.free_in_buffer = IO_BUF_SIZE;
+ }
+
+ static boolean empty_output_buffer(j_compress_ptr cinfo)
+ // Write the output buffer into the stream.
+ {
+ rw_dest* dest = (rw_dest*) cinfo->dest;
+ assert(dest);
+
+ if (dest->m_out_stream->write_bytes(dest->m_buffer,
IO_BUF_SIZE) != IO_BUF_SIZE)
+ {
+ // Error.
+ // @@ bah, exceptions suck. TODO consider
alternatives.
+ throw "jpeg::rw_dest couldn't write data.";
+ }
+
+ dest->m_pub.next_output_byte = dest->m_buffer;
+ dest->m_pub.free_in_buffer = IO_BUF_SIZE;
+
+ return TRUE;
+ }
+
+ static void term_destination(j_compress_ptr cinfo)
+ // Terminate the destination. Flush any leftover
+ // data, and make sure we get deleted.
+ {
+ rw_dest* dest = (rw_dest*) cinfo->dest;
+ assert(dest);
+
+ // Write any remaining data.
+ int datacount = IO_BUF_SIZE -
dest->m_pub.free_in_buffer;
+ if (datacount > 0) {
+ if
(dest->m_out_stream->write_bytes(dest->m_buffer, datacount) != datacount)
+ {
+ // Error.
+ throw "jpeg::rw_dest::term_destination
couldn't write data.";
+ }
+ }
+
+ // Clean ourselves up.
+ delete dest;
+ cinfo->dest = NULL;
+ }
+ };
+
+
+ void setup_rw_dest(j_compress_ptr cinfo, tu_file* outstream)
+ // Set up the given compress object to write to the given
+ // output stream.
+ {
+ cinfo->dest = (jpeg_destination_mgr*) (new rw_dest(outstream));
+ }
+
+
+ //
+ // Error handler
+ //
+
+
+ void jpeg_error_exit(j_common_ptr cinfo)
+ // Called when jpeglib has a fatal error.
+ {
+ assert(0);
+ (*cinfo->err->output_message) (cinfo);
+ tu_error_exit(1, "internal error in jpeglib");
+ }
+
+
+ static void setup_jpeg_err(jpeg_error_mgr* jerr)
+ // Set up some error handlers for the jpeg lib.
+ {
+ // Set up defaults.
+ jpeg_std_error(jerr);
+
+ jerr->error_exit = jpeg_error_exit;
+ }
+
+
+ //
+ // wrappers
+ //
+
+
+ struct input_impl : public input
+ // Bascially this is a thin wrapper around jpeg_decompress
+ // object.
+ {
+ // State needed for input.
+ struct jpeg_decompress_struct m_cinfo;
+ struct jpeg_error_mgr m_jerr;
+
+ bool m_compressor_opened;
+
+
+ enum SWF_DEFINE_BITS_JPEG2 { SWF_JPEG2 };
+ enum SWF_DEFINE_BITS_JPEG2_HEADER_ONLY { SWF_JPEG2_HEADER_ONLY
};
+
+ input_impl(tu_file* in)
+ :
+ m_compressor_opened(false)
+ // Constructor. Read the header data from in, and
+ // prepare to read data.
+ {
+ setup_jpeg_err(&m_jerr);
+ m_cinfo.err = &m_jerr;
+
+ // Initialize decompression object.
+ jpeg_create_decompress(&m_cinfo);
+
+ setup_rw_source(&m_cinfo, in);
+
+ start_image();
+ }
+
+
+ input_impl(SWF_DEFINE_BITS_JPEG2_HEADER_ONLY e, tu_file* in)
+ :
+ m_compressor_opened(false)
+ // The SWF file format stores JPEG images with the
+ // encoding tables separate from the image data. This
+ // constructor reads the encoding table only and keeps
+ // them in this object. You need to call
+ // start_image() and finish_image() around any calls
+ // to get_width/height/components and read_scanline.
+ {
+ setup_jpeg_err(&m_jerr);
+ m_cinfo.err = &m_jerr;
+
+ // Initialize decompression object.
+ jpeg_create_decompress(&m_cinfo);
+
+ setup_rw_source(&m_cinfo, in);
+
+ // Read the encoding tables.
+ jpeg_read_header(&m_cinfo, FALSE);
+
+ // Don't start reading any image data!
+ // App does that manually using start_image.
+ }
+
+ ~input_impl()
+ // Destructor. Clean up our jpeg reader state.
+ {
+ finish_image();
+
+ rw_source* src = (rw_source*) m_cinfo.src;
+ delete src;
+ m_cinfo.src = NULL;
+
+
+ jpeg_destroy_decompress(&m_cinfo);
+ }
+
+
+ void discard_partial_buffer()
+ // Discard any data sitting in our input buffer. Use
+ // this before/after reading headers or partial image
+ // data, to avoid screwing up future reads.
+ {
+ rw_source* src = (rw_source*) m_cinfo.src;
+
+ // We only have to discard the input buffer after
reading the tables.
+ if (src)
+ {
+ src->discard_partial_buffer();
+ }
+ }
+
+
+ void start_image()
+ // This is something you can do with "abbreviated"
+ // streams; i.e. if you constructed this inputter
+ // using (SWF_JPEG2_HEADER_ONLY) to just load the
+ // tables, or if you called finish_image() and want to
+ // load another image using the existing tables.
+ {
+ assert(m_compressor_opened == false);
+
// Now, read the image header.
jpeg_read_header(&m_cinfo, TRUE);
-
- jpeg_start_decompress(&m_cinfo);
- m_compressor_opened = true;
- }
-
- void finish_image()
- {
- if (m_compressor_opened)
- {
- jpeg_finish_decompress(&m_cinfo);
- m_compressor_opened = false;
- }
- }
-
- int get_height() const
- // Return the height of the image. Take the data from our
m_cinfo struct.
- {
- assert(m_compressor_opened);
- return m_cinfo.output_height;
- }
-
- int get_width() const
- // Return the width of the image. Take the data from our
m_cinfo struct.
- {
- assert(m_compressor_opened);
- return m_cinfo.output_width;
- }
-
- int get_components() const
- // Return number of components (i.e. == 3 for RGB
- // data). The size of the data for a scanline is
- // get_width() * get_components().
- {
- assert(m_compressor_opened);
- return m_cinfo.output_components;
- }
-
-
- void read_scanline(unsigned char* rgb_data)
- // Read a scanline's worth of image data into the
- // given buffer. The amount of data read is
- // get_width() * get_components().
- {
- assert(m_compressor_opened);
- assert(m_cinfo.output_scanline < m_cinfo.output_height);
- int lines_read = jpeg_read_scanlines(&m_cinfo,
&rgb_data, 1);
- assert(lines_read == 1);
- lines_read = lines_read; // avoid warning in
NDEBUG
- }
- };
-
-
- /*static*/ input* input::create(tu_file* in)
- // Create and return a jpeg-input object that will read from the
- // given input stream.
- {
- return new input_impl(in);
- }
-
- /*static*/ input* input::create_swf_jpeg2_header_only(tu_file* in)
- // Read SWF JPEG2-style header. App needs to call
- // start_image() before loading any image data. Multiple
- // images can be loaded by bracketing within
- // start_image()/finish_image() pairs.
- {
- return new input_impl(input_impl::SWF_JPEG2_HEADER_ONLY, in);
- }
-
-
- // Default destructor.
- input::~input() {}
-
-
- struct output_impl : public output
- // Basically this is a thin wrapper around jpeg_compress
- // object.
- {
- // State needed for output.
- struct jpeg_compress_struct m_cinfo;
- struct jpeg_error_mgr m_jerr;
-
- output_impl(tu_file* out, int width, int height, int quality)
- // Constructor. Read the header data from in, and
- // prepare to read data.
- {
- m_cinfo.err = jpeg_std_error(&m_jerr);
-
- // Initialize decompression object.
- jpeg_create_compress(&m_cinfo);
-
- setup_rw_dest(&m_cinfo, out);
- m_cinfo.image_width = width;
- m_cinfo.image_height = height;
- m_cinfo.input_components = 3;
- m_cinfo.in_color_space = JCS_RGB;
- jpeg_set_defaults(&m_cinfo);
- jpeg_set_quality(&m_cinfo, quality, TRUE);
-
- jpeg_start_compress(&m_cinfo, TRUE);
- }
-
-
- ~output_impl()
- // Destructor. Clean up our jpeg reader state.
- {
- jpeg_finish_compress(&m_cinfo);
-/*
- rw_dest* src = (rw_source*) m_cinfo.dest;
- delete dest;
- m_cinfo.dest = NULL;
-*/
- jpeg_destroy_compress(&m_cinfo);
- }
-
-
- void write_scanline(unsigned char* rgb_data)
- // Write out a single scanline.
- {
- jpeg_write_scanlines(&m_cinfo, &rgb_data, 1);
- }
- };
-
-
- /*static*/ output* output::create(tu_file* in, int width, int
height, int quality)
- // Create and return a jpeg-input object that will read from the
- // given input stream.
- {
- return new output_impl(in, width, height, quality);
- }
-
-
- // Default constructor.
- output::~output() {}
-}
-
-
-#else // not TU_CONFIG_LINK_TO_JPEGLIB
-
-
-namespace jpeg
-{
- /*static*/ input* input::create(tu_file* in)
- {
- return NULL;
- }
-
- /*static*/ input* input::create_swf_jpeg2_header_only(tu_file* in)
- {
- return NULL;
- }
-
- /*static*/ output* output::create(tu_file* out, int width, int height,
int quality)
- {
- return NULL;
- }
-
-}
-
-
-#endif // not TU_CONFIG_LINK_TO_JPEGLIB
-
-
-// Local Variables:
-// mode: C++
-// c-basic-offset: 8
-// tab-width: 8
-// indent-tabs-mode: t
-// End:
+
+ jpeg_start_decompress(&m_cinfo);
+ m_compressor_opened = true;
+ }
+
+ void finish_image()
+ {
+ if (m_compressor_opened)
+ {
+ jpeg_finish_decompress(&m_cinfo);
+ m_compressor_opened = false;
+ }
+ }
+
+ int get_height() const
+ // Return the height of the image. Take the data from our
m_cinfo struct.
+ {
+ assert(m_compressor_opened);
+ return m_cinfo.output_height;
+ }
+
+ int get_width() const
+ // Return the width of the image. Take the data from our
m_cinfo struct.
+ {
+ assert(m_compressor_opened);
+ return m_cinfo.output_width;
+ }
+
+ int get_components() const
+ // Return number of components (i.e. == 3 for RGB
+ // data). The size of the data for a scanline is
+ // get_width() * get_components().
+ {
+ assert(m_compressor_opened);
+ return m_cinfo.output_components;
+ }
+
+
+ void read_scanline(unsigned char* rgb_data)
+ // Read a scanline's worth of image data into the
+ // given buffer. The amount of data read is
+ // get_width() * get_components().
+ {
+ assert(m_compressor_opened);
+ assert(m_cinfo.output_scanline < m_cinfo.output_height);
+ int lines_read = jpeg_read_scanlines(&m_cinfo,
&rgb_data, 1);
+ assert(lines_read == 1);
+ lines_read = lines_read; // avoid warning in
NDEBUG
+ }
+ };
+
+
+ /*static*/ input* input::create(tu_file* in)
+ // Create and return a jpeg-input object that will read from the
+ // given input stream.
+ {
+ return new input_impl(in);
+ }
+
+ /*static*/ input* input::create_swf_jpeg2_header_only(tu_file* in)
+ // Read SWF JPEG2-style header. App needs to call
+ // start_image() before loading any image data. Multiple
+ // images can be loaded by bracketing within
+ // start_image()/finish_image() pairs.
+ {
+ return new input_impl(input_impl::SWF_JPEG2_HEADER_ONLY, in);
+ }
+
+
+ // Default destructor.
+ input::~input() {}
+
+
+ struct output_impl : public output
+ // Basically this is a thin wrapper around jpeg_compress
+ // object.
+ {
+ // State needed for output.
+ struct jpeg_compress_struct m_cinfo;
+ struct jpeg_error_mgr m_jerr;
+
+ output_impl(tu_file* out, int width, int height, int quality)
+ // Constructor. Read the header data from in, and
+ // prepare to read data.
+ {
+ m_cinfo.err = jpeg_std_error(&m_jerr);
+
+ // Initialize decompression object.
+ jpeg_create_compress(&m_cinfo);
+
+ setup_rw_dest(&m_cinfo, out);
+ m_cinfo.image_width = width;
+ m_cinfo.image_height = height;
+ m_cinfo.input_components = 3;
+ m_cinfo.in_color_space = JCS_RGB;
+ jpeg_set_defaults(&m_cinfo);
+ jpeg_set_quality(&m_cinfo, quality, TRUE);
+
+ jpeg_start_compress(&m_cinfo, TRUE);
+ }
+
+
+ ~output_impl()
+ // Destructor. Clean up our jpeg reader state.
+ {
+ jpeg_finish_compress(&m_cinfo);
+/*
+ rw_dest* src = (rw_source*) m_cinfo.dest;
+ delete dest;
+ m_cinfo.dest = NULL;
+*/
+ jpeg_destroy_compress(&m_cinfo);
+ }
+
+
+ void write_scanline(unsigned char* rgb_data)
+ // Write out a single scanline.
+ {
+ jpeg_write_scanlines(&m_cinfo, &rgb_data, 1);
+ }
+ };
+
+
+ /*static*/ output* output::create(tu_file* in, int width, int
height, int quality)
+ // Create and return a jpeg-input object that will read from the
+ // given input stream.
+ {
+ return new output_impl(in, width, height, quality);
+ }
+
+
+ // Default constructor.
+ output::~output() {}
+}
+
+
+#else // not TU_CONFIG_LINK_TO_JPEGLIB
+
+
+namespace jpeg
+{
+ /*static*/ input* input::create(tu_file* in)
+ {
+ return NULL;
+ }
+
+ /*static*/ input* input::create_swf_jpeg2_header_only(tu_file* in)
+ {
+ return NULL;
+ }
+
+ /*static*/ output* output::create(tu_file* out, int width, int height,
int quality)
+ {
+ return NULL;
+ }
+
+}
+
+
+#endif // not TU_CONFIG_LINK_TO_JPEGLIB
+
+
+// Local Variables:
+// mode: C++
+// c-basic-offset: 8
+// tab-width: 8
+// indent-tabs-mode: t
+// End:
Index: gnash/libbase/membuf.cpp
diff -u gnash/libbase/membuf.cpp:1.2 gnash/libbase/membuf.cpp:1.3
--- gnash/libbase/membuf.cpp:1.2 Sat Feb 11 01:57:03 2006
+++ gnash/libbase/membuf.cpp Sun Feb 26 15:49:30 2006
@@ -1,166 +1,166 @@
-// membuf.cpp -- Ignacio Castaño, Thatcher Ulrich <address@hidden> 2003
-
-// This source code has been donated to the Public Domain. Do
-// whatever you want with it.
-
-// A simple memory buffer. Similar to a string, but can hold null
-// characters.
-
-
-#include "membuf.h"
-#include "tu_file.h"
-#include "container.h"
-
-
-// Allocate in increments of BLOCKSIZE.
-static const int BLOCKSIZE = (1 << 12);
-
-
-static int capacity(int size)
-// Compute the buffer capacity corresponding to the given size.
-// Basically round up to the next block size.
-// Always return non-zero.
-{
- // BLOCKSIZE must be a power of two.
- compiler_assert((BLOCKSIZE & (BLOCKSIZE - 1)) == 0);
-
- if (size == 0) {
- // Special case, always allocate.
- return BLOCKSIZE;
- }
-
- return (size + BLOCKSIZE - 1) & ~(BLOCKSIZE - 1);
-}
-
-
-membuf::membuf()
- :
- m_size(0),
- m_capacity(0),
- m_data(0),
- m_read_only(false)
-{
-}
-
-
-membuf::membuf(const void* data, int size)
- :
- m_size(0),
- m_capacity(0),
- m_data(0),
- m_read_only(false)
-{
- append(data, size);
-}
-
-
-membuf::membuf(const membuf& buf)
- :
- m_size(0),
- m_capacity(0),
- m_data(0),
- m_read_only(false)
-{
- append(buf);
-}
-
-
-membuf::membuf(const tu_string& str)
- :
- m_size(0),
- m_capacity(0),
- m_data(0),
- m_read_only(false)
-{
- append(str);
-}
-
-
-// Special read-only constructor.
-membuf::membuf(read_only_enum e, const void* data, int size)
- :
- m_size(size),
- m_capacity(0),
- m_data(const_cast<void*>(data)),
- m_read_only(true)
-{
-}
-
-
-membuf::~membuf()
-{
- if (!m_read_only) {
- tu_free(m_data, m_capacity);
- }
- m_capacity = 0;
- m_data = NULL;
-}
-
-
-bool membuf::resize(int new_size)
-{
- assert(!m_read_only);
-
- if (new_size == m_size) {
- return true;
- }
-
- int new_capacity = capacity(new_size);
-
- if (m_data == NULL) {
- m_data = tu_malloc(new_capacity);
- } else {
- if (new_capacity != m_capacity) {
- m_data = tu_realloc(m_data, new_capacity, m_capacity);
- }
- }
- if (m_data == NULL) {
- // malloc/realloc failure!
- m_size = 0;
- m_capacity = 0;
- m_data = NULL;
- return false;
- }
- m_capacity = new_capacity;
-
- assert(m_capacity >= new_size);
-
- m_size = new_size;
-
- return true;
-}
-
-
-bool membuf::append(const void* data, int datasize)
-{
- assert(!m_read_only);
-
- int old_size = size();
- if (resize(size() + datasize) == false) {
- return false;
- }
-
- memcpy(((char*) m_data) + old_size, data, datasize);
-
- return true;
-}
-
-
-bool membuf::append(const membuf& buf)
-{
- return append(buf.data(), buf.size());
-}
-
-
-bool membuf::append(const tu_string& str)
-{
- return append(str.c_str(), str.length());
-}
-
-
-// Local Variables:
-// mode: C++
-// c-basic-offset: 8
-// tab-width: 8
-// indent-tabs-mode: t
-// End:
+// membuf.cpp -- Ignacio Castaño, Thatcher Ulrich <address@hidden> 2003
+
+// This source code has been donated to the Public Domain. Do
+// whatever you want with it.
+
+// A simple memory buffer. Similar to a string, but can hold null
+// characters.
+
+
+#include "membuf.h"
+#include "tu_file.h"
+#include "container.h"
+
+
+// Allocate in increments of BLOCKSIZE.
+static const int BLOCKSIZE = (1 << 12);
+
+
+static int capacity(int size)
+// Compute the buffer capacity corresponding to the given size.
+// Basically round up to the next block size.
+// Always return non-zero.
+{
+ // BLOCKSIZE must be a power of two.
+ compiler_assert((BLOCKSIZE & (BLOCKSIZE - 1)) == 0);
+
+ if (size == 0) {
+ // Special case, always allocate.
+ return BLOCKSIZE;
+ }
+
+ return (size + BLOCKSIZE - 1) & ~(BLOCKSIZE - 1);
+}
+
+
+membuf::membuf()
+ :
+ m_size(0),
+ m_capacity(0),
+ m_data(0),
+ m_read_only(false)
+{
+}
+
+
+membuf::membuf(const void* data, int size)
+ :
+ m_size(0),
+ m_capacity(0),
+ m_data(0),
+ m_read_only(false)
+{
+ append(data, size);
+}
+
+
+membuf::membuf(const membuf& buf)
+ :
+ m_size(0),
+ m_capacity(0),
+ m_data(0),
+ m_read_only(false)
+{
+ append(buf);
+}
+
+
+membuf::membuf(const tu_string& str)
+ :
+ m_size(0),
+ m_capacity(0),
+ m_data(0),
+ m_read_only(false)
+{
+ append(str);
+}
+
+
+// Special read-only constructor.
+membuf::membuf(read_only_enum e, const void* data, int size)
+ :
+ m_size(size),
+ m_capacity(0),
+ m_data(const_cast<void*>(data)),
+ m_read_only(true)
+{
+}
+
+
+membuf::~membuf()
+{
+ if (!m_read_only) {
+ tu_free(m_data, m_capacity);
+ }
+ m_capacity = 0;
+ m_data = NULL;
+}
+
+
+bool membuf::resize(int new_size)
+{
+ assert(!m_read_only);
+
+ if (new_size == m_size) {
+ return true;
+ }
+
+ int new_capacity = capacity(new_size);
+
+ if (m_data == NULL) {
+ m_data = tu_malloc(new_capacity);
+ } else {
+ if (new_capacity != m_capacity) {
+ m_data = tu_realloc(m_data, new_capacity, m_capacity);
+ }
+ }
+ if (m_data == NULL) {
+ // malloc/realloc failure!
+ m_size = 0;
+ m_capacity = 0;
+ m_data = NULL;
+ return false;
+ }
+ m_capacity = new_capacity;
+
+ assert(m_capacity >= new_size);
+
+ m_size = new_size;
+
+ return true;
+}
+
+
+bool membuf::append(const void* data, int datasize)
+{
+ assert(!m_read_only);
+
+ int old_size = size();
+ if (resize(size() + datasize) == false) {
+ return false;
+ }
+
+ memcpy(((char*) m_data) + old_size, data, datasize);
+
+ return true;
+}
+
+
+bool membuf::append(const membuf& buf)
+{
+ return append(buf.data(), buf.size());
+}
+
+
+bool membuf::append(const tu_string& str)
+{
+ return append(str.c_str(), str.length());
+}
+
+
+// Local Variables:
+// mode: C++
+// c-basic-offset: 8
+// tab-width: 8
+// indent-tabs-mode: t
+// End:
Index: gnash/libbase/membuf.h
diff -u gnash/libbase/membuf.h:1.1 gnash/libbase/membuf.h:1.2
--- gnash/libbase/membuf.h:1.1 Tue Dec 20 20:57:00 2005
+++ gnash/libbase/membuf.h Sun Feb 26 15:49:30 2006
@@ -1,64 +1,64 @@
-// membuf.h -- Thatcher Ulrich 2005
-
-// This source code has been donated to the Public Domain. Do
-// whatever you want with it.
-
-// A simple memory buffer. Similar to a string, but can hold null
-// characters.
-
-
-#ifndef MEMBUF_H
-#define MEMBUF_H
-
-
-#include "tu_config.h"
-#include "utility.h"
-
-class tu_string;
-
-
-struct membuf
-{
- membuf();
- membuf(const void* data, int size);
- membuf(const membuf& buf);
- membuf(const tu_string& str);
- ~membuf();
-
- // Construct a read-only membuf that points at the given data,
- // instead of copying it.
- enum read_only_enum { READ_ONLY };
- membuf(read_only_enum e, const void* data, int size);
-
- int size() const { return m_size; }
- const void* data() const { return m_data; }
- void* data() { assert(!m_read_only); return m_data; }
-
- // Don't call these mutators on read-only membufs.
-
- // Return false if we couldn't resize (i.e. realloc failure).
- bool resize(int new_size);
-
- // Return false on realloc failure.
- bool append(const void* data, int size);
- bool append(const membuf& buf);
- // We do not append the terminating '\0'.
- bool append(const tu_string& str);
-
-private:
- int m_size;
- int m_capacity;
- void* m_data;
- bool m_read_only;
-};
-
-
-#endif // MEMBUF_H
-
-
-// Local Variables:
-// mode: C++
-// c-basic-offset: 8
-// tab-width: 8
-// indent-tabs-mode: t
-// End:
+// membuf.h -- Thatcher Ulrich 2005
+
+// This source code has been donated to the Public Domain. Do
+// whatever you want with it.
+
+// A simple memory buffer. Similar to a string, but can hold null
+// characters.
+
+
+#ifndef MEMBUF_H
+#define MEMBUF_H
+
+
+#include "tu_config.h"
+#include "utility.h"
+
+class tu_string;
+
+
+struct membuf
+{
+ membuf();
+ membuf(const void* data, int size);
+ membuf(const membuf& buf);
+ membuf(const tu_string& str);
+ ~membuf();
+
+ // Construct a read-only membuf that points at the given data,
+ // instead of copying it.
+ enum read_only_enum { READ_ONLY };
+ membuf(read_only_enum e, const void* data, int size);
+
+ int size() const { return m_size; }
+ const void* data() const { return m_data; }
+ void* data() { assert(!m_read_only); return m_data; }
+
+ // Don't call these mutators on read-only membufs.
+
+ // Return false if we couldn't resize (i.e. realloc failure).
+ bool resize(int new_size);
+
+ // Return false on realloc failure.
+ bool append(const void* data, int size);
+ bool append(const membuf& buf);
+ // We do not append the terminating '\0'.
+ bool append(const tu_string& str);
+
+private:
+ int m_size;
+ int m_capacity;
+ void* m_data;
+ bool m_read_only;
+};
+
+
+#endif // MEMBUF_H
+
+
+// Local Variables:
+// mode: C++
+// c-basic-offset: 8
+// tab-width: 8
+// indent-tabs-mode: t
+// End:
Index: gnash/libbase/ogl.cpp
diff -u gnash/libbase/ogl.cpp:1.2 gnash/libbase/ogl.cpp:1.3
--- gnash/libbase/ogl.cpp:1.2 Sun Jan 22 16:04:17 2006
+++ gnash/libbase/ogl.cpp Sun Feb 26 15:49:30 2006
@@ -1,445 +1,445 @@
-// ogl.cpp -- by Thatcher Ulrich <address@hidden>
-
-// This source code has been donated to the Public Domain. Do
-// whatever you want with it.
-
-// Some OpenGL helpers; mainly to generically deal with extensions.
-
-
-#include <SDL.h>
-#include "ogl.h"
-#include "utility.h"
-#include <stdlib.h>
-#include <string.h>
-
-
-namespace ogl {
-
- bool is_open = false;
-
- // Pointers to extension functions.
- typedef void * (APIENTRY * PFNWGLALLOCATEMEMORYNVPROC) (int size, float
readfreq, float writefreq, float priority);
- typedef void (APIENTRY * PFNWGLFREEMEMORYNVPROC) (void *pointer);
- typedef void (APIENTRY * PFNGLVERTEXARRAYRANGENVPROC) (int size, void*
buffer);
- typedef void (APIENTRY * PFNGLGENFENCESNVPROC) (GLsizei n, GLuint
*fence_array);
- typedef void (APIENTRY * PFNGLSETFENCENVPROC) (GLuint fence_id, GLenum
condition);
- typedef void (APIENTRY * PFNGLFINISHFENCENVPROC) (GLuint fence_id);
-
- typedef void (APIENTRY * PFNGLACTIVETEXTUREARBPROC) (GLenum texture);
- typedef void (APIENTRY * PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum
texture);
- typedef void (APIENTRY * PFNGLMULTITEXCOORD2FARBPROC) (GLenum target,
GLfloat s, GLfloat t);
- typedef void (APIENTRY * PFNGLMULTITEXCOORD2FVARBPROC) (GLenum target,
const GLfloat *v);
-
- PFNWGLALLOCATEMEMORYNVPROC wglAllocateMemoryNV = 0;
- PFNWGLFREEMEMORYNVPROC wglFreeMemoryNV = 0;
- PFNGLVERTEXARRAYRANGENVPROC glVertexArrayRangeNV = 0;
- PFNGLGENFENCESNVPROC glGenFencesNV = 0;
- PFNGLSETFENCENVPROC glSetFenceNV = 0;
- PFNGLFINISHFENCENVPROC glFinishFenceNV = 0;
-
- PFNGLACTIVETEXTUREARBPROC glActiveTextureARB = 0;
- PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB = 0;
- PFNGLMULTITEXCOORD2FARBPROC glMultiTexCoord2fARB = 0;
- PFNGLMULTITEXCOORD2FVARBPROC glMultiTexCoord2fvARB = 0;
-
-
- // GL_CLAMP or GL_CLAMP_TO_EDGE, depending on which is available.
- int s_clamp_to_edge = GL_CLAMP;
-
- // Big, fast vertex-memory buffer.
- const int VERTEX_BUFFER_SIZE = 4 << 20;
- void* vertex_memory_buffer = 0;
- int vertex_memory_top = 0;
- bool vertex_memory_from_malloc = false; // tells us whether to
wglFreeMemoryNV() or free() the buffer when we're done.
-
-
- const int STREAM_SUB_BUFFER_COUNT = 2;
-
- class vertex_stream
- {
- // Class to facilitate streaming verts to the video card. Takes
- // care of fencing, and buffer bookkeeping.
- public:
- vertex_stream(int buffer_size);
- ~vertex_stream();
-
- void* reserve_memory(int size);
- void flush_combiners();
-
- private:
- int m_sub_buffer_size;
- int m_buffer_top;
- void* m_buffer;
- int m_extra_bytes; // extra bytes after last block; used
to pad up to write-combiner alignment
-
- unsigned int m_fence[4];
- };
-
-
- vertex_stream* s_stream = NULL;
-
-
- void open()
- // Scan for extensions.
- {
- wglAllocateMemoryNV = (PFNWGLALLOCATEMEMORYNVPROC)
SDL_GL_GetProcAddress( PROC_NAME_PREFIX "AllocateMemoryNV" );
- wglFreeMemoryNV = (PFNWGLFREEMEMORYNVPROC)
SDL_GL_GetProcAddress( PROC_NAME_PREFIX "FreeMemoryNV" );
- glVertexArrayRangeNV = (PFNGLVERTEXARRAYRANGENVPROC)
SDL_GL_GetProcAddress( "glVertexArrayRangeNV" );
-
- glGenFencesNV = (PFNGLGENFENCESNVPROC) SDL_GL_GetProcAddress(
"glGenFencesNV" );
- glSetFenceNV = (PFNGLSETFENCENVPROC) SDL_GL_GetProcAddress(
"glSetFenceNV" );
- glFinishFenceNV = (PFNGLFINISHFENCENVPROC)
SDL_GL_GetProcAddress( "glFinishFenceNV" );
-
- glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC)
SDL_GL_GetProcAddress("glActiveTextureARB");
- glClientActiveTextureARB = (PFNGLCLIENTACTIVETEXTUREARBPROC)
SDL_GL_GetProcAddress("glClientActiveTextureARB");
- glMultiTexCoord2fARB = (PFNGLMULTITEXCOORD2FARBPROC)
SDL_GL_GetProcAddress("glMultiTexCoord2fARB");
- glMultiTexCoord2fvARB = (PFNGLMULTITEXCOORD2FVARBPROC)
SDL_GL_GetProcAddress("glMultiTexCoord2fvARB");
-
- if (check_extension("GL_SGIS_texture_edge_clamp")
- || check_extension("GL_EXT_texture_edge_clamp"))
- {
- // Use CLAMP_TO_EDGE, since it's available.
- s_clamp_to_edge = GL_CLAMP_TO_EDGE;
- }
- }
-
-
- void close()
- // Release anything we need to.
- {
- // @@ free that mongo vertex buffer.
- }
-
-
- int get_clamp_mode()
- // Return a constant to pass to glTexParameteri(GL_TEXTURE_2D,
- // GL_TEXTURE_WRAP_x, ...), which is either GL_CLAMP or
- // GL_CLAMP_TO_EDGE, depending on whether GL_CLAMP_TO_EDGE is
- // available.
- {
- return s_clamp_to_edge;
- }
-
-
- bool check_extension(const char* extension)
- // Some extension checking code snipped from glut.
- {
- static const char* extensions = NULL;
- const char* start;
- char* where;
- char* terminator;
- bool supported;
-
- // Extension names should not have spaces
- where = strchr(extension, ' ');
- if (where || *extension == '\0') return false;
-
- // Grab extensions (but only once)
- if (!extensions) {
- extensions = (const char*)glGetString(GL_EXTENSIONS);
- // Double fault (no extensions)
- if ( ! extensions ) return false;
- }
-
- // Look for extension
- start = extensions;
- supported = false;
- while (!supported)
- {
- // Does extension SEEM to be supported?
- where = strstr((const char*)start, extension);
- if (!where) break;
-
- // Ok, extension SEEMS to be supported
- supported = true;
-
- // Check for space before extension
- supported &= (where == start) || (where[-1] == ' ');
-
- // Check for space after extension
- terminator = where + strlen(extension);
- supported &= (*terminator == '\0') || (*terminator == '
');
-
- // Next search starts at current terminator
- start = terminator;
- }
-
- return supported;
- }
-
-
- void* allocate_vertex_memory( int size )
- // Allocate a block of memory for storing vertex data. Using this
- // allocator will hopefully give you faster glDrawElements(), if
- // you do vertex_array_range on it before rendering.
- {
- // For best results, we must allocate one big ol' chunk of
- // vertex memory on the first call to this function, via
- // wglAllocateMemoryNV, and then allocate sub-chunks out of
- // it.
-
- if ( vertex_memory_buffer == 0 ) {
- // Need to allocate the big chunk.
-
- // If we have NV's allocator, then use it.
- if ( wglAllocateMemoryNV ) {
- vertex_memory_buffer = wglAllocateMemoryNV(
VERTEX_BUFFER_SIZE, 0.f, 0.f, 0.5f ); // @@ this gets us AGP memory.
-// wglAllocateMemoryNV( size, 0.f, 0.f, 1.0f );
// @@ this gets us video memory.
- vertex_memory_from_malloc = false;
- vertex_memory_top = 0;
-
- if ( vertex_memory_buffer &&
glVertexArrayRangeNV ) {
- glVertexArrayRangeNV(
VERTEX_BUFFER_SIZE, vertex_memory_buffer );
- }
-
- glEnableClientState(GL_VERTEX_ARRAY_RANGE_NV);
// GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV
- }
- // else we'll fall back on malloc() for vb allocations.
- }
-
- // Carve a chunk out of our big buffer, or out of malloc if
- // the buffer is dry.
-
- if ( vertex_memory_buffer && vertex_memory_top + size <=
VERTEX_BUFFER_SIZE ) {
- // Just allocate from the end of the big buffer and
increment the top.
- unsigned char* buffer = (unsigned char*)
vertex_memory_buffer + vertex_memory_top;
- vertex_memory_top += size;
-
- return (void*) buffer;
-
- } else {
- // Fall back to malloc.
- printf( "avm: warning, falling back to malloc!\n" );
- return malloc( size );
- }
- }
-
-
- void free_vertex_memory(void* buffer)
- // Frees a buffer previously allocated via allocate_vertex_memory().
- {
- // this function is not ready for prime-time.
- assert( 0 );
- }
-
-
- void gen_fences(int count, unsigned int* fence_array)
- // Wrapper for glGenFencesNV.
- {
- if (glGenFencesNV) {
- glGenFencesNV(count, (GLuint*)fence_array);
- }
- else
- {
- // set all fences to 0.
- for (int i = 0; i < count; i++) {
- fence_array[i] = 0;
- }
- }
- }
-
-
- void set_fence(unsigned int fence_id)
- // Use this to declare all previous glDrawElements() calls as
- // belonging to the specified fence. A subsequent
- // finish_fence(id) will block until those drawing calls have
- // completed.
- {
- if (glSetFenceNV)
- {
- glSetFenceNV(fence_id, GL_ALL_COMPLETED_NV);
- }
- // else no-op.
- }
-
-
- void finish_fence(unsigned int fence_id)
- // Block until all gl drawing calls, associated with the specified
- // fence, have completed.
- {
- if (glFinishFenceNV)
- {
- glFinishFenceNV(fence_id);
- }
- // else no-op.
- }
-
-
- void* stream_get_vertex_memory(int size)
- // Return a buffer to contain size bytes of vertex memory.
- // Put your vertex data in it, then call
- // stream_flush_combiners(), then call glDrawElements() to
- // draw the primitives.
- {
- if (s_stream == NULL) {
- s_stream = new vertex_stream(VERTEX_BUFFER_SIZE);
- }
-
- return s_stream->reserve_memory(size);
- }
-
-
- void stream_flush_combiners()
- // Make sure to flush all data written to the most recently
- // requested vertex buffer (requested by the last call to
- // stream_get_vertex_memory()). Ensure that the data doesn't
- // get hung up in a processor write-combiner.
- {
- assert(s_stream);
- if (s_stream == NULL) return;
-
- s_stream->flush_combiners();
- }
-
-
- static const int WRITE_COMBINER_ALIGNMENT = 64; // line-size
(in bytes) of the write-combiners, must be power of 2
-
-
- int wc_align_up(int size)
- // Return given size, rounded up to the next nearest write combiner
- // alignment boundary.
- {
- assert((WRITE_COMBINER_ALIGNMENT & (WRITE_COMBINER_ALIGNMENT -
1)) == 0); // make sure it's a power of 2
-
- return (size + WRITE_COMBINER_ALIGNMENT - 1) &
~(WRITE_COMBINER_ALIGNMENT - 1);
- }
-
-
- //
- // vertex_stream
- //
-
- vertex_stream::vertex_stream(int buffer_size)
- // Construct a streaming buffer, with vertex RAM of the specified size.
- {
- assert(buffer_size >= STREAM_SUB_BUFFER_COUNT);
-
- m_sub_buffer_size = buffer_size / STREAM_SUB_BUFFER_COUNT;
- m_buffer = ogl::allocate_vertex_memory(buffer_size);
- m_buffer_top = 0;
- m_extra_bytes = 0;
-
- // set up fences.
- ogl::gen_fences(4, &m_fence[0]);
-
- // Set (dummy) fences which will be finished as we reach them.
- ogl::set_fence(m_fence[1]);
- ogl::set_fence(m_fence[2]);
- ogl::set_fence(m_fence[3]);
- }
-
- vertex_stream::~vertex_stream()
- {
-// ogl::free_vertex_memory(m_buffer);
- }
-
- void* vertex_stream::reserve_memory(int size)
- // Clients should call this to get a temporary chunk of fast
- // vertex memory. Fill it with vertex info and call
- // glVertexPointer()/glDrawElements(). The memory won't get
- // stomped until the drawing is finished, provided you use the
- // returned buffer in a glDrawElements call before you call
- // reserve_memory() to get the next chunk.
- {
- assert(size <= m_sub_buffer_size);
-
- int aligned_size = wc_align_up(size);
- m_extra_bytes = aligned_size - size;
-
- for (int sub_buffer = 1; sub_buffer <= STREAM_SUB_BUFFER_COUNT;
sub_buffer++)
- {
- int border = m_sub_buffer_size * sub_buffer;
-
- if (m_buffer_top <= border
- && m_buffer_top + aligned_size > border)
- {
- // Crossing into the next sub-buffer.
-
- int prev_buffer = sub_buffer - 1;
- int next_buffer = sub_buffer %
STREAM_SUB_BUFFER_COUNT;
-
- // Protect the previous sub-buffer.
- ogl::set_fence(m_fence[prev_buffer]);
-
- // Don't overwrite the next sub-buffer while
it's still active.
- ogl::finish_fence(m_fence[next_buffer]);
-
- // Start the next quarter-buffer.
- m_buffer_top = m_sub_buffer_size * next_buffer;
- }
- }
-
- void* buf = ((char*) m_buffer) + m_buffer_top;
- m_buffer_top += aligned_size;
-
- return buf;
- }
-
-
- void vertex_stream::flush_combiners()
- // Make sure the tail of the block returned by the last call
- // to reserve_memory() gets written to the system RAM. If the
- // block doesn't end on a write-combiner line boundary, the
- // last bit of data may still be waiting to be flushed.
- //
- // That's my theory anyway -- farfetched but I'm not sure how
- // else to explain certain bug reports of spurious triangles
- // being rendered.
- {
- if (m_extra_bytes) {
- // Fill up the rest of the last write-combiner line.
- memset(((char*) m_buffer) + m_buffer_top -
m_extra_bytes, 0, m_extra_bytes);
- }
- }
-
-
- // Wrappers for multitexture extensions; no-op if the extension doesn't
exist.
-
- void active_texture(int stage)
- // Set the currently active texture stage; use GL_TEXTUREx_ARB.
- {
- if (glActiveTextureARB)
- {
- glActiveTextureARB(stage);
- }
- }
-
- void client_active_texture(int stage)
- // Set the currently active texture stage for vertex array
- // setup; use GL_TEXTUREx_ARB.
- {
- if (glClientActiveTextureARB)
- {
- glClientActiveTextureARB(stage);
- }
- }
-
- void multi_tex_coord_2f(int stage, float s, float t)
- // Texture coords for the current vertex, in the specified
- // stage.
- {
- if (glMultiTexCoord2fARB)
- {
- glMultiTexCoord2fARB(stage, s, t);
- }
- }
-
- void multi_tex_coord_2fv(int stage, float* st)
- // Texture coords for the current vertex, in the specified
- // stage.
- {
- if (glMultiTexCoord2fvARB)
- {
- glMultiTexCoord2fvARB(stage, st);
- }
- }
-};
-
-
-// Local Variables:
-// mode: C++
-// c-basic-offset: 8
-// tab-width: 8
-
-// indent-tabs-mode: t
-// End:
+// ogl.cpp -- by Thatcher Ulrich <address@hidden>
+
+// This source code has been donated to the Public Domain. Do
+// whatever you want with it.
+
+// Some OpenGL helpers; mainly to generically deal with extensions.
+
+
+#include <SDL.h>
+#include "ogl.h"
+#include "utility.h"
+#include <stdlib.h>
+#include <string.h>
+
+
+namespace ogl {
+
+ bool is_open = false;
+
+ // Pointers to extension functions.
+ typedef void * (APIENTRY * PFNWGLALLOCATEMEMORYNVPROC) (int size, float
readfreq, float writefreq, float priority);
+ typedef void (APIENTRY * PFNWGLFREEMEMORYNVPROC) (void *pointer);
+ typedef void (APIENTRY * PFNGLVERTEXARRAYRANGENVPROC) (int size, void*
buffer);
+ typedef void (APIENTRY * PFNGLGENFENCESNVPROC) (GLsizei n, GLuint
*fence_array);
+ typedef void (APIENTRY * PFNGLSETFENCENVPROC) (GLuint fence_id, GLenum
condition);
+ typedef void (APIENTRY * PFNGLFINISHFENCENVPROC) (GLuint fence_id);
+
+ typedef void (APIENTRY * PFNGLACTIVETEXTUREARBPROC) (GLenum texture);
+ typedef void (APIENTRY * PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum
texture);
+ typedef void (APIENTRY * PFNGLMULTITEXCOORD2FARBPROC) (GLenum target,
GLfloat s, GLfloat t);
+ typedef void (APIENTRY * PFNGLMULTITEXCOORD2FVARBPROC) (GLenum target,
const GLfloat *v);
+
+ PFNWGLALLOCATEMEMORYNVPROC wglAllocateMemoryNV = 0;
+ PFNWGLFREEMEMORYNVPROC wglFreeMemoryNV = 0;
+ PFNGLVERTEXARRAYRANGENVPROC glVertexArrayRangeNV = 0;
+ PFNGLGENFENCESNVPROC glGenFencesNV = 0;
+ PFNGLSETFENCENVPROC glSetFenceNV = 0;
+ PFNGLFINISHFENCENVPROC glFinishFenceNV = 0;
+
+ PFNGLACTIVETEXTUREARBPROC glActiveTextureARB = 0;
+ PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB = 0;
+ PFNGLMULTITEXCOORD2FARBPROC glMultiTexCoord2fARB = 0;
+ PFNGLMULTITEXCOORD2FVARBPROC glMultiTexCoord2fvARB = 0;
+
+
+ // GL_CLAMP or GL_CLAMP_TO_EDGE, depending on which is available.
+ int s_clamp_to_edge = GL_CLAMP;
+
+ // Big, fast vertex-memory buffer.
+ const int VERTEX_BUFFER_SIZE = 4 << 20;
+ void* vertex_memory_buffer = 0;
+ int vertex_memory_top = 0;
+ bool vertex_memory_from_malloc = false; // tells us whether to
wglFreeMemoryNV() or free() the buffer when we're done.
+
+
+ const int STREAM_SUB_BUFFER_COUNT = 2;
+
+ class vertex_stream
+ {
+ // Class to facilitate streaming verts to the video card. Takes
+ // care of fencing, and buffer bookkeeping.
+ public:
+ vertex_stream(int buffer_size);
+ ~vertex_stream();
+
+ void* reserve_memory(int size);
+ void flush_combiners();
+
+ private:
+ int m_sub_buffer_size;
+ int m_buffer_top;
+ void* m_buffer;
+ int m_extra_bytes; // extra bytes after last block; used
to pad up to write-combiner alignment
+
+ unsigned int m_fence[4];
+ };
+
+
+ vertex_stream* s_stream = NULL;
+
+
+ void open()
+ // Scan for extensions.
+ {
+ wglAllocateMemoryNV = (PFNWGLALLOCATEMEMORYNVPROC)
SDL_GL_GetProcAddress( PROC_NAME_PREFIX "AllocateMemoryNV" );
+ wglFreeMemoryNV = (PFNWGLFREEMEMORYNVPROC)
SDL_GL_GetProcAddress( PROC_NAME_PREFIX "FreeMemoryNV" );
+ glVertexArrayRangeNV = (PFNGLVERTEXARRAYRANGENVPROC)
SDL_GL_GetProcAddress( "glVertexArrayRangeNV" );
+
+ glGenFencesNV = (PFNGLGENFENCESNVPROC) SDL_GL_GetProcAddress(
"glGenFencesNV" );
+ glSetFenceNV = (PFNGLSETFENCENVPROC) SDL_GL_GetProcAddress(
"glSetFenceNV" );
+ glFinishFenceNV = (PFNGLFINISHFENCENVPROC)
SDL_GL_GetProcAddress( "glFinishFenceNV" );
+
+ glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC)
SDL_GL_GetProcAddress("glActiveTextureARB");
+ glClientActiveTextureARB = (PFNGLCLIENTACTIVETEXTUREARBPROC)
SDL_GL_GetProcAddress("glClientActiveTextureARB");
+ glMultiTexCoord2fARB = (PFNGLMULTITEXCOORD2FARBPROC)
SDL_GL_GetProcAddress("glMultiTexCoord2fARB");
+ glMultiTexCoord2fvARB = (PFNGLMULTITEXCOORD2FVARBPROC)
SDL_GL_GetProcAddress("glMultiTexCoord2fvARB");
+
+ if (check_extension("GL_SGIS_texture_edge_clamp")
+ || check_extension("GL_EXT_texture_edge_clamp"))
+ {
+ // Use CLAMP_TO_EDGE, since it's available.
+ s_clamp_to_edge = GL_CLAMP_TO_EDGE;
+ }
+ }
+
+
+ void close()
+ // Release anything we need to.
+ {
+ // @@ free that mongo vertex buffer.
+ }
+
+
+ int get_clamp_mode()
+ // Return a constant to pass to glTexParameteri(GL_TEXTURE_2D,
+ // GL_TEXTURE_WRAP_x, ...), which is either GL_CLAMP or
+ // GL_CLAMP_TO_EDGE, depending on whether GL_CLAMP_TO_EDGE is
+ // available.
+ {
+ return s_clamp_to_edge;
+ }
+
+
+ bool check_extension(const char* extension)
+ // Some extension checking code snipped from glut.
+ {
+ static const char* extensions = NULL;
+ const char* start;
+ char* where;
+ char* terminator;
+ bool supported;
+
+ // Extension names should not have spaces
+ where = strchr(extension, ' ');
+ if (where || *extension == '\0') return false;
+
+ // Grab extensions (but only once)
+ if (!extensions) {
+ extensions = (const char*)glGetString(GL_EXTENSIONS);
+ // Double fault (no extensions)
+ if ( ! extensions ) return false;
+ }
+
+ // Look for extension
+ start = extensions;
+ supported = false;
+ while (!supported)
+ {
+ // Does extension SEEM to be supported?
+ where = strstr((const char*)start, extension);
+ if (!where) break;
+
+ // Ok, extension SEEMS to be supported
+ supported = true;
+
+ // Check for space before extension
+ supported &= (where == start) || (where[-1] == ' ');
+
+ // Check for space after extension
+ terminator = where + strlen(extension);
+ supported &= (*terminator == '\0') || (*terminator == '
');
+
+ // Next search starts at current terminator
+ start = terminator;
+ }
+
+ return supported;
+ }
+
+
+ void* allocate_vertex_memory( int size )
+ // Allocate a block of memory for storing vertex data. Using this
+ // allocator will hopefully give you faster glDrawElements(), if
+ // you do vertex_array_range on it before rendering.
+ {
+ // For best results, we must allocate one big ol' chunk of
+ // vertex memory on the first call to this function, via
+ // wglAllocateMemoryNV, and then allocate sub-chunks out of
+ // it.
+
+ if ( vertex_memory_buffer == 0 ) {
+ // Need to allocate the big chunk.
+
+ // If we have NV's allocator, then use it.
+ if ( wglAllocateMemoryNV ) {
+ vertex_memory_buffer = wglAllocateMemoryNV(
VERTEX_BUFFER_SIZE, 0.f, 0.f, 0.5f ); // @@ this gets us AGP memory.
+// wglAllocateMemoryNV( size, 0.f, 0.f, 1.0f );
// @@ this gets us video memory.
+ vertex_memory_from_malloc = false;
+ vertex_memory_top = 0;
+
+ if ( vertex_memory_buffer &&
glVertexArrayRangeNV ) {
+ glVertexArrayRangeNV(
VERTEX_BUFFER_SIZE, vertex_memory_buffer );
+ }
+
+ glEnableClientState(GL_VERTEX_ARRAY_RANGE_NV);
// GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV
+ }
+ // else we'll fall back on malloc() for vb allocations.
+ }
+
+ // Carve a chunk out of our big buffer, or out of malloc if
+ // the buffer is dry.
+
+ if ( vertex_memory_buffer && vertex_memory_top + size <=
VERTEX_BUFFER_SIZE ) {
+ // Just allocate from the end of the big buffer and
increment the top.
+ unsigned char* buffer = (unsigned char*)
vertex_memory_buffer + vertex_memory_top;
+ vertex_memory_top += size;
+
+ return (void*) buffer;
+
+ } else {
+ // Fall back to malloc.
+ printf( "avm: warning, falling back to malloc!\n" );
+ return malloc( size );
+ }
+ }
+
+
+ void free_vertex_memory(void* buffer)
+ // Frees a buffer previously allocated via allocate_vertex_memory().
+ {
+ // this function is not ready for prime-time.
+ assert( 0 );
+ }
+
+
+ void gen_fences(int count, unsigned int* fence_array)
+ // Wrapper for glGenFencesNV.
+ {
+ if (glGenFencesNV) {
+ glGenFencesNV(count, (GLuint*)fence_array);
+ }
+ else
+ {
+ // set all fences to 0.
+ for (int i = 0; i < count; i++) {
+ fence_array[i] = 0;
+ }
+ }
+ }
+
+
+ void set_fence(unsigned int fence_id)
+ // Use this to declare all previous glDrawElements() calls as
+ // belonging to the specified fence. A subsequent
+ // finish_fence(id) will block until those drawing calls have
+ // completed.
+ {
+ if (glSetFenceNV)
+ {
+ glSetFenceNV(fence_id, GL_ALL_COMPLETED_NV);
+ }
+ // else no-op.
+ }
+
+
+ void finish_fence(unsigned int fence_id)
+ // Block until all gl drawing calls, associated with the specified
+ // fence, have completed.
+ {
+ if (glFinishFenceNV)
+ {
+ glFinishFenceNV(fence_id);
+ }
+ // else no-op.
+ }
+
+
+ void* stream_get_vertex_memory(int size)
+ // Return a buffer to contain size bytes of vertex memory.
+ // Put your vertex data in it, then call
+ // stream_flush_combiners(), then call glDrawElements() to
+ // draw the primitives.
+ {
+ if (s_stream == NULL) {
+ s_stream = new vertex_stream(VERTEX_BUFFER_SIZE);
+ }
+
+ return s_stream->reserve_memory(size);
+ }
+
+
+ void stream_flush_combiners()
+ // Make sure to flush all data written to the most recently
+ // requested vertex buffer (requested by the last call to
+ // stream_get_vertex_memory()). Ensure that the data doesn't
+ // get hung up in a processor write-combiner.
+ {
+ assert(s_stream);
+ if (s_stream == NULL) return;
+
+ s_stream->flush_combiners();
+ }
+
+
+ static const int WRITE_COMBINER_ALIGNMENT = 64; // line-size
(in bytes) of the write-combiners, must be power of 2
+
+
+ int wc_align_up(int size)
+ // Return given size, rounded up to the next nearest write combiner
+ // alignment boundary.
+ {
+ assert((WRITE_COMBINER_ALIGNMENT & (WRITE_COMBINER_ALIGNMENT -
1)) == 0); // make sure it's a power of 2
+
+ return (size + WRITE_COMBINER_ALIGNMENT - 1) &
~(WRITE_COMBINER_ALIGNMENT - 1);
+ }
+
+
+ //
+ // vertex_stream
+ //
+
+ vertex_stream::vertex_stream(int buffer_size)
+ // Construct a streaming buffer, with vertex RAM of the specified size.
+ {
+ assert(buffer_size >= STREAM_SUB_BUFFER_COUNT);
+
+ m_sub_buffer_size = buffer_size / STREAM_SUB_BUFFER_COUNT;
+ m_buffer = ogl::allocate_vertex_memory(buffer_size);
+ m_buffer_top = 0;
+ m_extra_bytes = 0;
+
+ // set up fences.
+ ogl::gen_fences(4, &m_fence[0]);
+
+ // Set (dummy) fences which will be finished as we reach them.
+ ogl::set_fence(m_fence[1]);
+ ogl::set_fence(m_fence[2]);
+ ogl::set_fence(m_fence[3]);
+ }
+
+ vertex_stream::~vertex_stream()
+ {
+// ogl::free_vertex_memory(m_buffer);
+ }
+
+ void* vertex_stream::reserve_memory(int size)
+ // Clients should call this to get a temporary chunk of fast
+ // vertex memory. Fill it with vertex info and call
+ // glVertexPointer()/glDrawElements(). The memory won't get
+ // stomped until the drawing is finished, provided you use the
+ // returned buffer in a glDrawElements call before you call
+ // reserve_memory() to get the next chunk.
+ {
+ assert(size <= m_sub_buffer_size);
+
+ int aligned_size = wc_align_up(size);
+ m_extra_bytes = aligned_size - size;
+
+ for (int sub_buffer = 1; sub_buffer <= STREAM_SUB_BUFFER_COUNT;
sub_buffer++)
+ {
+ int border = m_sub_buffer_size * sub_buffer;
+
+ if (m_buffer_top <= border
+ && m_buffer_top + aligned_size > border)
+ {
+ // Crossing into the next sub-buffer.
+
+ int prev_buffer = sub_buffer - 1;
+ int next_buffer = sub_buffer %
STREAM_SUB_BUFFER_COUNT;
+
+ // Protect the previous sub-buffer.
+ ogl::set_fence(m_fence[prev_buffer]);
+
+ // Don't overwrite the next sub-buffer while
it's still active.
+ ogl::finish_fence(m_fence[next_buffer]);
+
+ // Start the next quarter-buffer.
+ m_buffer_top = m_sub_buffer_size * next_buffer;
+ }
+ }
+
+ void* buf = ((char*) m_buffer) + m_buffer_top;
+ m_buffer_top += aligned_size;
+
+ return buf;
+ }
+
+
+ void vertex_stream::flush_combiners()
+ // Make sure the tail of the block returned by the last call
+ // to reserve_memory() gets written to the system RAM. If the
+ // block doesn't end on a write-combiner line boundary, the
+ // last bit of data may still be waiting to be flushed.
+ //
+ // That's my theory anyway -- farfetched but I'm not sure how
+ // else to explain certain bug reports of spurious triangles
+ // being rendered.
+ {
+ if (m_extra_bytes) {
+ // Fill up the rest of the last write-combiner line.
+ memset(((char*) m_buffer) + m_buffer_top -
m_extra_bytes, 0, m_extra_bytes);
+ }
+ }
+
+
+ // Wrappers for multitexture extensions; no-op if the extension doesn't
exist.
+
+ void active_texture(int stage)
+ // Set the currently active texture stage; use GL_TEXTUREx_ARB.
+ {
+ if (glActiveTextureARB)
+ {
+ glActiveTextureARB(stage);
+ }
+ }
+
+ void client_active_texture(int stage)
+ // Set the currently active texture stage for vertex array
+ // setup; use GL_TEXTUREx_ARB.
+ {
+ if (glClientActiveTextureARB)
+ {
+ glClientActiveTextureARB(stage);
+ }
+ }
+
+ void multi_tex_coord_2f(int stage, float s, float t)
+ // Texture coords for the current vertex, in the specified
+ // stage.
+ {
+ if (glMultiTexCoord2fARB)
+ {
+ glMultiTexCoord2fARB(stage, s, t);
+ }
+ }
+
+ void multi_tex_coord_2fv(int stage, float* st)
+ // Texture coords for the current vertex, in the specified
+ // stage.
+ {
+ if (glMultiTexCoord2fvARB)
+ {
+ glMultiTexCoord2fvARB(stage, st);
+ }
+ }
+};
+
+
+// Local Variables:
+// mode: C++
+// c-basic-offset: 8
+// tab-width: 8
+
+// indent-tabs-mode: t
+// End:
Index: gnash/libbase/png_helper.cpp
diff -u gnash/libbase/png_helper.cpp:1.1 gnash/libbase/png_helper.cpp:1.2
--- gnash/libbase/png_helper.cpp:1.1 Tue Dec 20 20:57:00 2005
+++ gnash/libbase/png_helper.cpp Sun Feb 26 15:49:30 2006
@@ -1,98 +1,98 @@
-// png_helper.cpp -- Thatcher Ulrich <address@hidden> 2004
-
-// This source code has been donated to the Public Domain. Do
-// whatever you want with it.
-
-// Wrapper for png file operations. The actual work is done by the
-// libpng lib.
-
-
-#include "utility.h"
-#include "png_helper.h"
-#include "tu_file.h"
-#include <stdio.h>
-
-#if TU_CONFIG_LINK_TO_LIBPNG
-
-#include <png.h>
-
-
-namespace png_helper
-{
- void write_grayscale(FILE* out, uint8* data, int width, int height)
- // Writes an 8-bit grayscale image in .png format, to the
- // given output stream.
- {
- png_structp png_ptr;
- png_infop info_ptr;
-
- png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
NULL, NULL);
- if (png_ptr == NULL)
- {
- // @@ log error here!
- return;
- }
-
- info_ptr = png_create_info_struct(png_ptr);
- if (info_ptr == NULL)
- {
- // @@ log error here!
- png_destroy_write_struct(&png_ptr, NULL);
- return;
- }
-
- if (setjmp(png_jmpbuf(png_ptr)))
- {
- // Error.
- png_destroy_write_struct(&png_ptr, &info_ptr);
- return;
- }
-
- png_init_io(png_ptr, out);
-
- png_set_IHDR(
- png_ptr,
- info_ptr,
- width,
- height,
- 8,
- PNG_COLOR_TYPE_GRAY,
- PNG_INTERLACE_NONE,
- PNG_COMPRESSION_TYPE_DEFAULT,
- PNG_FILTER_TYPE_DEFAULT);
-
- png_write_info(png_ptr, info_ptr);
-
- for (int y = 0; y < height; y++)
- {
- png_write_row(png_ptr, data + width * y);
- }
-
- png_write_end(png_ptr, info_ptr);
-
- png_destroy_write_struct(&png_ptr, &info_ptr);
- }
-}
-
-
-#else // not TU_CONFIG_LINK_TO_JPEGLIB
-
-
-namespace jpeg
-{
- void write_grayscale(FILE* out, uint8* data, int width, int height)
- {
- // no-op
- }
-}
-
-
-#endif // not TU_CONFIG_LINK_TO_LIBPNG
-
-
-// Local Variables:
-// mode: C++
-// c-basic-offset: 8
-// tab-width: 8
-// indent-tabs-mode: t
-// End:
+// png_helper.cpp -- Thatcher Ulrich <address@hidden> 2004
+
+// This source code has been donated to the Public Domain. Do
+// whatever you want with it.
+
+// Wrapper for png file operations. The actual work is done by the
+// libpng lib.
+
+
+#include "utility.h"
+#include "png_helper.h"
+#include "tu_file.h"
+#include <stdio.h>
+
+#if TU_CONFIG_LINK_TO_LIBPNG
+
+#include <png.h>
+
+
+namespace png_helper
+{
+ void write_grayscale(FILE* out, uint8* data, int width, int height)
+ // Writes an 8-bit grayscale image in .png format, to the
+ // given output stream.
+ {
+ png_structp png_ptr;
+ png_infop info_ptr;
+
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
NULL, NULL);
+ if (png_ptr == NULL)
+ {
+ // @@ log error here!
+ return;
+ }
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (info_ptr == NULL)
+ {
+ // @@ log error here!
+ png_destroy_write_struct(&png_ptr, NULL);
+ return;
+ }
+
+ if (setjmp(png_jmpbuf(png_ptr)))
+ {
+ // Error.
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ return;
+ }
+
+ png_init_io(png_ptr, out);
+
+ png_set_IHDR(
+ png_ptr,
+ info_ptr,
+ width,
+ height,
+ 8,
+ PNG_COLOR_TYPE_GRAY,
+ PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_DEFAULT,
+ PNG_FILTER_TYPE_DEFAULT);
+
+ png_write_info(png_ptr, info_ptr);
+
+ for (int y = 0; y < height; y++)
+ {
+ png_write_row(png_ptr, data + width * y);
+ }
+
+ png_write_end(png_ptr, info_ptr);
+
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ }
+}
+
+
+#else // not TU_CONFIG_LINK_TO_JPEGLIB
+
+
+namespace jpeg
+{
+ void write_grayscale(FILE* out, uint8* data, int width, int height)
+ {
+ // no-op
+ }
+}
+
+
+#endif // not TU_CONFIG_LINK_TO_LIBPNG
+
+
+// Local Variables:
+// mode: C++
+// c-basic-offset: 8
+// tab-width: 8
+// indent-tabs-mode: t
+// End:
Index: gnash/libbase/postscript.cpp
diff -u gnash/libbase/postscript.cpp:1.1 gnash/libbase/postscript.cpp:1.2
--- gnash/libbase/postscript.cpp:1.1 Tue Dec 20 20:57:00 2005
+++ gnash/libbase/postscript.cpp Sun Feb 26 15:49:30 2006
@@ -1,288 +1,288 @@
-// postscript.cpp -- by Thatcher Ulrich <address@hidden>
-
-// This source code has been donated to the Public Domain. Do
-// whatever you want with it.
-
-// Some helpers for generating Postscript graphics.
-
-
-#include "postscript.h"
-
-#include "tu_file.h"
-#include "utility.h"
-#include <stdarg.h>
-
-
-// Loosely translated into C++ from:
-// -- ps.lua
-// -- lua interface to postscript
-// -- Luiz Henrique de Figueiredo (address@hidden)
-// -- 14 May 96
-//
-// From the Lua 4.0.1 distribution, see http://www.lua.org
-
-
-
-postscript::postscript(tu_file* out, const char* title, bool encapsulated)
- :
- m_out(out),
- m_page(0),
- m_x0(1000),
- m_x1(0),
- m_y0(1000),
- m_y1(0),
- m_empty(true)
-// Initialize the file & this struct, etc.
-{
- assert(m_out != NULL);
-
- if (title == NULL)
- {
- title = "no title";
- }
-
- if (encapsulated)
- {
- m_out->printf("%%!PS-Adobe-2.0 EPSF-1.2\n");
- }
- else
- {
- m_out->printf("%%!PS-Adobe 3.0\n");
- }
- m_out->printf("%%%%Title: %s\n", title);
- m_out->printf(
- "%%%%Creator: postscript.cpp from tu-testbed\n"
- "%%%%CreationDate: 1 1 2001\n"
- "%%%%Pages: (atend)\n"
- "%%%%BoundingBox: (atend)\n"
- "%%%%EndComments\n"
- "%%%%BeginProcSet: postscript.cpp\n"
- "/s { stroke } bind def\n"
- "/f { fill } bind def\n"
- "/m { moveto } bind def\n"
- "/l { lineto } bind def\n"
- "/L { moveto lineto stroke } bind def\n"
- "/t { show } bind def\n"
- "/o { 0 360 arc stroke } bind def\n"
- "/O { 0 360 arc fill } bind def\n"
- "/p { 3 0 360 arc fil } bind def\n"
- "/F { findfont exch scalefont setfont } bind def\n"
- "/LS { 0 setdash } bind def\n"
- "/LW { setlinewidth } bind def\n"
- "%%%%EndProcSet: postscript.cpp\n"
- "%%%%EndProlog\n"
- "%%%%BeginSetup\n"
- "0 setlinewidth\n"
- "1 setlinejoin\n"
- "1 setlinecap\n"
- "10 /Times-Roman F\n"
- "%%%%EndSetup\n\n"
- "%%%%Page: 1 1\n");
-}
-
-
-postscript::~postscript()
-// End the Postscript info.
-{
- m_out->printf(
- "stroke\n"
- "showpage\n"
- "%%%%Trailer\n"
- "%%%%Pages: %d %d\n"
- "%%%%BoundingBox: %d %d %d %d\n"
- "%%%%EOF\n",
- m_page + 1, m_page + 1,
- int(m_x0), int(m_y0), int(m_x1), int(m_y1)
- );
-
-}
-
-
-void postscript::clear()
-// New page.
-{
- if (m_empty) return;
-
- m_page++;
- m_out->printf("showpage\n%%%%Page: %d %d\n", m_page + 1, m_page + 1);
-
- m_empty = true;
-}
-
-
-void postscript::comment(const char* s)
-// Insert a comment into the output.
-{
- m_out->printf("%% %s\n", s);
-}
-
-
-void postscript::rgbcolor(float r, float g, float b)
-// Set the pen color. Components range from 0 to 1.
-{
- m_out->printf("%f %f %f setrgbcolor\n", r, g, b);
-}
-
-
-void postscript::gray(float amount)
-// 0 == black, 1 == white
-{
- m_out->printf("%f setgray\n", amount);
-}
-
-
-void postscript::black()
-{
- rgbcolor(0, 0, 0);
-}
-
-
-void postscript::line(float x0, float y0, float x1, float y1)
-{
- m_out->printf(
- "%f %f %f %f L\n",
- x1, y1, x0, y0);
-
- update(x0, y0);
- update(x1, y1);
-}
-
-
-void postscript::moveto(float x0, float y0)
-{
- m_out->printf(
- "%f %f m\n",
- x0, y0);
-
- update(x0, y0);
-}
-
-
-void postscript::lineto(float x0, float y0)
-{
- m_out->printf(
- "%f %f l\n",
- x0, y0);
-
- update(x0, y0);
-}
-
-
-void postscript::linewidth(float w)
-{
- m_out->printf("%f LW\n", w);
-}
-
-
-// @@ linestyle ?
-
-
-void postscript::fill()
-{
- m_out->printf("f\n");
-}
-
-
-void postscript::font(const char* name, float size)
-{
- m_out->printf("%f /%s F\n", size, name);
-}
-
-
-#ifdef _WIN32
-#define vsnprintf _vsnprintf
-#endif // _WIN32
-
-
-void postscript::printf(float x, float y, const char* fmt, ...)
-{
- static const int BUFFER_SIZE = 1000;
-
- char buffer[BUFFER_SIZE];
-
- va_list ap;
- va_start(ap, fmt);
- vsnprintf(buffer, BUFFER_SIZE, fmt, ap);
- va_end(ap);
-
- m_out->printf("%f %f m (%s) t\n", x, y, buffer);
- update(x, y);
- update(x + 100, y + 10); // @@ should get bounds of text and
update properly!
-}
-
-
-void postscript::circle(float x, float y, float radius)
-{
- m_out->printf("%f %f %f o\n", x, y, radius);
- update(x - radius, y - radius);
- update(x + radius, y + radius);
-}
-
-
-void postscript::disk(float x, float y, float radius)
-{
- m_out->printf("%f %f %f O\n", x, y, radius);
- update(x - radius, y - radius);
- update(x + radius, y + radius);
-}
-
-
-void postscript::dot(float x, float y)
-{
- m_out->printf("%f %f p\n", x, y);
- update(x, y);
-}
-
-
-void postscript::rectangle(float x0, float x1, float y0, float y1)
-{
- m_out->printf(
- "%f %f m "
- "%f %f l "
- "%f %f l "
- "%f %f l "
- "%f %f l s\n",
- x0, y0,
- x1, y0,
- x1, y1,
- x0, y1,
- x0, y0);
- update(x0, y0);
- update(x1, y1);
-}
-
-
-void postscript::box(float x0, float x1, float y0, float y1)
-{
- m_out->printf(
- "%f %f m "
- "%f %f l "
- "%f %f l "
- "%f %f l f\n",
- x0, y0,
- x1, y0,
- x1, y1,
- x0, y1);
- update(x0, y0);
- update(x1, y1);
-}
-
-
-void postscript::update(float x, float y)
-// enlarge the bounding box if necessary.
-{
- if (x < m_x0) m_x0 = floorf(x);
- if (x > m_x1) m_x1 = ceilf(x);
- if (y < m_y0) m_y0 = floorf(y);
- if (y > m_y1) m_y1 = ceilf(y);
-
- m_empty = false;
-}
-
-
-// Local Variables:
-// mode: C++
-// c-basic-offset: 8
-// tab-width: 8
-// indent-tabs-mode: t
-// End:
+// postscript.cpp -- by Thatcher Ulrich <address@hidden>
+
+// This source code has been donated to the Public Domain. Do
+// whatever you want with it.
+
+// Some helpers for generating Postscript graphics.
+
+
+#include "postscript.h"
+
+#include "tu_file.h"
+#include "utility.h"
+#include <stdarg.h>
+
+
+// Loosely translated into C++ from:
+// -- ps.lua
+// -- lua interface to postscript
+// -- Luiz Henrique de Figueiredo (address@hidden)
+// -- 14 May 96
+//
+// From the Lua 4.0.1 distribution, see http://www.lua.org
+
+
+
+postscript::postscript(tu_file* out, const char* title, bool encapsulated)
+ :
+ m_out(out),
+ m_page(0),
+ m_x0(1000),
+ m_x1(0),
+ m_y0(1000),
+ m_y1(0),
+ m_empty(true)
+// Initialize the file & this struct, etc.
+{
+ assert(m_out != NULL);
+
+ if (title == NULL)
+ {
+ title = "no title";
+ }
+
+ if (encapsulated)
+ {
+ m_out->printf("%%!PS-Adobe-2.0 EPSF-1.2\n");
+ }
+ else
+ {
+ m_out->printf("%%!PS-Adobe 3.0\n");
+ }
+ m_out->printf("%%%%Title: %s\n", title);
+ m_out->printf(
+ "%%%%Creator: postscript.cpp from tu-testbed\n"
+ "%%%%CreationDate: 1 1 2001\n"
+ "%%%%Pages: (atend)\n"
+ "%%%%BoundingBox: (atend)\n"
+ "%%%%EndComments\n"
+ "%%%%BeginProcSet: postscript.cpp\n"
+ "/s { stroke } bind def\n"
+ "/f { fill } bind def\n"
+ "/m { moveto } bind def\n"
+ "/l { lineto } bind def\n"
+ "/L { moveto lineto stroke } bind def\n"
+ "/t { show } bind def\n"
+ "/o { 0 360 arc stroke } bind def\n"
+ "/O { 0 360 arc fill } bind def\n"
+ "/p { 3 0 360 arc fil } bind def\n"
+ "/F { findfont exch scalefont setfont } bind def\n"
+ "/LS { 0 setdash } bind def\n"
+ "/LW { setlinewidth } bind def\n"
+ "%%%%EndProcSet: postscript.cpp\n"
+ "%%%%EndProlog\n"
+ "%%%%BeginSetup\n"
+ "0 setlinewidth\n"
+ "1 setlinejoin\n"
+ "1 setlinecap\n"
+ "10 /Times-Roman F\n"
+ "%%%%EndSetup\n\n"
+ "%%%%Page: 1 1\n");
+}
+
+
+postscript::~postscript()
+// End the Postscript info.
+{
+ m_out->printf(
+ "stroke\n"
+ "showpage\n"
+ "%%%%Trailer\n"
+ "%%%%Pages: %d %d\n"
+ "%%%%BoundingBox: %d %d %d %d\n"
+ "%%%%EOF\n",
+ m_page + 1, m_page + 1,
+ int(m_x0), int(m_y0), int(m_x1), int(m_y1)
+ );
+
+}
+
+
+void postscript::clear()
+// New page.
+{
+ if (m_empty) return;
+
+ m_page++;
+ m_out->printf("showpage\n%%%%Page: %d %d\n", m_page + 1, m_page + 1);
+
+ m_empty = true;
+}
+
+
+void postscript::comment(const char* s)
+// Insert a comment into the output.
+{
+ m_out->printf("%% %s\n", s);
+}
+
+
+void postscript::rgbcolor(float r, float g, float b)
+// Set the pen color. Components range from 0 to 1.
+{
+ m_out->printf("%f %f %f setrgbcolor\n", r, g, b);
+}
+
+
+void postscript::gray(float amount)
+// 0 == black, 1 == white
+{
+ m_out->printf("%f setgray\n", amount);
+}
+
+
+void postscript::black()
+{
+ rgbcolor(0, 0, 0);
+}
+
+
+void postscript::line(float x0, float y0, float x1, float y1)
+{
+ m_out->printf(
+ "%f %f %f %f L\n",
+ x1, y1, x0, y0);
+
+ update(x0, y0);
+ update(x1, y1);
+}
+
+
+void postscript::moveto(float x0, float y0)
+{
+ m_out->printf(
+ "%f %f m\n",
+ x0, y0);
+
+ update(x0, y0);
+}
+
+
+void postscript::lineto(float x0, float y0)
+{
+ m_out->printf(
+ "%f %f l\n",
+ x0, y0);
+
+ update(x0, y0);
+}
+
+
+void postscript::linewidth(float w)
+{
+ m_out->printf("%f LW\n", w);
+}
+
+
+// @@ linestyle ?
+
+
+void postscript::fill()
+{
+ m_out->printf("f\n");
+}
+
+
+void postscript::font(const char* name, float size)
+{
+ m_out->printf("%f /%s F\n", size, name);
+}
+
+
+#ifdef _WIN32
+#define vsnprintf _vsnprintf
+#endif // _WIN32
+
+
+void postscript::printf(float x, float y, const char* fmt, ...)
+{
+ static const int BUFFER_SIZE = 1000;
+
+ char buffer[BUFFER_SIZE];
+
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(buffer, BUFFER_SIZE, fmt, ap);
+ va_end(ap);
+
+ m_out->printf("%f %f m (%s) t\n", x, y, buffer);
+ update(x, y);
+ update(x + 100, y + 10); // @@ should get bounds of text and
update properly!
+}
+
+
+void postscript::circle(float x, float y, float radius)
+{
+ m_out->printf("%f %f %f o\n", x, y, radius);
+ update(x - radius, y - radius);
+ update(x + radius, y + radius);
+}
+
+
+void postscript::disk(float x, float y, float radius)
+{
+ m_out->printf("%f %f %f O\n", x, y, radius);
+ update(x - radius, y - radius);
+ update(x + radius, y + radius);
+}
+
+
+void postscript::dot(float x, float y)
+{
+ m_out->printf("%f %f p\n", x, y);
+ update(x, y);
+}
+
+
+void postscript::rectangle(float x0, float x1, float y0, float y1)
+{
+ m_out->printf(
+ "%f %f m "
+ "%f %f l "
+ "%f %f l "
+ "%f %f l "
+ "%f %f l s\n",
+ x0, y0,
+ x1, y0,
+ x1, y1,
+ x0, y1,
+ x0, y0);
+ update(x0, y0);
+ update(x1, y1);
+}
+
+
+void postscript::box(float x0, float x1, float y0, float y1)
+{
+ m_out->printf(
+ "%f %f m "
+ "%f %f l "
+ "%f %f l "
+ "%f %f l f\n",
+ x0, y0,
+ x1, y0,
+ x1, y1,
+ x0, y1);
+ update(x0, y0);
+ update(x1, y1);
+}
+
+
+void postscript::update(float x, float y)
+// enlarge the bounding box if necessary.
+{
+ if (x < m_x0) m_x0 = floorf(x);
+ if (x > m_x1) m_x1 = ceilf(x);
+ if (y < m_y0) m_y0 = floorf(y);
+ if (y > m_y1) m_y1 = ceilf(y);
+
+ m_empty = false;
+}
+
+
+// Local Variables:
+// mode: C++
+// c-basic-offset: 8
+// tab-width: 8
+// indent-tabs-mode: t
+// End:
Index: gnash/libbase/test_ogl.cpp
diff -u gnash/libbase/test_ogl.cpp:1.1 gnash/libbase/test_ogl.cpp:1.2
--- gnash/libbase/test_ogl.cpp:1.1 Tue Dec 20 20:57:00 2005
+++ gnash/libbase/test_ogl.cpp Sun Feb 26 15:49:30 2006
@@ -1,42 +1,42 @@
-// ogl.cpp -- by Thatcher Ulrich <address@hidden>
-
-// This source code has been donated to the Public Domain. Do
-// whatever you want with it.
-
-// test program for ogl wrapper
-
-
-#include <stdlib.h>
-#include "ogl.h"
-#include <SDL.h>
-
-
-#undef main // SDL weirdness under WIN32!!
-extern "C" int main(int argc, char *argv[])
-{
- if (SDL_Init(SDL_INIT_VIDEO /* | SDL_INIT_JOYSTICK | SDL_INIT_CDROM |
SDL_INIT_AUDIO*/))
- {
- fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
- exit(1);
- }
- atexit(SDL_Quit);
-
- int bpp = 24;
- int flags = SDL_OPENGL | (0 ? SDL_FULLSCREEN : 0);
-
- SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 );
- SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 );
- SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 );
- SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );
- SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
-
- // Set the video mode.
- if (SDL_SetVideoMode(320, 240, bpp, flags) == 0) {
- fprintf(stderr, "SDL_SetVideoMode() failed.");
- exit(1);
- }
-
- ogl::open();
-
- return 0;
-}
+// ogl.cpp -- by Thatcher Ulrich <address@hidden>
+
+// This source code has been donated to the Public Domain. Do
+// whatever you want with it.
+
+// test program for ogl wrapper
+
+
+#include <stdlib.h>
+#include "ogl.h"
+#include <SDL.h>
+
+
+#undef main // SDL weirdness under WIN32!!
+extern "C" int main(int argc, char *argv[])
+{
+ if (SDL_Init(SDL_INIT_VIDEO /* | SDL_INIT_JOYSTICK | SDL_INIT_CDROM |
SDL_INIT_AUDIO*/))
+ {
+ fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
+ exit(1);
+ }
+ atexit(SDL_Quit);
+
+ int bpp = 24;
+ int flags = SDL_OPENGL | (0 ? SDL_FULLSCREEN : 0);
+
+ SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 );
+ SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 );
+ SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 );
+ SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );
+ SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
+
+ // Set the video mode.
+ if (SDL_SetVideoMode(320, 240, bpp, flags) == 0) {
+ fprintf(stderr, "SDL_SetVideoMode() failed.");
+ exit(1);
+ }
+
+ ogl::open();
+
+ return 0;
+}
Index: gnash/libbase/triangulate_float.cpp
diff -u gnash/libbase/triangulate_float.cpp:1.3
gnash/libbase/triangulate_float.cpp:1.4
--- gnash/libbase/triangulate_float.cpp:1.3 Sat Feb 25 03:54:03 2006
+++ gnash/libbase/triangulate_float.cpp Sun Feb 26 15:49:30 2006
@@ -1,77 +1,77 @@
-// triangulate_float.cpp -- Thatcher Ulrich 2004
-
-// This source code has been donated to the Public Domain. Do
-// whatever you want with it.
-
-// Code to triangulate arbitrary 2D polygonal regions.
-//
-// Instantiate our templated algo from triangulate_inst.h
-
-#include "triangulate_impl.h"
-
-
-namespace triangulate
-{
- // Version using float coords
- void compute(
- std::vector<float>* result, // trilist
- int path_count,
- const std::vector<float> paths[],
- int debug_halt_step /* = -1 */,
- std::vector<float>* debug_remaining_loop /* = NULL */)
- {
- compute_triangulation<float>(result, path_count, paths,
debug_halt_step, debug_remaining_loop);
- }
-}
-
-
-
-#ifdef TEST_TRIANGULATE_FLOAT
-
-// Compile test with something like:
-//
-// gcc -o triangulate_test -I../ triangulate_float.cpp tu_random.cpp
-DTEST_TRIANGULATE_FLOAT -lstdc++
-//
-// or
-//
-// cl -Od -Zi -o triangulate_test.exe -I../ triangulate_float.cpp
tu_random.cpp -DTEST_TRIANGULATE_FLOAT
-
-
-void test_square()
-// A very minimal, easy test.
-{
- std::vector<float> result;
- std::vector<std::vector<float> > paths;
-
- // Make a square.
- paths.resize(1);
- paths[0].push_back(0);
- paths[0].push_back(0);
- paths[0].push_back(1);
- paths[0].push_back(0);
- paths[0].push_back(1);
- paths[0].push_back(1);
- paths[0].push_back(0);
- paths[0].push_back(1);
-
- // Triangulate.
- triangulate::compute(&result, paths.size(), &paths[0]);
-
- // Dump.
- for (int i = 0; i < result.size(); i++)
- {
- printf("%f\n", result[i]);
- }
-}
-
-
-int main()
-{
- test_square();
-
- return 0;
-}
-
-
-#endif // TEST_TRIANGULATE_FLOAT
-
+// triangulate_float.cpp -- Thatcher Ulrich 2004
+
+// This source code has been donated to the Public Domain. Do
+// whatever you want with it.
+
+// Code to triangulate arbitrary 2D polygonal regions.
+//
+// Instantiate our templated algo from triangulate_inst.h
+
+#include "triangulate_impl.h"
+
+
+namespace triangulate
+{
+ // Version using float coords
+ void compute(
+ std::vector<float>* result, // trilist
+ int path_count,
+ const std::vector<float> paths[],
+ int debug_halt_step /* = -1 */,
+ std::vector<float>* debug_remaining_loop /* = NULL */)
+ {
+ compute_triangulation<float>(result, path_count, paths,
debug_halt_step, debug_remaining_loop);
+ }
+}
+
+
+
+#ifdef TEST_TRIANGULATE_FLOAT
+
+// Compile test with something like:
+//
+// gcc -o triangulate_test -I../ triangulate_float.cpp tu_random.cpp
-DTEST_TRIANGULATE_FLOAT -lstdc++
+//
+// or
+//
+// cl -Od -Zi -o triangulate_test.exe -I../ triangulate_float.cpp
tu_random.cpp -DTEST_TRIANGULATE_FLOAT
+
+
+void test_square()
+// A very minimal, easy test.
+{
+ std::vector<float> result;
+ std::vector<std::vector<float> > paths;
+
+ // Make a square.
+ paths.resize(1);
+ paths[0].push_back(0);
+ paths[0].push_back(0);
+ paths[0].push_back(1);
+ paths[0].push_back(0);
+ paths[0].push_back(1);
+ paths[0].push_back(1);
+ paths[0].push_back(0);
+ paths[0].push_back(1);
+
+ // Triangulate.
+ triangulate::compute(&result, paths.size(), &paths[0]);
+
+ // Dump.
+ for (int i = 0; i < result.size(); i++)
+ {
+ printf("%f\n", result[i]);
+ }
+}
+
+
+int main()
+{
+ test_square();
+
+ return 0;
+}
+
+
+#endif // TEST_TRIANGULATE_FLOAT
+
Index: gnash/libbase/triangulate_sint32.cpp
diff -u gnash/libbase/triangulate_sint32.cpp:1.3
gnash/libbase/triangulate_sint32.cpp:1.4
--- gnash/libbase/triangulate_sint32.cpp:1.3 Sat Feb 25 03:54:03 2006
+++ gnash/libbase/triangulate_sint32.cpp Sun Feb 26 15:49:30 2006
@@ -1,25 +1,25 @@
-// triangulate_sint32.cpp -- Thatcher Ulrich 2004
-
-// This source code has been donated to the Public Domain. Do
-// whatever you want with it.
-
-// Code to triangulate arbitrary 2D polygonal regions.
-//
-// Instantiate our templated algo from triangulate_inst.h
-
-#include "triangulate_impl.h"
-
-
-namespace triangulate
-{
- // Version using sint32 coords
- void compute(
- std::vector<sint32>* result, // trilist
- int path_count,
- const std::vector<sint32> paths[],
- int debug_halt_step /* = -1 */,
- std::vector<sint32>* debug_remaining_loop /* = NULL */)
- {
- compute_triangulation<sint32>(result, path_count, paths,
debug_halt_step, debug_remaining_loop);
- }
-}
+// triangulate_sint32.cpp -- Thatcher Ulrich 2004
+
+// This source code has been donated to the Public Domain. Do
+// whatever you want with it.
+
+// Code to triangulate arbitrary 2D polygonal regions.
+//
+// Instantiate our templated algo from triangulate_inst.h
+
+#include "triangulate_impl.h"
+
+
+namespace triangulate
+{
+ // Version using sint32 coords
+ void compute(
+ std::vector<sint32>* result, // trilist
+ int path_count,
+ const std::vector<sint32> paths[],
+ int debug_halt_step /* = -1 */,
+ std::vector<sint32>* debug_remaining_loop /* = NULL */)
+ {
+ compute_triangulation<sint32>(result, path_count, paths,
debug_halt_step, debug_remaining_loop);
+ }
+}
Index: gnash/libbase/tu_file.cpp
diff -u gnash/libbase/tu_file.cpp:1.1 gnash/libbase/tu_file.cpp:1.2
--- gnash/libbase/tu_file.cpp:1.1 Tue Dec 20 20:57:00 2005
+++ gnash/libbase/tu_file.cpp Sun Feb 26 15:49:30 2006
@@ -1,540 +1,540 @@
-// tu_file.cpp -- Ignacio Castaño, Thatcher Ulrich <address@hidden> 2003
-
-// This source code has been donated to the Public Domain. Do
-// whatever you want with it.
-
-// A file class that can be customized with callbacks.
-
-
-#include "tu_file.h"
-#include "utility.h"
-#include "container.h"
-#include "membuf.h"
-
-
-//
-// tu_file functions using FILE
-//
-
-
-static int std_read_func(void* dst, int bytes, void* appdata)
-// Return the number of bytes actually read. EOF or an error would
-// cause that to not be equal to "bytes".
-{
- assert(appdata);
- assert(dst);
- return fread( dst, 1, bytes, (FILE *)appdata );
-}
-
-static int std_write_func(const void* src, int bytes, void* appdata)
-// Return the number of bytes actually written.
-{
- assert(appdata);
- assert(src);
- return fwrite( src, 1, bytes, (FILE *)appdata );
-}
-
-static int std_seek_func(int pos, void *appdata)
-// Return 0 on success, or TU_FILE_SEEK_ERROR on failure.
-{
- assert(appdata);
- clearerr((FILE*) appdata); // make sure EOF flag is cleared.
- int result = fseek((FILE*)appdata, pos, SEEK_SET);
- if (result == EOF)
- {
- // @@ TODO should set m_error to something relevant based on
errno.
- return TU_FILE_SEEK_ERROR;
- }
- return 0;
-}
-
-static int std_seek_to_end_func(void *appdata)
-// Return 0 on success, TU_FILE_SEEK_ERROR on failure.
-{
- assert(appdata);
- int result = fseek((FILE*)appdata, 0, SEEK_END);
- if (result == EOF)
- {
- // @@ TODO should set m_error to something relevant based on
errno.
- return TU_FILE_SEEK_ERROR;
- }
- return 0;
-}
-
-static int std_tell_func(const void *appdata)
-// Return the file position, or -1 on failure.
-{
- assert(appdata);
- return ftell((FILE*)appdata);
-}
-
-static bool std_get_eof_func(void *appdata)
-// Return true if we're at EOF.
-{
- assert(appdata);
- if (feof((FILE*) appdata))
- {
- return true;
- }
- else
- {
- return false;
- }
-}
-
-static int std_close_func(void *appdata)
-// Return 0 on success, or TU_FILE_CLOSE_ERROR on failure.
-{
- assert(appdata);
- int result = fclose((FILE*)appdata);
- if (result == EOF)
- {
- // @@ TODO should set m_error to something relevant based on
errno.
- return TU_FILE_CLOSE_ERROR;
- }
- return 0;
-}
-
-
-//
-// tu_file functions using a readable/writable memory buffer
-//
-
-
-struct filebuf
-{
- membuf m_;
- int m_position;
- bool m_read_only;
-
- filebuf()
- :
- m_position(0),
- m_read_only(false)
- {
- }
-
- filebuf(int size, void* data)
- :
- m_(membuf::READ_ONLY, data, size),
- m_position(0),
- m_read_only(true)
- {
- }
-
- ~filebuf()
- {
- }
-
- bool resize(int new_size)
- // Return false if we couldn't resize.
- {
- if (m_read_only) return false;
-
- m_.resize(new_size);
-
- // Hm, does this make sense? We're truncating the file, so
clamping the cursor.
- // Alternative would be to disallow resize, but that doesn't
seem good either.
- if (m_position > m_.size())
- {
- m_position = m_.size();
- }
-
- return true;
- }
-
- bool is_valid()
- {
- return
- m_position >= 0
- && m_position <= m_.size();
- }
-
- unsigned char* get_cursor() { return ((unsigned char*) m_.data()) +
m_position; }
-};
-
-
-static int mem_read_func(void* dst, int bytes, void* appdata)
-// Return the number of bytes actually read. EOF or an error would
-// cause that to not be equal to "bytes".
-{
- assert(appdata);
- assert(dst);
-
- filebuf* buf = (filebuf*) appdata;
- assert(buf->is_valid());
-
- int bytes_to_read = imin(bytes, buf->m_.size() - buf->m_position);
- if (bytes_to_read)
- {
- memcpy(dst, buf->get_cursor(), bytes_to_read);
- }
- buf->m_position += bytes_to_read;
-
- return bytes_to_read;
-}
-
-
-static int mem_write_func(const void* src, int bytes, void* appdata)
-// Return the number of bytes actually written.
-{
- assert(appdata);
- assert(src);
-
- filebuf* buf = (filebuf*) appdata;
- assert(buf->is_valid());
-
- // Expand buffer if necessary.
- int bytes_to_expand = imax(0, buf->m_position + bytes -
buf->m_.size());
- if (bytes_to_expand)
- {
- if (buf->resize(buf->m_.size() + bytes_to_expand) == false)
- {
- // Couldn't expand!
- return 0;
- }
- }
-
- memcpy(buf->get_cursor(), src, bytes);
- buf->m_position += bytes;
-
- return bytes;
-}
-
-static int mem_seek_func(int pos, void *appdata)
-// Return 0 on success, or TU_FILE_SEEK_ERROR on failure.
-{
- assert(appdata);
- assert(pos >= 0);
-
- filebuf* buf = (filebuf*) appdata;
- assert(buf->is_valid());
-
- if (pos < 0)
- {
- buf->m_position = 0;
- return TU_FILE_SEEK_ERROR;
- }
-
- if (pos > buf->m_.size())
- {
- buf->m_position = buf->m_.size();
- return TU_FILE_SEEK_ERROR;
- }
-
- buf->m_position = pos;
- return 0;
-}
-
-static int mem_seek_to_end_func(void* appdata)
-// Return 0 on success, TU_FILE_SEEK_ERROR on failure.
-{
- assert(appdata);
-
- filebuf* buf = (filebuf*) appdata;
- assert(buf->is_valid());
-
- buf->m_position = buf->m_.size();
- return 0;
-}
-
-static int mem_tell_func(const void* appdata)
-// Return the file position, or -1 on failure.
-{
- assert(appdata);
-
- filebuf* buf = (filebuf*) appdata;
- assert(buf->is_valid());
-
- return buf->m_position;
-}
-
-static bool mem_get_eof_func(void* appdata)
-// Return true if we're positioned at the end of the buffer.
-{
- assert(appdata);
-
- filebuf* buf = (filebuf*) appdata;
- assert(buf->is_valid());
-
- return buf->m_position >= buf->m_.size();
-}
-
-static int mem_close_func(void* appdata)
-// Return 0 on success, or TU_FILE_CLOSE_ERROR on failure.
-{
- assert(appdata);
-
- filebuf* buf = (filebuf*) appdata;
- assert(buf->is_valid());
-
- delete buf;
-
- return 0;
-}
-
-
-//
-// generic functionality
-//
-
-
-tu_file::tu_file(
- void * appdata,
- read_func rf,
- write_func wf,
- seek_func sf,
- seek_to_end_func ef,
- tell_func tf,
- get_eof_func gef,
- close_func cf)
-// Create a file using the custom callbacks.
-{
- m_data = appdata;
- m_read = rf;
- m_write = wf;
- m_seek = sf;
- m_seek_to_end = ef;
- m_tell = tf;
- m_get_eof = gef;
- m_close = cf;
- m_error = TU_FILE_NO_ERROR;
-}
-
-
-tu_file::tu_file(FILE* fp, bool autoclose=false)
-// Create a file from a standard file pointer.
-{
- m_data = (void *)fp;
- m_read = std_read_func;
- m_write = std_write_func;
- m_seek = std_seek_func;
- m_seek_to_end = std_seek_to_end_func;
- m_tell = std_tell_func;
- m_get_eof = std_get_eof_func;
- m_close = autoclose ? std_close_func : NULL;
- m_error = TU_FILE_NO_ERROR;
-}
-
-
-tu_file::tu_file(const char * name, const char * mode)
-// Create a file from the given name and the given mode.
-{
- m_data = fopen(name, mode);
- if (m_data)
- {
- m_read = std_read_func;
- m_write = std_write_func;
- m_seek = std_seek_func;
- m_seek_to_end = std_seek_to_end_func;
- m_tell = std_tell_func;
- m_get_eof = std_get_eof_func;
- m_close = std_close_func;
- m_error = TU_FILE_NO_ERROR;
- }
- else
- {
- m_read = NULL;
- m_write = NULL;
- m_seek = NULL;
- m_seek_to_end = NULL;
- m_tell = NULL;
- m_get_eof = NULL;
- m_close = NULL;
- m_error = TU_FILE_OPEN_ERROR;
- }
-}
-
-
-tu_file::tu_file(memory_buffer_enum m)
-// Create a read/write memory buffer.
-{
- m_data = new membuf;
-
- m_read = mem_read_func;
- m_write = mem_write_func;
- m_seek = mem_seek_func;
- m_seek_to_end = mem_seek_to_end_func;
- m_tell = mem_tell_func;
- m_get_eof = mem_get_eof_func;
- m_close = mem_close_func;
- m_error = TU_FILE_NO_ERROR;
-}
-
-
-tu_file::tu_file(memory_buffer_enum m, int size, void* data)
-// Create a read-only memory buffer, using the given data.
-{
- m_data = new membuf(data, size);
-
- m_read = mem_read_func;
- m_write = mem_write_func;
- m_seek = mem_seek_func;
- m_seek_to_end = mem_seek_to_end_func;
- m_tell = mem_tell_func;
- m_get_eof = mem_get_eof_func;
- m_close = mem_close_func;
- m_error = TU_FILE_NO_ERROR;
-}
-
-
-tu_file::~tu_file()
-// Close this file when destroyed.
-{
- close();
-}
-
-
-void tu_file::close()
-// Close this file.
-{
- if (m_close)
- {
- m_close(m_data);
- }
- m_data = NULL;
- m_read = NULL;
- m_write = NULL;
- m_seek = NULL;
- m_tell = NULL;
- m_close = NULL;
-}
-
-
-void tu_file::copy_from(tu_file* src)
-// Copy remaining contents of *src into *this.
-{
- // @@ bah, should buffer this!
- while (src->get_eof() == false)
- {
- Uint8 b = src->read8();
- if (src->get_error())
- {
- break;
- }
-
- write8(b);
- }
-}
-
-
-void tu_file::copy_to(membuf* dst)
-// Copy remaining contents of *this into *dst.
-{
- static const int BUFSIZE = 4096;
-
- while (get_eof() == false)
- {
- // Make room at the end of dst.
- dst->resize(dst->size() + BUFSIZE);
- int bytes_read = read_bytes(((char*) dst->data()) + dst->size()
- BUFSIZE, BUFSIZE);
- if (bytes_read < BUFSIZE) {
- // Didn't use everything we allocated; trim the unused
bytes.
- dst->resize(dst->size() - (BUFSIZE - bytes_read));
- }
-
- if (get_error())
- {
- break;
- }
- }
-}
-
-
-int tu_file::copy_bytes(tu_file* src, int byte_count)
-// Copy a fixed number of bytes from *src into *this. Return the
-// number of bytes copied.
-{
- static const int BUFSIZE = 4096;
- char buffer[BUFSIZE];
-
- int bytes_left = byte_count;
- while (bytes_left)
- {
- int to_copy = imin(bytes_left, BUFSIZE);
-
- int read_count = src->read_bytes(buffer, to_copy);
- int write_count = write_bytes(buffer, read_count);
-
- assert(write_count <= read_count);
- assert(read_count <= to_copy);
- assert(to_copy <= bytes_left);
-
- bytes_left -= write_count;
- if (write_count < to_copy)
- {
- // Some kind of error; abort.
- return byte_count - bytes_left;
- }
- }
-
- assert(bytes_left == 0);
-
- return byte_count;
-}
-
-
-void tu_file::write_string(const char* src)
-{
- for (;;)
- {
- write8(*src);
- if (*src == 0)
- {
- break;
- }
- src++;
- }
-}
-
-
-int tu_file::read_string(char* dst, int max_length)
-{
- int i=0;
- while (i<max_length)
- {
- dst[i] = read8();
- if (dst[i]=='\0')
- {
- return i;
- }
- i++;
- }
-
- dst[max_length - 1] = 0; // force termination.
-
- return -1;
-}
-
-
-
-#include <stdarg.h>
-#include <string.h>
-
-#ifdef _WIN32
-#define vsnprintf _vsnprintf
-#endif // _WIN32
-
-
-int tu_file::printf(const char* fmt, ...)
-// Use printf-like semantics to send output to this stream.
-{
- // Workspace for vsnprintf formatting.
- static const int BUFFER_SIZE = 1000;
- char buffer[BUFFER_SIZE];
-
- va_list ap;
- va_start(ap, fmt);
- vsnprintf(buffer, BUFFER_SIZE, fmt, ap);
- va_end(ap);
-
- return write_bytes(buffer, strlen(buffer));
-}
-
-
-// Local Variables:
-// mode: C++
-// c-basic-offset: 8
-// tab-width: 8
-// indent-tabs-mode: t
-// End:
+// tu_file.cpp -- Ignacio Castaño, Thatcher Ulrich <address@hidden> 2003
+
+// This source code has been donated to the Public Domain. Do
+// whatever you want with it.
+
+// A file class that can be customized with callbacks.
+
+
+#include "tu_file.h"
+#include "utility.h"
+#include "container.h"
+#include "membuf.h"
+
+
+//
+// tu_file functions using FILE
+//
+
+
+static int std_read_func(void* dst, int bytes, void* appdata)
+// Return the number of bytes actually read. EOF or an error would
+// cause that to not be equal to "bytes".
+{
+ assert(appdata);
+ assert(dst);
+ return fread( dst, 1, bytes, (FILE *)appdata );
+}
+
+static int std_write_func(const void* src, int bytes, void* appdata)
+// Return the number of bytes actually written.
+{
+ assert(appdata);
+ assert(src);
+ return fwrite( src, 1, bytes, (FILE *)appdata );
+}
+
+static int std_seek_func(int pos, void *appdata)
+// Return 0 on success, or TU_FILE_SEEK_ERROR on failure.
+{
+ assert(appdata);
+ clearerr((FILE*) appdata); // make sure EOF flag is cleared.
+ int result = fseek((FILE*)appdata, pos, SEEK_SET);
+ if (result == EOF)
+ {
+ // @@ TODO should set m_error to something relevant based on
errno.
+ return TU_FILE_SEEK_ERROR;
+ }
+ return 0;
+}
+
+static int std_seek_to_end_func(void *appdata)
+// Return 0 on success, TU_FILE_SEEK_ERROR on failure.
+{
+ assert(appdata);
+ int result = fseek((FILE*)appdata, 0, SEEK_END);
+ if (result == EOF)
+ {
+ // @@ TODO should set m_error to something relevant based on
errno.
+ return TU_FILE_SEEK_ERROR;
+ }
+ return 0;
+}
+
+static int std_tell_func(const void *appdata)
+// Return the file position, or -1 on failure.
+{
+ assert(appdata);
+ return ftell((FILE*)appdata);
+}
+
+static bool std_get_eof_func(void *appdata)
+// Return true if we're at EOF.
+{
+ assert(appdata);
+ if (feof((FILE*) appdata))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+static int std_close_func(void *appdata)
+// Return 0 on success, or TU_FILE_CLOSE_ERROR on failure.
+{
+ assert(appdata);
+ int result = fclose((FILE*)appdata);
+ if (result == EOF)
+ {
+ // @@ TODO should set m_error to something relevant based on
errno.
+ return TU_FILE_CLOSE_ERROR;
+ }
+ return 0;
+}
+
+
+//
+// tu_file functions using a readable/writable memory buffer
+//
+
+
+struct filebuf
+{
+ membuf m_;
+ int m_position;
+ bool m_read_only;
+
+ filebuf()
+ :
+ m_position(0),
+ m_read_only(false)
+ {
+ }
+
+ filebuf(int size, void* data)
+ :
+ m_(membuf::READ_ONLY, data, size),
+ m_position(0),
+ m_read_only(true)
+ {
+ }
+
+ ~filebuf()
+ {
+ }
+
+ bool resize(int new_size)
+ // Return false if we couldn't resize.
+ {
+ if (m_read_only) return false;
+
+ m_.resize(new_size);
+
+ // Hm, does this make sense? We're truncating the file, so
clamping the cursor.
+ // Alternative would be to disallow resize, but that doesn't
seem good either.
+ if (m_position > m_.size())
+ {
+ m_position = m_.size();
+ }
+
+ return true;
+ }
+
+ bool is_valid()
+ {
+ return
+ m_position >= 0
+ && m_position <= m_.size();
+ }
+
+ unsigned char* get_cursor() { return ((unsigned char*) m_.data()) +
m_position; }
+};
+
+
+static int mem_read_func(void* dst, int bytes, void* appdata)
+// Return the number of bytes actually read. EOF or an error would
+// cause that to not be equal to "bytes".
+{
+ assert(appdata);
+ assert(dst);
+
+ filebuf* buf = (filebuf*) appdata;
+ assert(buf->is_valid());
+
+ int bytes_to_read = imin(bytes, buf->m_.size() - buf->m_position);
+ if (bytes_to_read)
+ {
+ memcpy(dst, buf->get_cursor(), bytes_to_read);
+ }
+ buf->m_position += bytes_to_read;
+
+ return bytes_to_read;
+}
+
+
+static int mem_write_func(const void* src, int bytes, void* appdata)
+// Return the number of bytes actually written.
+{
+ assert(appdata);
+ assert(src);
+
+ filebuf* buf = (filebuf*) appdata;
+ assert(buf->is_valid());
+
+ // Expand buffer if necessary.
+ int bytes_to_expand = imax(0, buf->m_position + bytes -
buf->m_.size());
+ if (bytes_to_expand)
+ {
+ if (buf->resize(buf->m_.size() + bytes_to_expand) == false)
+ {
+ // Couldn't expand!
+ return 0;
+ }
+ }
+
+ memcpy(buf->get_cursor(), src, bytes);
+ buf->m_position += bytes;
+
+ return bytes;
+}
+
+static int mem_seek_func(int pos, void *appdata)
+// Return 0 on success, or TU_FILE_SEEK_ERROR on failure.
+{
+ assert(appdata);
+ assert(pos >= 0);
+
+ filebuf* buf = (filebuf*) appdata;
+ assert(buf->is_valid());
+
+ if (pos < 0)
+ {
+ buf->m_position = 0;
+ return TU_FILE_SEEK_ERROR;
+ }
+
+ if (pos > buf->m_.size())
+ {
+ buf->m_position = buf->m_.size();
+ return TU_FILE_SEEK_ERROR;
+ }
+
+ buf->m_position = pos;
+ return 0;
+}
+
+static int mem_seek_to_end_func(void* appdata)
+// Return 0 on success, TU_FILE_SEEK_ERROR on failure.
+{
+ assert(appdata);
+
+ filebuf* buf = (filebuf*) appdata;
+ assert(buf->is_valid());
+
+ buf->m_position = buf->m_.size();
+ return 0;
+}
+
+static int mem_tell_func(const void* appdata)
+// Return the file position, or -1 on failure.
+{
+ assert(appdata);
+
+ filebuf* buf = (filebuf*) appdata;
+ assert(buf->is_valid());
+
+ return buf->m_position;
+}
+
+static bool mem_get_eof_func(void* appdata)
+// Return true if we're positioned at the end of the buffer.
+{
+ assert(appdata);
+
+ filebuf* buf = (filebuf*) appdata;
+ assert(buf->is_valid());
+
+ return buf->m_position >= buf->m_.size();
+}
+
+static int mem_close_func(void* appdata)
+// Return 0 on success, or TU_FILE_CLOSE_ERROR on failure.
+{
+ assert(appdata);
+
+ filebuf* buf = (filebuf*) appdata;
+ assert(buf->is_valid());
+
+ delete buf;
+
+ return 0;
+}
+
+
+//
+// generic functionality
+//
+
+
+tu_file::tu_file(
+ void * appdata,
+ read_func rf,
+ write_func wf,
+ seek_func sf,
+ seek_to_end_func ef,
+ tell_func tf,
+ get_eof_func gef,
+ close_func cf)
+// Create a file using the custom callbacks.
+{
+ m_data = appdata;
+ m_read = rf;
+ m_write = wf;
+ m_seek = sf;
+ m_seek_to_end = ef;
+ m_tell = tf;
+ m_get_eof = gef;
+ m_close = cf;
+ m_error = TU_FILE_NO_ERROR;
+}
+
+
+tu_file::tu_file(FILE* fp, bool autoclose=false)
+// Create a file from a standard file pointer.
+{
+ m_data = (void *)fp;
+ m_read = std_read_func;
+ m_write = std_write_func;
+ m_seek = std_seek_func;
+ m_seek_to_end = std_seek_to_end_func;
+ m_tell = std_tell_func;
+ m_get_eof = std_get_eof_func;
+ m_close = autoclose ? std_close_func : NULL;
+ m_error = TU_FILE_NO_ERROR;
+}
+
+
+tu_file::tu_file(const char * name, const char * mode)
+// Create a file from the given name and the given mode.
+{
+ m_data = fopen(name, mode);
+ if (m_data)
+ {
+ m_read = std_read_func;
+ m_write = std_write_func;
+ m_seek = std_seek_func;
+ m_seek_to_end = std_seek_to_end_func;
+ m_tell = std_tell_func;
+ m_get_eof = std_get_eof_func;
+ m_close = std_close_func;
+ m_error = TU_FILE_NO_ERROR;
+ }
+ else
+ {
+ m_read = NULL;
+ m_write = NULL;
+ m_seek = NULL;
+ m_seek_to_end = NULL;
+ m_tell = NULL;
+ m_get_eof = NULL;
+ m_close = NULL;
+ m_error = TU_FILE_OPEN_ERROR;
+ }
+}
+
+
+tu_file::tu_file(memory_buffer_enum m)
+// Create a read/write memory buffer.
+{
+ m_data = new membuf;
+
+ m_read = mem_read_func;
+ m_write = mem_write_func;
+ m_seek = mem_seek_func;
+ m_seek_to_end = mem_seek_to_end_func;
+ m_tell = mem_tell_func;
+ m_get_eof = mem_get_eof_func;
+ m_close = mem_close_func;
+ m_error = TU_FILE_NO_ERROR;
+}
+
+
+tu_file::tu_file(memory_buffer_enum m, int size, void* data)
+// Create a read-only memory buffer, using the given data.
+{
+ m_data = new membuf(data, size);
+
+ m_read = mem_read_func;
+ m_write = mem_write_func;
+ m_seek = mem_seek_func;
+ m_seek_to_end = mem_seek_to_end_func;
+ m_tell = mem_tell_func;
+ m_get_eof = mem_get_eof_func;
+ m_close = mem_close_func;
+ m_error = TU_FILE_NO_ERROR;
+}
+
+
+tu_file::~tu_file()
+// Close this file when destroyed.
+{
+ close();
+}
+
+
+void tu_file::close()
+// Close this file.
+{
+ if (m_close)
+ {
+ m_close(m_data);
+ }
+ m_data = NULL;
+ m_read = NULL;
+ m_write = NULL;
+ m_seek = NULL;
+ m_tell = NULL;
+ m_close = NULL;
+}
+
+
+void tu_file::copy_from(tu_file* src)
+// Copy remaining contents of *src into *this.
+{
+ // @@ bah, should buffer this!
+ while (src->get_eof() == false)
+ {
+ Uint8 b = src->read8();
+ if (src->get_error())
+ {
+ break;
+ }
+
+ write8(b);
+ }
+}
+
+
+void tu_file::copy_to(membuf* dst)
+// Copy remaining contents of *this into *dst.
+{
+ static const int BUFSIZE = 4096;
+
+ while (get_eof() == false)
+ {
+ // Make room at the end of dst.
+ dst->resize(dst->size() + BUFSIZE);
+ int bytes_read = read_bytes(((char*) dst->data()) + dst->size()
- BUFSIZE, BUFSIZE);
+ if (bytes_read < BUFSIZE) {
+ // Didn't use everything we allocated; trim the unused
bytes.
+ dst->resize(dst->size() - (BUFSIZE - bytes_read));
+ }
+
+ if (get_error())
+ {
+ break;
+ }
+ }
+}
+
+
+int tu_file::copy_bytes(tu_file* src, int byte_count)
+// Copy a fixed number of bytes from *src into *this. Return the
+// number of bytes copied.
+{
+ static const int BUFSIZE = 4096;
+ char buffer[BUFSIZE];
+
+ int bytes_left = byte_count;
+ while (bytes_left)
+ {
+ int to_copy = imin(bytes_left, BUFSIZE);
+
+ int read_count = src->read_bytes(buffer, to_copy);
+ int write_count = write_bytes(buffer, read_count);
+
+ assert(write_count <= read_count);
+ assert(read_count <= to_copy);
+ assert(to_copy <= bytes_left);
+
+ bytes_left -= write_count;
+ if (write_count < to_copy)
+ {
+ // Some kind of error; abort.
+ return byte_count - bytes_left;
+ }
+ }
+
+ assert(bytes_left == 0);
+
+ return byte_count;
+}
+
+
+void tu_file::write_string(const char* src)
+{
+ for (;;)
+ {
+ write8(*src);
+ if (*src == 0)
+ {
+ break;
+ }
+ src++;
+ }
+}
+
+
+int tu_file::read_string(char* dst, int max_length)
+{
+ int i=0;
+ while (i<max_length)
+ {
+ dst[i] = read8();
+ if (dst[i]=='\0')
+ {
+ return i;
+ }
+ i++;
+ }
+
+ dst[max_length - 1] = 0; // force termination.
+
+ return -1;
+}
+
+
+
+#include <stdarg.h>
+#include <string.h>
+
+#ifdef _WIN32
+#define vsnprintf _vsnprintf
+#endif // _WIN32
+
+
+int tu_file::printf(const char* fmt, ...)
+// Use printf-like semantics to send output to this stream.
+{
+ // Workspace for vsnprintf formatting.
+ static const int BUFFER_SIZE = 1000;
+ char buffer[BUFFER_SIZE];
+
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(buffer, BUFFER_SIZE, fmt, ap);
+ va_end(ap);
+
+ return write_bytes(buffer, strlen(buffer));
+}
+
+
+// Local Variables:
+// mode: C++
+// c-basic-offset: 8
+// tab-width: 8
+// indent-tabs-mode: t
+// End:
Index: gnash/libbase/tu_file_SDL.cpp
diff -u gnash/libbase/tu_file_SDL.cpp:1.1 gnash/libbase/tu_file_SDL.cpp:1.2
--- gnash/libbase/tu_file_SDL.cpp:1.1 Tue Dec 20 20:57:00 2005
+++ gnash/libbase/tu_file_SDL.cpp Sun Feb 26 15:49:30 2006
@@ -1,120 +1,120 @@
-// tu_file_SDL.cpp -- Ignacio Castaño, Thatcher Ulrich <address@hidden>
2003
-
-// This source code has been donated to the Public Domain. Do
-// whatever you want with it.
-
-// tu_file constructor, for creating a tu_file from an SDL_RWops*
-// stream. In its own source file so that if clients of the base
-// library don't call it, it won't get pulled in by the linker and
-// won't try to link with SDL.
-
-
-#include "tu_file.h"
-#include "utility.h"
-#include <SDL.h>
-
-
-// TODO: add error detection and reporting!!!
-
-static int sdl_read_func(void* dst, int bytes, void* appdata)
-{
- assert(dst);
- assert(appdata);
- int result = SDL_RWread((SDL_RWops*) appdata, dst, 1, bytes);
- if (result == -1)
- {
- // @@ set appdata->m_error?
- return 0;
- }
- return result;
-}
-
-static int sdl_write_func(const void* src, int bytes, void* appdata)
-{
- assert(src);
- assert(appdata);
- int result = SDL_RWwrite((SDL_RWops*) appdata, src, 1, bytes);
- if (result == -1)
- {
- // @@ set m_errer?
- return 0;
- }
- return result;
-}
-
-static int sdl_seek_func(int pos, void *appdata)
-{
- assert(pos >= 0);
- assert(appdata);
- return SDL_RWseek((SDL_RWops*) appdata, pos, SEEK_SET);
-}
-
-static int sdl_seek_to_end_func(void *appdata)
-{
- assert(appdata);
- return SDL_RWseek((SDL_RWops*) appdata, 0, SEEK_END);
-}
-
-static int sdl_tell_func(const void *appdata)
-{
- assert(appdata);
- return SDL_RWtell((SDL_RWops*) appdata);
-}
-
-static bool sdl_get_eof_func(void* appdata)
-{
- assert(appdata);
-
- int cur_pos = sdl_tell_func(appdata);
- sdl_seek_to_end_func(appdata);
- int end_pos = sdl_tell_func(appdata);
- if (end_pos <= cur_pos)
- {
- return true;
- }
- else
- {
- sdl_seek_func(cur_pos, appdata);
- return false;
- }
-}
-
-static int sdl_close_func(void *appdata)
-{
- assert(appdata);
- int result = SDL_RWclose((SDL_RWops*) appdata);
- if (result != 0)
- {
- return TU_FILE_CLOSE_ERROR;
- }
- return 0;
-}
-
-
-tu_file::tu_file(SDL_RWops* sdl_stream, bool autoclose)
-// Create a tu_file object that can be used to read/write stuff. Use
-// an SDL_RWops* as the underlying implementation.
-//
-// If autoclose is true, then the sdl_stream has SDL_RWclose()
-// called on it when the resulting file object is destructed.
-{
- assert(sdl_stream);
-
- m_data = (void*) sdl_stream;
- m_read = sdl_read_func;
- m_write = sdl_write_func;
- m_seek = sdl_seek_func;
- m_seek_to_end = sdl_seek_to_end_func;
- m_tell = sdl_tell_func;
- m_get_eof = sdl_get_eof_func;
- m_close = autoclose ? sdl_close_func : NULL;
- m_error = TU_FILE_NO_ERROR;
-}
-
-
-// Local Variables:
-// mode: C++
-// c-basic-offset: 8
-// tab-width: 8
-// indent-tabs-mode: t
-// End:
+// tu_file_SDL.cpp -- Ignacio Castaño, Thatcher Ulrich <address@hidden>
2003
+
+// This source code has been donated to the Public Domain. Do
+// whatever you want with it.
+
+// tu_file constructor, for creating a tu_file from an SDL_RWops*
+// stream. In its own source file so that if clients of the base
+// library don't call it, it won't get pulled in by the linker and
+// won't try to link with SDL.
+
+
+#include "tu_file.h"
+#include "utility.h"
+#include <SDL.h>
+
+
+// TODO: add error detection and reporting!!!
+
+static int sdl_read_func(void* dst, int bytes, void* appdata)
+{
+ assert(dst);
+ assert(appdata);
+ int result = SDL_RWread((SDL_RWops*) appdata, dst, 1, bytes);
+ if (result == -1)
+ {
+ // @@ set appdata->m_error?
+ return 0;
+ }
+ return result;
+}
+
+static int sdl_write_func(const void* src, int bytes, void* appdata)
+{
+ assert(src);
+ assert(appdata);
+ int result = SDL_RWwrite((SDL_RWops*) appdata, src, 1, bytes);
+ if (result == -1)
+ {
+ // @@ set m_errer?
+ return 0;
+ }
+ return result;
+}
+
+static int sdl_seek_func(int pos, void *appdata)
+{
+ assert(pos >= 0);
+ assert(appdata);
+ return SDL_RWseek((SDL_RWops*) appdata, pos, SEEK_SET);
+}
+
+static int sdl_seek_to_end_func(void *appdata)
+{
+ assert(appdata);
+ return SDL_RWseek((SDL_RWops*) appdata, 0, SEEK_END);
+}
+
+static int sdl_tell_func(const void *appdata)
+{
+ assert(appdata);
+ return SDL_RWtell((SDL_RWops*) appdata);
+}
+
+static bool sdl_get_eof_func(void* appdata)
+{
+ assert(appdata);
+
+ int cur_pos = sdl_tell_func(appdata);
+ sdl_seek_to_end_func(appdata);
+ int end_pos = sdl_tell_func(appdata);
+ if (end_pos <= cur_pos)
+ {
+ return true;
+ }
+ else
+ {
+ sdl_seek_func(cur_pos, appdata);
+ return false;
+ }
+}
+
+static int sdl_close_func(void *appdata)
+{
+ assert(appdata);
+ int result = SDL_RWclose((SDL_RWops*) appdata);
+ if (result != 0)
+ {
+ return TU_FILE_CLOSE_ERROR;
+ }
+ return 0;
+}
+
+
+tu_file::tu_file(SDL_RWops* sdl_stream, bool autoclose)
+// Create a tu_file object that can be used to read/write stuff. Use
+// an SDL_RWops* as the underlying implementation.
+//
+// If autoclose is true, then the sdl_stream has SDL_RWclose()
+// called on it when the resulting file object is destructed.
+{
+ assert(sdl_stream);
+
+ m_data = (void*) sdl_stream;
+ m_read = sdl_read_func;
+ m_write = sdl_write_func;
+ m_seek = sdl_seek_func;
+ m_seek_to_end = sdl_seek_to_end_func;
+ m_tell = sdl_tell_func;
+ m_get_eof = sdl_get_eof_func;
+ m_close = autoclose ? sdl_close_func : NULL;
+ m_error = TU_FILE_NO_ERROR;
+}
+
+
+// Local Variables:
+// mode: C++
+// c-basic-offset: 8
+// tab-width: 8
+// indent-tabs-mode: t
+// End:
Index: gnash/libbase/tu_random.cpp
diff -u gnash/libbase/tu_random.cpp:1.1 gnash/libbase/tu_random.cpp:1.2
--- gnash/libbase/tu_random.cpp:1.1 Tue Dec 20 20:57:00 2005
+++ gnash/libbase/tu_random.cpp Sun Feb 26 15:49:30 2006
@@ -1,150 +1,150 @@
-// tu_random.cpp -- Thatcher Ulrich 2003
-
-// This source code has been donated to the Public Domain. Do
-// whatever you want with it.
-
-// Pseudorandom number generator.
-
-
-#include "tu_random.h"
-
-
-namespace tu_random
-{
- // Global generator.
- static generator s_generator;
-
- Uint32 next_random()
- {
- return s_generator.next_random();
- }
-
- void seed_random(Uint32 seed)
- {
- s_generator.seed_random(seed);
- }
-
- float get_unit_float()
- {
- return s_generator.get_unit_float();
- }
-
-
- // PRNG code adapted from the complimentary-multiply-with-carry
- // code in the article: George Marsaglia, "Seeds for Random Number
- // Generators", Communications of the ACM, May 2003, Vol 46 No 5,
- // pp90-93.
- //
- // The article says:
- //
- // "Any one of the choices for seed table size and multiplier will
- // provide a RNG that has passed extensive tests of randomness,
- // particularly those in [3], yet is simple and fast --
- // approximately 30 million random 32-bit integers per second on a
- // 850MHz PC. The period is a*b^n, where a is the multiplier, n
- // the size of the seed table and b=2^32-1. (a is chosen so that
- // b is a primitive root of the prime a*b^n + 1.)"
- //
- // [3] Marsaglia, G., Zaman, A., and Tsang, W. Toward a universal
- // random number generator. _Statistics and Probability Letters
- // 8_ (1990), 35-39.
-
-// const Uint64 a = 123471786; // for SEED_COUNT=1024
-// const Uint64 a = 123554632; // for SEED_COUNT=512
-// const Uint64 a = 8001634; // for SEED_COUNT=255
-// const Uint64 a = 8007626; // for SEED_COUNT=128
-// const Uint64 a = 647535442; // for SEED_COUNT=64
-// const Uint64 a = 547416522; // for SEED_COUNT=32
-// const Uint64 a = 487198574; // for SEED_COUNT=16
- const Uint64 a = 716514398; // for SEED_COUNT=8
-
-
- generator::generator()
- :
- c(362436),
- i(SEED_COUNT - 1)
- {
- seed_random(987654321);
- }
-
-
- void generator::seed_random(Uint32 seed)
- {
- // Simple pseudo-random to reseed the seeds.
- // Suggested by the above article.
- Uint32 j = seed;
- for (int i = 0; i < SEED_COUNT; i++)
- {
- j = j ^ (j << 13);
- j = j ^ (j >> 17);
- j = j ^ (j << 5);
- Q[i] = j;
- }
- }
-
-
- Uint32 generator::next_random()
- // Return the next pseudo-random number in the sequence.
- {
- Uint64 t;
- Uint32 x;
-
- //static Uint32 c = 362436;
- //static Uint32 i = SEED_COUNT - 1;
- const Uint32 r = 0xFFFFFFFE;
-
- i = (i+1) & (SEED_COUNT - 1);
- t = a * Q[i] + c;
- c = (Uint32) (t >> 32);
- x = (Uint32) (t + c);
- if (x < c)
- {
- x++;
- c++;
- }
-
- Uint32 val = r - x;
- Q[i] = val;
- return val;
- }
-
-
- float generator::get_unit_float()
- {
- Uint32 r = next_random();
-
- // 24 bits of precision.
- return float(r >> 8) / (16777216.0f - 1.0f);
- }
-
-} // end namespace tu_random
-
-
-#ifdef TEST_TU_RANDOM
-
-// Compile with e.g.:
-//
-// gcc -o tu_random_test tu_random.cpp -I.. -g -DTEST_TU_RANDOM -lstdc++
-//
-// Generate a test file of random numbers for DIEHARD.
-int main()
-{
- const int COUNT = 15000000 / 4; // number of 4-byte words;
DIEHARD needs ~80M bits
-
- for (int i = 0; i < COUNT; i++)
- {
- Uint32 val = tu_random::next_random();
- fwrite(&val, sizeof(val), 1, stdout);
- }
-}
-
-
-#endif // TEST_TU_RANDOM
-
-
-// Local Variables:
-// mode: C++
-// c-basic-offset: 8
-// tab-width: 8
-// indent-tabs-mode: t
-// End:
+// tu_random.cpp -- Thatcher Ulrich 2003
+
+// This source code has been donated to the Public Domain. Do
+// whatever you want with it.
+
+// Pseudorandom number generator.
+
+
+#include "tu_random.h"
+
+
+namespace tu_random
+{
+ // Global generator.
+ static generator s_generator;
+
+ Uint32 next_random()
+ {
+ return s_generator.next_random();
+ }
+
+ void seed_random(Uint32 seed)
+ {
+ s_generator.seed_random(seed);
+ }
+
+ float get_unit_float()
+ {
+ return s_generator.get_unit_float();
+ }
+
+
+ // PRNG code adapted from the complimentary-multiply-with-carry
+ // code in the article: George Marsaglia, "Seeds for Random Number
+ // Generators", Communications of the ACM, May 2003, Vol 46 No 5,
+ // pp90-93.
+ //
+ // The article says:
+ //
+ // "Any one of the choices for seed table size and multiplier will
+ // provide a RNG that has passed extensive tests of randomness,
+ // particularly those in [3], yet is simple and fast --
+ // approximately 30 million random 32-bit integers per second on a
+ // 850MHz PC. The period is a*b^n, where a is the multiplier, n
+ // the size of the seed table and b=2^32-1. (a is chosen so that
+ // b is a primitive root of the prime a*b^n + 1.)"
+ //
+ // [3] Marsaglia, G., Zaman, A., and Tsang, W. Toward a universal
+ // random number generator. _Statistics and Probability Letters
+ // 8_ (1990), 35-39.
+
+// const Uint64 a = 123471786; // for SEED_COUNT=1024
+// const Uint64 a = 123554632; // for SEED_COUNT=512
+// const Uint64 a = 8001634; // for SEED_COUNT=255
+// const Uint64 a = 8007626; // for SEED_COUNT=128
+// const Uint64 a = 647535442; // for SEED_COUNT=64
+// const Uint64 a = 547416522; // for SEED_COUNT=32
+// const Uint64 a = 487198574; // for SEED_COUNT=16
+ const Uint64 a = 716514398; // for SEED_COUNT=8
+
+
+ generator::generator()
+ :
+ c(362436),
+ i(SEED_COUNT - 1)
+ {
+ seed_random(987654321);
+ }
+
+
+ void generator::seed_random(Uint32 seed)
+ {
+ // Simple pseudo-random to reseed the seeds.
+ // Suggested by the above article.
+ Uint32 j = seed;
+ for (int i = 0; i < SEED_COUNT; i++)
+ {
+ j = j ^ (j << 13);
+ j = j ^ (j >> 17);
+ j = j ^ (j << 5);
+ Q[i] = j;
+ }
+ }
+
+
+ Uint32 generator::next_random()
+ // Return the next pseudo-random number in the sequence.
+ {
+ Uint64 t;
+ Uint32 x;
+
+ //static Uint32 c = 362436;
+ //static Uint32 i = SEED_COUNT - 1;
+ const Uint32 r = 0xFFFFFFFE;
+
+ i = (i+1) & (SEED_COUNT - 1);
+ t = a * Q[i] + c;
+ c = (Uint32) (t >> 32);
+ x = (Uint32) (t + c);
+ if (x < c)
+ {
+ x++;
+ c++;
+ }
+
+ Uint32 val = r - x;
+ Q[i] = val;
+ return val;
+ }
+
+
+ float generator::get_unit_float()
+ {
+ Uint32 r = next_random();
+
+ // 24 bits of precision.
+ return float(r >> 8) / (16777216.0f - 1.0f);
+ }
+
+} // end namespace tu_random
+
+
+#ifdef TEST_TU_RANDOM
+
+// Compile with e.g.:
+//
+// gcc -o tu_random_test tu_random.cpp -I.. -g -DTEST_TU_RANDOM -lstdc++
+//
+// Generate a test file of random numbers for DIEHARD.
+int main()
+{
+ const int COUNT = 15000000 / 4; // number of 4-byte words;
DIEHARD needs ~80M bits
+
+ for (int i = 0; i < COUNT; i++)
+ {
+ Uint32 val = tu_random::next_random();
+ fwrite(&val, sizeof(val), 1, stdout);
+ }
+}
+
+
+#endif // TEST_TU_RANDOM
+
+
+// Local Variables:
+// mode: C++
+// c-basic-offset: 8
+// tab-width: 8
+// indent-tabs-mode: t
+// End:
Index: gnash/libbase/tu_swap.h
diff -u gnash/libbase/tu_swap.h:1.1 gnash/libbase/tu_swap.h:1.2
--- gnash/libbase/tu_swap.h:1.1 Tue Dec 20 20:57:00 2005
+++ gnash/libbase/tu_swap.h Sun Feb 26 15:49:30 2006
@@ -28,6 +28,9 @@
// endian conversions
//
+#ifdef swap16
+#undef swap16
+#endif
inline Uint16 swap16(Uint16 u)
{
@@ -35,6 +38,9 @@
((u & 0xFF00) >> 8);
}
+#ifdef swap32
+#undef swap32
+#endif
inline Uint32 swap32(Uint32 u)
{
return ((u & 0x000000FF) << 24) |
@@ -43,6 +49,9 @@
((u & 0xFF000000) >> 24);
}
+#ifdef swap64
+#undef swap64
+#endif
inline Uint64 swap64(Uint64 u)
{
#ifdef __GNUC__
Index: gnash/libbase/tu_timer.cpp
diff -u gnash/libbase/tu_timer.cpp:1.1 gnash/libbase/tu_timer.cpp:1.2
--- gnash/libbase/tu_timer.cpp:1.1 Tue Dec 20 20:57:00 2005
+++ gnash/libbase/tu_timer.cpp Sun Feb 26 15:49:30 2006
@@ -1,104 +1,104 @@
-// tu_timer.cpp -- by Thatcher Ulrich <address@hidden>
-
-// This source code has been donated to the Public Domain. Do
-// whatever you want with it.
-
-// Utility/profiling timer.
-
-
-#include "tu_timer.h"
-
-
-#ifdef _WIN32
-
-#include <windows.h>
-
-
-uint64 tu_timer::get_ticks()
-{
- return timeGetTime();
-}
-
-
-double tu_timer::ticks_to_seconds(uint64 ticks)
-{
- return ticks * (1.0f / 1000.f);
-}
-
-
-uint64 tu_timer::get_profile_ticks()
-{
- // @@ use rdtsc?
-
- LARGE_INTEGER li;
- QueryPerformanceCounter(&li);
-
- return li.QuadPart;
-}
-
-
-double tu_timer::profile_ticks_to_seconds(uint64 ticks)
-{
- LARGE_INTEGER freq;
- QueryPerformanceFrequency(&freq);
-
- double seconds = (double) ticks;
- seconds /= (double) freq.QuadPart;
-
- return seconds;
-}
-
-
-#else // not _WIN32
-
-
-#include <sys/time.h>
-
-
-// The profile ticks implementation is just fine for a normal timer.
-
-
-uint64 tu_timer::get_ticks()
-{
- return get_profile_ticks();
-}
-
-
-double tu_timer::ticks_to_seconds(uint64 ticks)
-{
- return profile_ticks_to_seconds(ticks);
-}
-
-
-uint64 tu_timer::get_profile_ticks()
-{
- // @@ TODO prefer rdtsc when available?
-
- // Return microseconds.
- struct timeval tv;
- uint64 result;
-
- gettimeofday(&tv, 0);
-
- result = tv.tv_sec * 1000000;
- result += tv.tv_usec;
-
- return result;
-}
-
-
-double tu_timer::profile_ticks_to_seconds(uint64 ticks)
-{
- // ticks is microseconds. Convert to seconds.
- return ticks / 1000000.0;
-}
-
-#endif // not _WIN32
-
-
-// Local Variables:
-// mode: C++
-// c-basic-offset: 8
-// tab-width: 8
-// indent-tabs-mode: t
-// End:
+// tu_timer.cpp -- by Thatcher Ulrich <address@hidden>
+
+// This source code has been donated to the Public Domain. Do
+// whatever you want with it.
+
+// Utility/profiling timer.
+
+
+#include "tu_timer.h"
+
+
+#ifdef _WIN32
+
+#include <windows.h>
+
+
+uint64 tu_timer::get_ticks()
+{
+ return timeGetTime();
+}
+
+
+double tu_timer::ticks_to_seconds(uint64 ticks)
+{
+ return ticks * (1.0f / 1000.f);
+}
+
+
+uint64 tu_timer::get_profile_ticks()
+{
+ // @@ use rdtsc?
+
+ LARGE_INTEGER li;
+ QueryPerformanceCounter(&li);
+
+ return li.QuadPart;
+}
+
+
+double tu_timer::profile_ticks_to_seconds(uint64 ticks)
+{
+ LARGE_INTEGER freq;
+ QueryPerformanceFrequency(&freq);
+
+ double seconds = (double) ticks;
+ seconds /= (double) freq.QuadPart;
+
+ return seconds;
+}
+
+
+#else // not _WIN32
+
+
+#include <sys/time.h>
+
+
+// The profile ticks implementation is just fine for a normal timer.
+
+
+uint64 tu_timer::get_ticks()
+{
+ return get_profile_ticks();
+}
+
+
+double tu_timer::ticks_to_seconds(uint64 ticks)
+{
+ return profile_ticks_to_seconds(ticks);
+}
+
+
+uint64 tu_timer::get_profile_ticks()
+{
+ // @@ TODO prefer rdtsc when available?
+
+ // Return microseconds.
+ struct timeval tv;
+ uint64 result;
+
+ gettimeofday(&tv, 0);
+
+ result = tv.tv_sec * 1000000;
+ result += tv.tv_usec;
+
+ return result;
+}
+
+
+double tu_timer::profile_ticks_to_seconds(uint64 ticks)
+{
+ // ticks is microseconds. Convert to seconds.
+ return ticks / 1000000.0;
+}
+
+#endif // not _WIN32
+
+
+// Local Variables:
+// mode: C++
+// c-basic-offset: 8
+// tab-width: 8
+// indent-tabs-mode: t
+// End:
Index: gnash/libbase/tu_types.cpp
diff -u gnash/libbase/tu_types.cpp:1.1 gnash/libbase/tu_types.cpp:1.2
--- gnash/libbase/tu_types.cpp:1.1 Tue Dec 20 20:57:00 2005
+++ gnash/libbase/tu_types.cpp Sun Feb 26 15:49:30 2006
@@ -1,60 +1,60 @@
-// tu_types.cpp -- Ignacio Castaño, Thatcher Ulrich 2003
-
-// This source code has been donated to the Public Domain. Do
-// whatever you want with it.
-
-// Minimal typedefs. Follows SDL conventions; falls back on SDL.h if
-// platform isn't obvious.
-
-
-#include "tu_types.h"
-#include "utility.h"
-
-
-bool tu_types_validate()
-{
- // Check typedef sizes.
- if (sizeof(Uint8) != 1
- || sizeof(Uint16) != 2
- || sizeof(Uint32) != 4
- || sizeof(Uint64) != 8
- || sizeof(Sint8) != 1
- || sizeof(Sint16) != 2
- || sizeof(Sint32) != 4
- || sizeof(Sint64) != 8)
- {
- // No good.
- assert(0);
- return false;
- }
-
- // Endian checks.
- char* buf = "1234";
-
-#ifdef _TU_LITTLE_ENDIAN_
- if (*(Uint32*) buf != 0x34333231)
- {
- // No good.
- assert(0);
- return false;
- }
-#else // not _TU_LITTLE_ENDIAN_
- if (*(Uint32*) buf != 0x31323334)
- {
- // No good.
- assert(0);
- return false;
- }
-#endif // not _TU_LITTLE_ENDIAN_
-
- // Checks passed.
- return true;
-}
-
-
-// Local Variables:
-// mode: C++
-// c-basic-offset: 8
-// tab-width: 8
-// indent-tabs-mode: t
-// End:
+// tu_types.cpp -- Ignacio Castaño, Thatcher Ulrich 2003
+
+// This source code has been donated to the Public Domain. Do
+// whatever you want with it.
+
+// Minimal typedefs. Follows SDL conventions; falls back on SDL.h if
+// platform isn't obvious.
+
+
+#include "tu_types.h"
+#include "utility.h"
+
+
+bool tu_types_validate()
+{
+ // Check typedef sizes.
+ if (sizeof(Uint8) != 1
+ || sizeof(Uint16) != 2
+ || sizeof(Uint32) != 4
+ || sizeof(Uint64) != 8
+ || sizeof(Sint8) != 1
+ || sizeof(Sint16) != 2
+ || sizeof(Sint32) != 4
+ || sizeof(Sint64) != 8)
+ {
+ // No good.
+ assert(0);
+ return false;
+ }
+
+ // Endian checks.
+ char* buf = "1234";
+
+#ifdef _TU_LITTLE_ENDIAN_
+ if (*(Uint32*) buf != 0x34333231)
+ {
+ // No good.
+ assert(0);
+ return false;
+ }
+#else // not _TU_LITTLE_ENDIAN_
+ if (*(Uint32*) buf != 0x31323334)
+ {
+ // No good.
+ assert(0);
+ return false;
+ }
+#endif // not _TU_LITTLE_ENDIAN_
+
+ // Checks passed.
+ return true;
+}
+
+
+// Local Variables:
+// mode: C++
+// c-basic-offset: 8
+// tab-width: 8
+// indent-tabs-mode: t
+// End:
Index: gnash/libbase/utf8.cpp
diff -u gnash/libbase/utf8.cpp:1.1 gnash/libbase/utf8.cpp:1.2
--- gnash/libbase/utf8.cpp:1.1 Tue Dec 20 20:57:00 2005
+++ gnash/libbase/utf8.cpp Sun Feb 26 15:49:30 2006
@@ -1,365 +1,365 @@
-// utf8.cpp -- Thatcher Ulrich 2004 -*- coding: utf-8;-*-
-
-// This source code has been donated to the Public Domain. Do
-// whatever you want with it. THE AUTHOR DOES NOT WARRANT THIS CODE.
-
-// Utility code for dealing with UTF-8 encoded text.
-//
-// Much useful info at "UTF-8 and Unicode FAQ"
http://www.cl.cam.ac.uk/~mgk25/unicode.html
-
-
-#include "utf8.h"
-
-
-Uint32 utf8::decode_next_unicode_character(const char** utf8_buffer)
-{
- Uint32 uc;
- char c;
-
- // Security considerations:
- //
- // If we hit a zero byte, we want to return 0 without stepping
- // the buffer pointer past the 0.
- //
- // If we hit an "overlong sequence"; i.e. a character encoded
- // in a longer multibyte string than is necessary, then we
- // need to discard the character. This is so attackers can't
- // disguise dangerous characters or character sequences --
- // there is only one valid encoding for each character.
- //
- // If we decode characters { 0xD800 .. 0xDFFF } or { 0xFFFE,
- // 0xFFFF } then we ignore them; they are not valid in UTF-8.
-
-// This isn't actually an invalid character; it's a valid char that
-// looks like an inverted question mark.
-#define INVALID 0x0FFFD
-
-#define FIRST_BYTE(mask, shift) \
- uc = (c & (mask)) << (shift);
-
-#define NEXT_BYTE(shift) \
- c = **utf8_buffer; \
- if (c == 0) return 0; /* end of buffer, do not advance */ \
- if ((c & 0xC0) != 0x80) return INVALID; /* standard check */ \
- (*utf8_buffer)++; \
- uc |= (c & 0x3F) << shift;
-
- c = **utf8_buffer;
- if (c == 0) return 0; // End of buffer. Do not advance.
-
- (*utf8_buffer)++;
- if ((c & 0x80) == 0) return (Uint32) c; // Conventional 7-bit ASCII.
-
- // Multi-byte sequences.
- if ((c & 0xE0) == 0xC0)
- {
- // Two-byte sequence.
- FIRST_BYTE(0x1F, 6);
- NEXT_BYTE(0);
- if (uc < 0x80) return INVALID; // overlong
- return uc;
- }
- else if ((c & 0xF0) == 0xE0)
- {
- // Three-byte sequence.
- FIRST_BYTE(0x0F, 12);
- NEXT_BYTE(6);
- NEXT_BYTE(0);
- if (uc < 0x800) return INVALID; // overlong
- if (uc >= 0x0D800 && uc <= 0x0DFFF) return INVALID; // not
valid ISO 10646
- if (uc == 0x0FFFE || uc == 0x0FFFF) return INVALID; // not
valid ISO 10646
- return uc;
- }
- else if ((c & 0xF8) == 0xF0)
- {
- // Four-byte sequence.
- FIRST_BYTE(0x07, 18);
- NEXT_BYTE(12);
- NEXT_BYTE(6);
- NEXT_BYTE(0);
- if (uc < 0x010000) return INVALID; // overlong
- return uc;
- }
- else if ((c & 0xFC) == 0xF8)
- {
- // Five-byte sequence.
- FIRST_BYTE(0x03, 24);
- NEXT_BYTE(18);
- NEXT_BYTE(12);
- NEXT_BYTE(6);
- NEXT_BYTE(0);
- if (uc < 0x0200000) return INVALID; // overlong
- return uc;
- }
- else if ((c & 0xFE) == 0xFC)
- {
- // Six-byte sequence.
- FIRST_BYTE(0x01, 30);
- NEXT_BYTE(24);
- NEXT_BYTE(18);
- NEXT_BYTE(12);
- NEXT_BYTE(6);
- NEXT_BYTE(0);
- if (uc < 0x04000000) return INVALID; // overlong
- return uc;
- }
- else
- {
- // Invalid.
- return INVALID;
- }
-}
-
-
-void utf8::encode_unicode_character(char* buffer, int* index, Uint32
ucs_character)
-{
- if (ucs_character <= 0x7F)
- {
- // Plain single-byte ASCII.
- buffer[(*index)++] = (char) ucs_character;
- }
- else if (ucs_character <= 0x7FF)
- {
- // Two bytes.
- buffer[(*index)++] = 0xC0 | (ucs_character >> 6);
- buffer[(*index)++] = 0x80 | ((ucs_character >> 0) & 0x3F);
- }
- else if (ucs_character <= 0xFFFF)
- {
- // Three bytes.
- buffer[(*index)++] = 0xE0 | (ucs_character >> 12);
- buffer[(*index)++] = 0x80 | ((ucs_character >> 6) & 0x3F);
- buffer[(*index)++] = 0x80 | ((ucs_character >> 0) & 0x3F);
- }
- else if (ucs_character <= 0x1FFFFF)
- {
- // Four bytes.
- buffer[(*index)++] = 0xF0 | (ucs_character >> 18);
- buffer[(*index)++] = 0x80 | ((ucs_character >> 12) & 0x3F);
- buffer[(*index)++] = 0x80 | ((ucs_character >> 6) & 0x3F);
- buffer[(*index)++] = 0x80 | ((ucs_character >> 0) & 0x3F);
- }
- else if (ucs_character <= 0x3FFFFFF)
- {
- // Five bytes.
- buffer[(*index)++] = 0xF8 | (ucs_character >> 24);
- buffer[(*index)++] = 0x80 | ((ucs_character >> 18) & 0x3F);
- buffer[(*index)++] = 0x80 | ((ucs_character >> 12) & 0x3F);
- buffer[(*index)++] = 0x80 | ((ucs_character >> 6) & 0x3F);
- buffer[(*index)++] = 0x80 | ((ucs_character >> 0) & 0x3F);
- }
- else if (ucs_character <= 0x7FFFFFFF)
- {
- // Six bytes.
- buffer[(*index)++] = 0xFC | (ucs_character >> 30);
- buffer[(*index)++] = 0x80 | ((ucs_character >> 24) & 0x3F);
- buffer[(*index)++] = 0x80 | ((ucs_character >> 18) & 0x3F);
- buffer[(*index)++] = 0x80 | ((ucs_character >> 12) & 0x3F);
- buffer[(*index)++] = 0x80 | ((ucs_character >> 6) & 0x3F);
- buffer[(*index)++] = 0x80 | ((ucs_character >> 0) & 0x3F);
- }
- else
- {
- // Invalid char; don't encode anything.
- }
-}
-
-
-#ifdef UTF8_UNIT_TEST
-
-// Compile this test case with something like:
-//
-// gcc utf8.cpp -g -I.. -DUTF8_UNIT_TEST -lstdc++ -o utf8_test
-//
-// or
-//
-// cl utf8.cpp -Zi -Od -DUTF8_UNIT_TEST -I..
-//
-// If possible, try running the test program with the first arg
-// pointing at the file:
-//
-// http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
-//
-// and examine the results by eye to make sure they are acceptable to
-// you.
-
-
-#include "utility.h"
-#include <stdio.h>
-
-
-bool check_equal(const char* utf8_in, const Uint32* ucs_in)
-{
- for (;;)
- {
- Uint32 next_ucs = *ucs_in++;
- Uint32 next_ucs_from_utf8 =
utf8::decode_next_unicode_character(&utf8_in);
- if (next_ucs != next_ucs_from_utf8)
- {
- return false;
- }
- if (next_ucs == 0)
- {
- assert(next_ucs_from_utf8 == 0);
- break;
- }
- }
-
- return true;
-}
-
-
-void log_ascii(const char* line)
-{
- for (;;)
- {
- unsigned char c = (unsigned char) *line++;
- if (c == 0)
- {
- // End of line.
- return;
- }
- else if (c != '\n'
- && (c < 32 || c > 127))
- {
- // Non-printable as plain ASCII.
- printf("<0x%02X>", (int) c);
- }
- else
- {
- printf("%c", c);
- }
- }
-}
-
-
-void log_ucs(const Uint32* line)
-{
- for (;;)
- {
- Uint32 uc = *line++;
- if (uc == 0)
- {
- // End of line.
- return;
- }
- else if (uc != '\n'
- && (uc < 32 || uc > 127))
- {
- // Non-printable as plain ASCII.
- printf("<U-%04X>", uc);
- }
- else
- {
- printf("%c", (char) uc);
- }
- }
-}
-
-
-int main(int argc, const char* argv[])
-{
- // Simple canned test.
- {
- const char* test8 = "Ignacio Castaño";
- const Uint32 test32[] =
- {
- 0x49, 0x67, 0x6E, 0x61, 0x63,
- 0x69, 0x6F, 0x20, 0x43, 0x61,
- 0x73, 0x74, 0x61, 0xF1, 0x6F,
- 0x00
- };
-
- assert(check_equal(test8, test32));
- }
-
- // If user passed an arg, try reading the file as UTF-8 encoded text.
- if (argc > 1)
- {
- const char* filename = argv[1];
- FILE* fp = fopen(filename, "rb");
- if (fp == NULL)
- {
- printf("Can't open file '%s'\n", filename);
- return 1;
- }
-
- // Read lines from the file, encode/decode them, and highlight
discrepancies.
- const int LINE_SIZE = 200; // max line size
- char line_buffer_utf8[LINE_SIZE];
- char reencoded_utf8[6 * LINE_SIZE];
- Uint32 line_buffer_ucs[LINE_SIZE];
-
- int byte_counter = 0;
- for (;;)
- {
- int c = fgetc(fp);
- if (c == EOF)
- {
- // Done.
- break;
- }
- line_buffer_utf8[byte_counter++] = c;
- if (c == '\n' || byte_counter >= LINE_SIZE - 2)
- {
- // End of line. Process the line.
- line_buffer_utf8[byte_counter++] = 0; //
terminate.
-
- // Decode into UCS.
- const char* p = line_buffer_utf8;
- Uint32* q = line_buffer_ucs;
- for (;;)
- {
- Uint32 uc =
utf8::decode_next_unicode_character(&p);
- *q++ = uc;
-
- assert(q < line_buffer_ucs + LINE_SIZE);
- assert(p < line_buffer_utf8 +
LINE_SIZE);
-
- if (uc == 0) break;
- }
-
- // Encode back into UTF-8.
- q = line_buffer_ucs;
- int index = 0;
- for (;;)
- {
- Uint32 uc = *q++;
- assert(index < LINE_SIZE * 6 - 6);
- int last_index = index;
-
utf8::encode_unicode_character(reencoded_utf8, &index, uc);
- assert(index <= last_index + 6);
- if (uc == 0) break;
- }
-
-// This can be useful for debugging.
-#if 0
- // Show the UCS and the re-encoded UTF-8.
- log_ucs(line_buffer_ucs);
- log_ascii(reencoded_utf8);
-#endif // 0
-
- assert(check_equal(line_buffer_utf8,
line_buffer_ucs));
- assert(check_equal(reencoded_utf8,
line_buffer_ucs));
-
- // Start next line.
- byte_counter = 0;
- }
- }
-
- fclose(fp);
- }
-
- return 0;
-}
-
-
-#endif // UTF8_UNIT_TEST
-
-
-// Local Variables:
-// mode: C++
-// c-basic-offset: 8
-// tab-width: 8
-// indent-tabs-mode: t
-// End:
+// utf8.cpp -- Thatcher Ulrich 2004 -*- coding: utf-8;-*-
+
+// This source code has been donated to the Public Domain. Do
+// whatever you want with it. THE AUTHOR DOES NOT WARRANT THIS CODE.
+
+// Utility code for dealing with UTF-8 encoded text.
+//
+// Much useful info at "UTF-8 and Unicode FAQ"
http://www.cl.cam.ac.uk/~mgk25/unicode.html
+
+
+#include "utf8.h"
+
+
+Uint32 utf8::decode_next_unicode_character(const char** utf8_buffer)
+{
+ Uint32 uc;
+ char c;
+
+ // Security considerations:
+ //
+ // If we hit a zero byte, we want to return 0 without stepping
+ // the buffer pointer past the 0.
+ //
+ // If we hit an "overlong sequence"; i.e. a character encoded
+ // in a longer multibyte string than is necessary, then we
+ // need to discard the character. This is so attackers can't
+ // disguise dangerous characters or character sequences --
+ // there is only one valid encoding for each character.
+ //
+ // If we decode characters { 0xD800 .. 0xDFFF } or { 0xFFFE,
+ // 0xFFFF } then we ignore them; they are not valid in UTF-8.
+
+// This isn't actually an invalid character; it's a valid char that
+// looks like an inverted question mark.
+#define INVALID 0x0FFFD
+
+#define FIRST_BYTE(mask, shift) \
+ uc = (c & (mask)) << (shift);
+
+#define NEXT_BYTE(shift) \
+ c = **utf8_buffer; \
+ if (c == 0) return 0; /* end of buffer, do not advance */ \
+ if ((c & 0xC0) != 0x80) return INVALID; /* standard check */ \
+ (*utf8_buffer)++; \
+ uc |= (c & 0x3F) << shift;
+
+ c = **utf8_buffer;
+ if (c == 0) return 0; // End of buffer. Do not advance.
+
+ (*utf8_buffer)++;
+ if ((c & 0x80) == 0) return (Uint32) c; // Conventional 7-bit ASCII.
+
+ // Multi-byte sequences.
+ if ((c & 0xE0) == 0xC0)
+ {
+ // Two-byte sequence.
+ FIRST_BYTE(0x1F, 6);
+ NEXT_BYTE(0);
+ if (uc < 0x80) return INVALID; // overlong
+ return uc;
+ }
+ else if ((c & 0xF0) == 0xE0)
+ {
+ // Three-byte sequence.
+ FIRST_BYTE(0x0F, 12);
+ NEXT_BYTE(6);
+ NEXT_BYTE(0);
+ if (uc < 0x800) return INVALID; // overlong
+ if (uc >= 0x0D800 && uc <= 0x0DFFF) return INVALID; // not
valid ISO 10646
+ if (uc == 0x0FFFE || uc == 0x0FFFF) return INVALID; // not
valid ISO 10646
+ return uc;
+ }
+ else if ((c & 0xF8) == 0xF0)
+ {
+ // Four-byte sequence.
+ FIRST_BYTE(0x07, 18);
+ NEXT_BYTE(12);
+ NEXT_BYTE(6);
+ NEXT_BYTE(0);
+ if (uc < 0x010000) return INVALID; // overlong
+ return uc;
+ }
+ else if ((c & 0xFC) == 0xF8)
+ {
+ // Five-byte sequence.
+ FIRST_BYTE(0x03, 24);
+ NEXT_BYTE(18);
+ NEXT_BYTE(12);
+ NEXT_BYTE(6);
+ NEXT_BYTE(0);
+ if (uc < 0x0200000) return INVALID; // overlong
+ return uc;
+ }
+ else if ((c & 0xFE) == 0xFC)
+ {
+ // Six-byte sequence.
+ FIRST_BYTE(0x01, 30);
+ NEXT_BYTE(24);
+ NEXT_BYTE(18);
+ NEXT_BYTE(12);
+ NEXT_BYTE(6);
+ NEXT_BYTE(0);
+ if (uc < 0x04000000) return INVALID; // overlong
+ return uc;
+ }
+ else
+ {
+ // Invalid.
+ return INVALID;
+ }
+}
+
+
+void utf8::encode_unicode_character(char* buffer, int* index, Uint32
ucs_character)
+{
+ if (ucs_character <= 0x7F)
+ {
+ // Plain single-byte ASCII.
+ buffer[(*index)++] = (char) ucs_character;
+ }
+ else if (ucs_character <= 0x7FF)
+ {
+ // Two bytes.
+ buffer[(*index)++] = 0xC0 | (ucs_character >> 6);
+ buffer[(*index)++] = 0x80 | ((ucs_character >> 0) & 0x3F);
+ }
+ else if (ucs_character <= 0xFFFF)
+ {
+ // Three bytes.
+ buffer[(*index)++] = 0xE0 | (ucs_character >> 12);
+ buffer[(*index)++] = 0x80 | ((ucs_character >> 6) & 0x3F);
+ buffer[(*index)++] = 0x80 | ((ucs_character >> 0) & 0x3F);
+ }
+ else if (ucs_character <= 0x1FFFFF)
+ {
+ // Four bytes.
+ buffer[(*index)++] = 0xF0 | (ucs_character >> 18);
+ buffer[(*index)++] = 0x80 | ((ucs_character >> 12) & 0x3F);
+ buffer[(*index)++] = 0x80 | ((ucs_character >> 6) & 0x3F);
+ buffer[(*index)++] = 0x80 | ((ucs_character >> 0) & 0x3F);
+ }
+ else if (ucs_character <= 0x3FFFFFF)
+ {
+ // Five bytes.
+ buffer[(*index)++] = 0xF8 | (ucs_character >> 24);
+ buffer[(*index)++] = 0x80 | ((ucs_character >> 18) & 0x3F);
+ buffer[(*index)++] = 0x80 | ((ucs_character >> 12) & 0x3F);
+ buffer[(*index)++] = 0x80 | ((ucs_character >> 6) & 0x3F);
+ buffer[(*index)++] = 0x80 | ((ucs_character >> 0) & 0x3F);
+ }
+ else if (ucs_character <= 0x7FFFFFFF)
+ {
+ // Six bytes.
+ buffer[(*index)++] = 0xFC | (ucs_character >> 30);
+ buffer[(*index)++] = 0x80 | ((ucs_character >> 24) & 0x3F);
+ buffer[(*index)++] = 0x80 | ((ucs_character >> 18) & 0x3F);
+ buffer[(*index)++] = 0x80 | ((ucs_character >> 12) & 0x3F);
+ buffer[(*index)++] = 0x80 | ((ucs_character >> 6) & 0x3F);
+ buffer[(*index)++] = 0x80 | ((ucs_character >> 0) & 0x3F);
+ }
+ else
+ {
+ // Invalid char; don't encode anything.
+ }
+}
+
+
+#ifdef UTF8_UNIT_TEST
+
+// Compile this test case with something like:
+//
+// gcc utf8.cpp -g -I.. -DUTF8_UNIT_TEST -lstdc++ -o utf8_test
+//
+// or
+//
+// cl utf8.cpp -Zi -Od -DUTF8_UNIT_TEST -I..
+//
+// If possible, try running the test program with the first arg
+// pointing at the file:
+//
+// http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
+//
+// and examine the results by eye to make sure they are acceptable to
+// you.
+
+
+#include "utility.h"
+#include <stdio.h>
+
+
+bool check_equal(const char* utf8_in, const Uint32* ucs_in)
+{
+ for (;;)
+ {
+ Uint32 next_ucs = *ucs_in++;
+ Uint32 next_ucs_from_utf8 =
utf8::decode_next_unicode_character(&utf8_in);
+ if (next_ucs != next_ucs_from_utf8)
+ {
+ return false;
+ }
+ if (next_ucs == 0)
+ {
+ assert(next_ucs_from_utf8 == 0);
+ break;
+ }
+ }
+
+ return true;
+}
+
+
+void log_ascii(const char* line)
+{
+ for (;;)
+ {
+ unsigned char c = (unsigned char) *line++;
+ if (c == 0)
+ {
+ // End of line.
+ return;
+ }
+ else if (c != '\n'
+ && (c < 32 || c > 127))
+ {
+ // Non-printable as plain ASCII.
+ printf("<0x%02X>", (int) c);
+ }
+ else
+ {
+ printf("%c", c);
+ }
+ }
+}
+
+
+void log_ucs(const Uint32* line)
+{
+ for (;;)
+ {
+ Uint32 uc = *line++;
+ if (uc == 0)
+ {
+ // End of line.
+ return;
+ }
+ else if (uc != '\n'
+ && (uc < 32 || uc > 127))
+ {
+ // Non-printable as plain ASCII.
+ printf("<U-%04X>", uc);
+ }
+ else
+ {
+ printf("%c", (char) uc);
+ }
+ }
+}
+
+
+int main(int argc, const char* argv[])
+{
+ // Simple canned test.
+ {
+ const char* test8 = "Ignacio Castaño";
+ const Uint32 test32[] =
+ {
+ 0x49, 0x67, 0x6E, 0x61, 0x63,
+ 0x69, 0x6F, 0x20, 0x43, 0x61,
+ 0x73, 0x74, 0x61, 0xF1, 0x6F,
+ 0x00
+ };
+
+ assert(check_equal(test8, test32));
+ }
+
+ // If user passed an arg, try reading the file as UTF-8 encoded text.
+ if (argc > 1)
+ {
+ const char* filename = argv[1];
+ FILE* fp = fopen(filename, "rb");
+ if (fp == NULL)
+ {
+ printf("Can't open file '%s'\n", filename);
+ return 1;
+ }
+
+ // Read lines from the file, encode/decode them, and highlight
discrepancies.
+ const int LINE_SIZE = 200; // max line size
+ char line_buffer_utf8[LINE_SIZE];
+ char reencoded_utf8[6 * LINE_SIZE];
+ Uint32 line_buffer_ucs[LINE_SIZE];
+
+ int byte_counter = 0;
+ for (;;)
+ {
+ int c = fgetc(fp);
+ if (c == EOF)
+ {
+ // Done.
+ break;
+ }
+ line_buffer_utf8[byte_counter++] = c;
+ if (c == '\n' || byte_counter >= LINE_SIZE - 2)
+ {
+ // End of line. Process the line.
+ line_buffer_utf8[byte_counter++] = 0; //
terminate.
+
+ // Decode into UCS.
+ const char* p = line_buffer_utf8;
+ Uint32* q = line_buffer_ucs;
+ for (;;)
+ {
+ Uint32 uc =
utf8::decode_next_unicode_character(&p);
+ *q++ = uc;
+
+ assert(q < line_buffer_ucs + LINE_SIZE);
+ assert(p < line_buffer_utf8 +
LINE_SIZE);
+
+ if (uc == 0) break;
+ }
+
+ // Encode back into UTF-8.
+ q = line_buffer_ucs;
+ int index = 0;
+ for (;;)
+ {
+ Uint32 uc = *q++;
+ assert(index < LINE_SIZE * 6 - 6);
+ int last_index = index;
+
utf8::encode_unicode_character(reencoded_utf8, &index, uc);
+ assert(index <= last_index + 6);
+ if (uc == 0) break;
+ }
+
+// This can be useful for debugging.
+#if 0
+ // Show the UCS and the re-encoded UTF-8.
+ log_ucs(line_buffer_ucs);
+ log_ascii(reencoded_utf8);
+#endif // 0
+
+ assert(check_equal(line_buffer_utf8,
line_buffer_ucs));
+ assert(check_equal(reencoded_utf8,
line_buffer_ucs));
+
+ // Start next line.
+ byte_counter = 0;
+ }
+ }
+
+ fclose(fp);
+ }
+
+ return 0;
+}
+
+
+#endif // UTF8_UNIT_TEST
+
+
+// Local Variables:
+// mode: C++
+// c-basic-offset: 8
+// tab-width: 8
+// indent-tabs-mode: t
+// End:
Index: gnash/libbase/utility.cpp
diff -u gnash/libbase/utility.cpp:1.2 gnash/libbase/utility.cpp:1.3
--- gnash/libbase/utility.cpp:1.2 Mon Jan 23 20:37:19 2006
+++ gnash/libbase/utility.cpp Sun Feb 26 15:49:30 2006
@@ -1,95 +1,95 @@
-// Copyright (C) 2005, 2006 Free Software Foundation, Inc.
-//
-// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-//
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "utility.h"
-#include "dlmalloc.h"
-
-#ifdef HAVE_DMALLOC
-
-// Overrides of new/delete that use Doug Lea's malloc. Very helpful
-// on certain lame platforms.
-
-void* operator new(size_t size)
-{
- return dlmalloc(size);
-}
-
-void operator delete(void* ptr)
-{
- if (ptr) dlfree(ptr);
-}
-
-void* operator new[](size_t size)
-{
- return dlmalloc(size);
-}
-
-void operator delete[](void* ptr)
-{
- if (ptr) dlfree(ptr);
-}
-// end of HAVE_DMALLOC
-#endif
-
-
-void dump_memory_stats(const char *from, int line, const char *label)
-// Dump the internal statistics from malloc() so we can track memory leaks
-{
-
-
-// This does not work with DMALLOC, since the internal data structures
-// differ.
-#ifdef HAVE_MALLINFO
-
- struct mallinfo mi;
- static int allocated = 0;
- static int freeb = 0;
-
- mi = mallinfo();
- if (label != 0) {
- printf("Malloc Statistics from %s() (line #%d): %s\n", from,
line, label);
- } else {
- printf("Malloc Statistics from %s() (line #%d):\n", from, line);
- }
-
- //printf("\tnon-mapped space from system: %d\n", mi.arena);
- printf("\ttotal allocated space: %d\n", mi.uordblks);
- printf("\ttotal free space: %d\n", mi.fordblks);
- //printf("\tspace in mmapped regions: %d\n", mi.hblkhd);
- //printf("\ttop-most, releasable space: %d\n", mi.keepcost); //
Prints 78824
- if (freeb != mi.fordblks) {
- printf("\t%d bytes difference in free space.\n", freeb -
mi.fordblks);
- freeb = mi.fordblks;
- }
-
- //if (allocated != mi.uordblks) {
- // printf("\t%d bytes difference in allocated space.\n", mi.uordblks -
allocated);
- // allocated = mi.uordblks;
- //}
-
-// HAVE_MALLINFO
-#endif
-}
-
-// Local Variables:
-// mode: C++
-// indent-tabs-mode: t
-// End:
+// Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+//
+// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+//
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "utility.h"
+#include "dlmalloc.h"
+
+#ifdef HAVE_DMALLOC
+
+// Overrides of new/delete that use Doug Lea's malloc. Very helpful
+// on certain lame platforms.
+
+void* operator new(size_t size)
+{
+ return dlmalloc(size);
+}
+
+void operator delete(void* ptr)
+{
+ if (ptr) dlfree(ptr);
+}
+
+void* operator new[](size_t size)
+{
+ return dlmalloc(size);
+}
+
+void operator delete[](void* ptr)
+{
+ if (ptr) dlfree(ptr);
+}
+// end of HAVE_DMALLOC
+#endif
+
+
+void dump_memory_stats(const char *from, int line, const char *label)
+// Dump the internal statistics from malloc() so we can track memory leaks
+{
+
+
+// This does not work with DMALLOC, since the internal data structures
+// differ.
+#ifdef HAVE_MALLINFO
+
+ struct mallinfo mi;
+ static int allocated = 0;
+ static int freeb = 0;
+
+ mi = mallinfo();
+ if (label != 0) {
+ printf("Malloc Statistics from %s() (line #%d): %s\n", from,
line, label);
+ } else {
+ printf("Malloc Statistics from %s() (line #%d):\n", from, line);
+ }
+
+ //printf("\tnon-mapped space from system: %d\n", mi.arena);
+ printf("\ttotal allocated space: %d\n", mi.uordblks);
+ printf("\ttotal free space: %d\n", mi.fordblks);
+ //printf("\tspace in mmapped regions: %d\n", mi.hblkhd);
+ //printf("\ttop-most, releasable space: %d\n", mi.keepcost); //
Prints 78824
+ if (freeb != mi.fordblks) {
+ printf("\t%d bytes difference in free space.\n", freeb -
mi.fordblks);
+ freeb = mi.fordblks;
+ }
+
+ //if (allocated != mi.uordblks) {
+ // printf("\t%d bytes difference in allocated space.\n", mi.uordblks -
allocated);
+ // allocated = mi.uordblks;
+ //}
+
+// HAVE_MALLINFO
+#endif
+}
+
+// Local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:
Index: gnash/libbase/utility.h
diff -u gnash/libbase/utility.h:1.1 gnash/libbase/utility.h:1.2
--- gnash/libbase/utility.h:1.1 Tue Dec 20 20:57:00 2005
+++ gnash/libbase/utility.h Sun Feb 26 15:49:30 2006
@@ -1,180 +1,180 @@
-// utility.h -- by Thatcher Ulrich <address@hidden>
-
-// This source code has been donated to the Public Domain. Do
-// whatever you want with it.
-
-// Various little utility functions, macros & typedefs.
-
-
-#ifndef UTILITY_H
-#define UTILITY_H
-
-#include "tu_config.h"
-#include <assert.h>
-#include "tu_math.h"
-#include "tu_types.h"
-#include "tu_swap.h"
-#include <ctype.h>
-
-
-#ifdef _WIN32
-#ifndef NDEBUG
-
-// On windows, replace ANSI assert with our own, for a less annoying
-// debugging experience.
-//int tu_testbed_assert_break(const char* filename, int linenum, const char*
expression);
-#undef assert
-#define assert(x) if (!(x)) { __asm { int 3 } } //
tu_testbed_assert_break(__FILE__, __LINE__, #x))
-
-#endif // not NDEBUG
-#endif // _WIN32
-
-
-// Compile-time assert. Thanks to Jon Jagger
-// (http://www.jaggersoft.com) for this trick.
-#define compiler_assert(x) switch(0){case 0: case x:;}
-
-
-//
-// new/delete wackiness -- if USE_DL_MALLOC is defined, we're going to
-// try to use Doug Lea's malloc as much as possible by overriding the
-// default operator new/delete.
-//
-#ifdef USE_DL_MALLOC
-
-void* operator new(size_t size);
-void operator delete(void* ptr);
-void* operator new[](size_t size);
-void operator delete[](void* ptr);
-
-#else // not USE_DL_MALLOC
-
-// If we're not using DL_MALLOC, then *really* don't use it: #define
-// away dlmalloc(), dlfree(), etc, back to the platform defaults.
-#define dlmalloc malloc
-#define dlfree free
-#define dlrealloc realloc
-#define dlcalloc calloc
-#define dlmemalign memalign
-#define dlvalloc valloc
-#define dlpvalloc pvalloc
-#define dlmalloc_trim malloc_trim
-#define dlmalloc_stats malloc_stats
-
-#endif // not USE_DL_MALLOC
-
-
-#ifndef M_PI
-#define M_PI 3.141592654
-#endif // M_PI
-
-
-//
-// some misc handy math functions
-//
-
-inline int iabs(int i) { if (i < 0) return -i; else return i; }
-inline int imax(int a, int b) { if (a < b) return b; else return a; }
-inline float fmax(float a, float b) { if (a < b) return b; else return a; }
-inline int imin(int a, int b) { if (a < b) return a; else return b; }
-inline float fmin(float a, float b) { if (a < b) return a; else return b; }
-
-
-inline int iclamp(int i, int min, int max) {
- assert( min <= max );
- return imax(min, imin(i, max));
-}
-
-inline float fclamp(float f, float xmin, float xmax) {
- assert( xmin <= xmax );
- return fmax(xmin, fmin(f, xmax));
-}
-
-inline float flerp(float a, float b, float f) { return (b - a) * f + a; }
-
-const float LN_2 = 0.693147180559945f;
-inline float log2(float f) { return logf(f) / LN_2; }
-
-inline int fchop( float f ) { return (int) f; } // replace w/ inline
asm if desired
-inline int frnd(float f) { return fchop(f + 0.5f); } // replace with
inline asm if desired
-
-
-// Handy macro to quiet compiler warnings about unused parameters/variables.
-#define UNUSED(x) (x) = (x)
-
-
-// Compile-time constant size of array.
-#define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
-
-
-inline size_t bernstein_hash(const void* data_in, int size, unsigned int seed
= 5381)
-// Computes a hash of the given data buffer.
-// Hash function suggested by http://www.cs.yorku.ca/~oz/hash.html
-// Due to Dan Bernstein. Allegedly very good on strings.
-//
-// One problem with this hash function is that e.g. if you take a
-// bunch of 32-bit ints and hash them, their hash values will be
-// concentrated toward zero, instead of randomly distributed in
-// [0,2^32-1], because of shifting up only 5 bits per byte.
-{
- const unsigned char* data = (const unsigned char*) data_in;
- unsigned int h = seed;
- while (size > 0) {
- size--;
- h = ((h << 5) + h) ^ (unsigned) data[size];
- }
-
- return h;
-}
-
-
-inline size_t sdbm_hash(const void* data_in, int size, unsigned int seed =
5381)
-// Alternative: "sdbm" hash function, suggested at same web page
-// above, http::/www.cs.yorku.ca/~oz/hash.html
-//
-// This is somewhat slower, but it works way better than the above
-// hash function for hashing large numbers of 32-bit ints.
-{
- const unsigned char* data = (const unsigned char*) data_in;
- unsigned int h = seed;
- while (size > 0) {
- size--;
- h = (h << 16) + (h << 6) - h + (unsigned) data[size];
- }
-
- return h;
-}
-
-
-inline size_t bernstein_hash_case_insensitive(const void* data_in, int size,
unsigned int seed = 5381)
-// Computes a hash of the given data buffer; does tolower() on each
-// byte. Hash function suggested by
-// http://www.cs.yorku.ca/~oz/hash.html Due to Dan Bernstein.
-// Allegedly very good on strings.
-{
- const unsigned char* data = (const unsigned char*) data_in;
- unsigned int h = seed;
- while (size > 0) {
- size--;
- h = ((h << 5) + h) ^ (unsigned) tolower(data[size]);
- }
-
- // Alternative: "sdbm" hash function, suggested at same web page above.
- // h = 0;
- // for bytes { h = (h << 16) + (h << 6) - hash + *p; }
-
- return h;
-}
-
-// Dump the internal statistics from malloc() so we can track memory leaks
-void dump_memory_stats(const char *from, int line, const char *label);
-
-#endif // UTILITY_H
-
-
-// Local Variables:
-// mode: C++
-// c-basic-offset: 8
-// tab-width: 8
-// indent-tabs-mode: t
-// End:
+// utility.h -- by Thatcher Ulrich <address@hidden>
+
+// This source code has been donated to the Public Domain. Do
+// whatever you want with it.
+
+// Various little utility functions, macros & typedefs.
+
+
+#ifndef UTILITY_H
+#define UTILITY_H
+
+#include "tu_config.h"
+#include <assert.h>
+#include "tu_math.h"
+#include "tu_types.h"
+#include "tu_swap.h"
+#include <ctype.h>
+
+
+#ifdef _WIN32
+#ifndef NDEBUG
+
+// On windows, replace ANSI assert with our own, for a less annoying
+// debugging experience.
+//int tu_testbed_assert_break(const char* filename, int linenum, const char*
expression);
+#undef assert
+#define assert(x) if (!(x)) { __asm { int 3 } } //
tu_testbed_assert_break(__FILE__, __LINE__, #x))
+
+#endif // not NDEBUG
+#endif // _WIN32
+
+
+// Compile-time assert. Thanks to Jon Jagger
+// (http://www.jaggersoft.com) for this trick.
+#define compiler_assert(x) switch(0){case 0: case x:;}
+
+
+//
+// new/delete wackiness -- if USE_DL_MALLOC is defined, we're going to
+// try to use Doug Lea's malloc as much as possible by overriding the
+// default operator new/delete.
+//
+#ifdef USE_DL_MALLOC
+
+void* operator new(size_t size);
+void operator delete(void* ptr);
+void* operator new[](size_t size);
+void operator delete[](void* ptr);
+
+#else // not USE_DL_MALLOC
+
+// If we're not using DL_MALLOC, then *really* don't use it: #define
+// away dlmalloc(), dlfree(), etc, back to the platform defaults.
+#define dlmalloc malloc
+#define dlfree free
+#define dlrealloc realloc
+#define dlcalloc calloc
+#define dlmemalign memalign
+#define dlvalloc valloc
+#define dlpvalloc pvalloc
+#define dlmalloc_trim malloc_trim
+#define dlmalloc_stats malloc_stats
+
+#endif // not USE_DL_MALLOC
+
+
+#ifndef M_PI
+#define M_PI 3.141592654
+#endif // M_PI
+
+
+//
+// some misc handy math functions
+//
+
+inline int iabs(int i) { if (i < 0) return -i; else return i; }
+inline int imax(int a, int b) { if (a < b) return b; else return a; }
+inline float fmax(float a, float b) { if (a < b) return b; else return a; }
+inline int imin(int a, int b) { if (a < b) return a; else return b; }
+inline float fmin(float a, float b) { if (a < b) return a; else return b; }
+
+
+inline int iclamp(int i, int min, int max) {
+ assert( min <= max );
+ return imax(min, imin(i, max));
+}
+
+inline float fclamp(float f, float xmin, float xmax) {
+ assert( xmin <= xmax );
+ return fmax(xmin, fmin(f, xmax));
+}
+
+inline float flerp(float a, float b, float f) { return (b - a) * f + a; }
+
+const float LN_2 = 0.693147180559945f;
+inline float log2(float f) { return logf(f) / LN_2; }
+
+inline int fchop( float f ) { return (int) f; } // replace w/ inline
asm if desired
+inline int frnd(float f) { return fchop(f + 0.5f); } // replace with
inline asm if desired
+
+
+// Handy macro to quiet compiler warnings about unused parameters/variables.
+#define UNUSED(x) (x) = (x)
+
+
+// Compile-time constant size of array.
+#define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
+
+
+inline size_t bernstein_hash(const void* data_in, int size, unsigned int seed
= 5381)
+// Computes a hash of the given data buffer.
+// Hash function suggested by http://www.cs.yorku.ca/~oz/hash.html
+// Due to Dan Bernstein. Allegedly very good on strings.
+//
+// One problem with this hash function is that e.g. if you take a
+// bunch of 32-bit ints and hash them, their hash values will be
+// concentrated toward zero, instead of randomly distributed in
+// [0,2^32-1], because of shifting up only 5 bits per byte.
+{
+ const unsigned char* data = (const unsigned char*) data_in;
+ unsigned int h = seed;
+ while (size > 0) {
+ size--;
+ h = ((h << 5) + h) ^ (unsigned) data[size];
+ }
+
+ return h;
+}
+
+
+inline size_t sdbm_hash(const void* data_in, int size, unsigned int seed =
5381)
+// Alternative: "sdbm" hash function, suggested at same web page
+// above, http::/www.cs.yorku.ca/~oz/hash.html
+//
+// This is somewhat slower, but it works way better than the above
+// hash function for hashing large numbers of 32-bit ints.
+{
+ const unsigned char* data = (const unsigned char*) data_in;
+ unsigned int h = seed;
+ while (size > 0) {
+ size--;
+ h = (h << 16) + (h << 6) - h + (unsigned) data[size];
+ }
+
+ return h;
+}
+
+
+inline size_t bernstein_hash_case_insensitive(const void* data_in, int size,
unsigned int seed = 5381)
+// Computes a hash of the given data buffer; does tolower() on each
+// byte. Hash function suggested by
+// http://www.cs.yorku.ca/~oz/hash.html Due to Dan Bernstein.
+// Allegedly very good on strings.
+{
+ const unsigned char* data = (const unsigned char*) data_in;
+ unsigned int h = seed;
+ while (size > 0) {
+ size--;
+ h = ((h << 5) + h) ^ (unsigned) tolower(data[size]);
+ }
+
+ // Alternative: "sdbm" hash function, suggested at same web page above.
+ // h = 0;
+ // for bytes { h = (h << 16) + (h << 6) - hash + *p; }
+
+ return h;
+}
+
+// Dump the internal statistics from malloc() so we can track memory leaks
+void dump_memory_stats(const char *from, int line, const char *label);
+
+#endif // UTILITY_H
+
+
+// Local Variables:
+// mode: C++
+// c-basic-offset: 8
+// tab-width: 8
+// indent-tabs-mode: t
+// End:
Index: gnash/libbase/zlib_adapter.cpp
diff -u gnash/libbase/zlib_adapter.cpp:1.1 gnash/libbase/zlib_adapter.cpp:1.2
--- gnash/libbase/zlib_adapter.cpp:1.1 Tue Dec 20 20:57:00 2005
+++ gnash/libbase/zlib_adapter.cpp Sun Feb 26 15:49:30 2006
@@ -1,326 +1,326 @@
-// zlib_adapter.cpp -- Thatcher Ulrich 2003
-
-// This source code has been donated to the Public Domain. Do
-// whatever you want with it.
-
-// Code to wrap zlib compression/decompression around a tu_file
-// stream.
-
-
-#include "zlib_adapter.h"
-#include "tu_file.h"
-#include "utility.h"
-
-
-#if !TU_CONFIG_LINK_TO_ZLIB
-
-
-// Stubs, in case client doesn't want to link to zlib.
-namespace zlib_adapter
-{
- tu_file* make_inflater(tu_file* in) { return NULL; }
- tu_file* make_deflater(tu_file* out) { return NULL; }
-}
-
-
-#else // TU_CONFIG_LINK_TO_ZLIB
-
-
-#include <zlib.h>
-
-
-namespace zlib_adapter
-{
- const int ZBUF_SIZE = 4096;
-
- struct inflater_impl
- {
- tu_file* m_in;
- z_stream m_zstream;
- int m_initial_stream_pos; // position of the input stream
where we started inflating.
- int m_logical_stream_pos; // current stream position of
uncompressed data.
- bool m_at_eof;
-
- unsigned char m_rawdata[ZBUF_SIZE];
-
- int m_error;
-
-
- inflater_impl(tu_file* in)
- // Constructor.
- :
- m_in(in),
- m_initial_stream_pos(in->get_position()),
- m_logical_stream_pos(0),
- m_at_eof(false),
- m_error(0)
- {
- assert(m_in);
-
- m_zstream.zalloc = (alloc_func)0;
- m_zstream.zfree = (free_func)0;
- m_zstream.opaque = (voidpf)0;
-
- m_zstream.next_in = 0;
- m_zstream.avail_in = 0;
-
- m_zstream.next_out = 0;
- m_zstream.avail_out = 0;
-
- int err = inflateInit(&m_zstream);
- if (err != Z_OK) {
- //log_error("error: inflater_impl::ctor()
inflateInit() returned %d\n", err);
- m_error = 1;
- return;
- }
-
- // Ready to go!
- }
-
-
- void reset()
- // Discard current results and rewind to the beginning.
- // Necessary in order to seek backwards.
- {
- m_error = 0;
- m_at_eof = 0;
- int err = inflateReset(&m_zstream);
- if (err != Z_OK) {
- m_error = 1;
- return;
- }
-
- m_zstream.next_in = 0;
- m_zstream.avail_in = 0;
-
- m_zstream.next_out = 0;
- m_zstream.avail_out = 0;
-
- // Rewind the underlying stream.
- m_in->set_position(m_initial_stream_pos);
-
- m_logical_stream_pos = 0;
- }
-
-
- int inflate_from_stream(void* dst, int bytes)
- {
- if (m_error)
- {
- return 0;
- }
-
- m_zstream.next_out = (unsigned char*) dst;
- m_zstream.avail_out = bytes;
-
- for (;;)
- {
- if (m_zstream.avail_in == 0)
- {
- // Get more raw data.
- int new_bytes =
m_in->read_bytes(m_rawdata, ZBUF_SIZE);
- if (new_bytes == 0)
- {
- // The cupboard is bare! We
have nothing to feed to inflate().
- break;
- }
- else
- {
- m_zstream.next_in = m_rawdata;
- m_zstream.avail_in = new_bytes;
- }
- }
-
- int err = inflate(&m_zstream, Z_SYNC_FLUSH);
- if (err == Z_STREAM_END)
- {
- m_at_eof = true;
- break;
- }
- if (err != Z_OK)
- {
- // something's wrong.
- m_error = 1;
- break;
- }
-
- if (m_zstream.avail_out == 0)
- {
- break;
- }
- }
-
- int bytes_read = bytes - m_zstream.avail_out;
- m_logical_stream_pos += bytes_read;
-
- return bytes_read;
- }
-
- void rewind_unused_bytes()
- // If we have unused bytes in our input buffer, rewind
- // to before they started.
- {
- if (m_zstream.avail_in > 0)
- {
- int pos = m_in->get_position();
- int rewound_pos = pos - m_zstream.avail_in;
- assert(pos >= 0);
- assert(pos >= m_initial_stream_pos);
- assert(rewound_pos >= 0);
- assert(rewound_pos >= m_initial_stream_pos);
-
- m_in->set_position(rewound_pos);
- }
- }
- };
-
-
- int inflate_read(void* dst, int bytes, void* appdata)
- // Return number of bytes actually read.
- {
- inflater_impl* inf = (inflater_impl*) appdata;
- if (inf->m_error)
- {
- return 0;
- }
-
- return inf->inflate_from_stream(dst, bytes);
- }
-
-
- int inflate_write(const void* src, int bytes, void* appdata)
- // Return number of bytes actually written.
- {
- // *In*flaters can't write!!!
- assert(0);
- return 0;
- }
-
-
- int inflate_seek(int pos, void* appdata)
- // Try to go to pos. Return actual pos.
- {
- inflater_impl* inf = (inflater_impl*) appdata;
- if (inf->m_error)
- {
- return inf->m_logical_stream_pos;
- }
-
- // If we're seeking backwards, then restart from the beginning.
- if (pos < inf->m_logical_stream_pos)
- {
- inf->reset();
- }
-
- unsigned char temp[ZBUF_SIZE];
-
- // Now seek forwards, by just reading data in blocks.
- while (inf->m_logical_stream_pos < pos)
- {
- int to_read = pos - inf->m_logical_stream_pos;
- int to_read_this_time = imin(to_read, ZBUF_SIZE);
- assert(to_read_this_time > 0);
-
- int bytes_read = inf->inflate_from_stream(temp,
to_read_this_time);
- assert(bytes_read <= to_read_this_time);
- if (bytes_read == 0)
- {
- // Trouble; can't seek any further.
- break;
- }
- }
-
- assert(inf->m_logical_stream_pos <= pos);
-
- return inf->m_logical_stream_pos;
- }
-
-
- int inflate_seek_to_end(void* appdata)
- {
- inflater_impl* inf = (inflater_impl*) appdata;
- if (inf->m_error)
- {
- return inf->m_logical_stream_pos;
- }
-
- // Keep reading until we can't read any more.
-
- unsigned char temp[ZBUF_SIZE];
-
- // Seek forwards.
- for (;;)
- {
- int bytes_read = inf->inflate_from_stream(temp,
ZBUF_SIZE);
- if (bytes_read == 0)
- {
- // We've seeked as far as we can.
- break;
- }
- }
-
- return inf->m_logical_stream_pos;
- }
-
- int inflate_tell(const void* appdata)
- {
- inflater_impl* inf = (inflater_impl*) appdata;
-
- return inf->m_logical_stream_pos;
- }
-
- bool inflate_get_eof(void* appdata)
- {
- inflater_impl* inf = (inflater_impl*) appdata;
-
- return inf->m_at_eof;
- }
-
- int inflate_close(void* appdata)
- {
- inflater_impl* inf = (inflater_impl*) appdata;
-
- inf->rewind_unused_bytes();
- int err = inflateEnd(&(inf->m_zstream));
-
- delete inf;
-
- if (err != Z_OK)
- {
- return TU_FILE_CLOSE_ERROR;
- }
-
- return 0;
- }
-
-
- tu_file* make_inflater(tu_file* in)
- {
- assert(in);
-
- inflater_impl* inflater = new inflater_impl(in);
- return new tu_file(
- inflater,
- inflate_read,
- inflate_write,
- inflate_seek,
- inflate_seek_to_end,
- inflate_tell,
- inflate_get_eof,
- inflate_close);
- }
-
-
- // @@ TODO
- // tu_file* make_deflater(tu_file* out) { ... }
-}
-
-#endif // TU_CONFIG_LINK_TO_ZLIB
-
-
-// Local Variables:
-// mode: C++
-// c-basic-offset: 8
-// tab-width: 8
-// indent-tabs-mode: t
-// End:
+// zlib_adapter.cpp -- Thatcher Ulrich 2003
+
+// This source code has been donated to the Public Domain. Do
+// whatever you want with it.
+
+// Code to wrap zlib compression/decompression around a tu_file
+// stream.
+
+
+#include "zlib_adapter.h"
+#include "tu_file.h"
+#include "utility.h"
+
+
+#if !TU_CONFIG_LINK_TO_ZLIB
+
+
+// Stubs, in case client doesn't want to link to zlib.
+namespace zlib_adapter
+{
+ tu_file* make_inflater(tu_file* in) { return NULL; }
+ tu_file* make_deflater(tu_file* out) { return NULL; }
+}
+
+
+#else // TU_CONFIG_LINK_TO_ZLIB
+
+
+#include <zlib.h>
+
+
+namespace zlib_adapter
+{
+ const int ZBUF_SIZE = 4096;
+
+ struct inflater_impl
+ {
+ tu_file* m_in;
+ z_stream m_zstream;
+ int m_initial_stream_pos; // position of the input stream
where we started inflating.
+ int m_logical_stream_pos; // current stream position of
uncompressed data.
+ bool m_at_eof;
+
+ unsigned char m_rawdata[ZBUF_SIZE];
+
+ int m_error;
+
+
+ inflater_impl(tu_file* in)
+ // Constructor.
+ :
+ m_in(in),
+ m_initial_stream_pos(in->get_position()),
+ m_logical_stream_pos(0),
+ m_at_eof(false),
+ m_error(0)
+ {
+ assert(m_in);
+
+ m_zstream.zalloc = (alloc_func)0;
+ m_zstream.zfree = (free_func)0;
+ m_zstream.opaque = (voidpf)0;
+
+ m_zstream.next_in = 0;
+ m_zstream.avail_in = 0;
+
+ m_zstream.next_out = 0;
+ m_zstream.avail_out = 0;
+
+ int err = inflateInit(&m_zstream);
+ if (err != Z_OK) {
+ //log_error("error: inflater_impl::ctor()
inflateInit() returned %d\n", err);
+ m_error = 1;
+ return;
+ }
+
+ // Ready to go!
+ }
+
+
+ void reset()
+ // Discard current results and rewind to the beginning.
+ // Necessary in order to seek backwards.
+ {
+ m_error = 0;
+ m_at_eof = 0;
+ int err = inflateReset(&m_zstream);
+ if (err != Z_OK) {
+ m_error = 1;
+ return;
+ }
+
+ m_zstream.next_in = 0;
+ m_zstream.avail_in = 0;
+
+ m_zstream.next_out = 0;
+ m_zstream.avail_out = 0;
+
+ // Rewind the underlying stream.
+ m_in->set_position(m_initial_stream_pos);
+
+ m_logical_stream_pos = 0;
+ }
+
+
+ int inflate_from_stream(void* dst, int bytes)
+ {
+ if (m_error)
+ {
+ return 0;
+ }
+
+ m_zstream.next_out = (unsigned char*) dst;
+ m_zstream.avail_out = bytes;
+
+ for (;;)
+ {
+ if (m_zstream.avail_in == 0)
+ {
+ // Get more raw data.
+ int new_bytes =
m_in->read_bytes(m_rawdata, ZBUF_SIZE);
+ if (new_bytes == 0)
+ {
+ // The cupboard is bare! We
have nothing to feed to inflate().
+ break;
+ }
+ else
+ {
+ m_zstream.next_in = m_rawdata;
+ m_zstream.avail_in = new_bytes;
+ }
+ }
+
+ int err = inflate(&m_zstream, Z_SYNC_FLUSH);
+ if (err == Z_STREAM_END)
+ {
+ m_at_eof = true;
+ break;
+ }
+ if (err != Z_OK)
+ {
+ // something's wrong.
+ m_error = 1;
+ break;
+ }
+
+ if (m_zstream.avail_out == 0)
+ {
+ break;
+ }
+ }
+
+ int bytes_read = bytes - m_zstream.avail_out;
+ m_logical_stream_pos += bytes_read;
+
+ return bytes_read;
+ }
+
+ void rewind_unused_bytes()
+ // If we have unused bytes in our input buffer, rewind
+ // to before they started.
+ {
+ if (m_zstream.avail_in > 0)
+ {
+ int pos = m_in->get_position();
+ int rewound_pos = pos - m_zstream.avail_in;
+ assert(pos >= 0);
+ assert(pos >= m_initial_stream_pos);
+ assert(rewound_pos >= 0);
+ assert(rewound_pos >= m_initial_stream_pos);
+
+ m_in->set_position(rewound_pos);
+ }
+ }
+ };
+
+
+ int inflate_read(void* dst, int bytes, void* appdata)
+ // Return number of bytes actually read.
+ {
+ inflater_impl* inf = (inflater_impl*) appdata;
+ if (inf->m_error)
+ {
+ return 0;
+ }
+
+ return inf->inflate_from_stream(dst, bytes);
+ }
+
+
+ int inflate_write(const void* src, int bytes, void* appdata)
+ // Return number of bytes actually written.
+ {
+ // *In*flaters can't write!!!
+ assert(0);
+ return 0;
+ }
+
+
+ int inflate_seek(int pos, void* appdata)
+ // Try to go to pos. Return actual pos.
+ {
+ inflater_impl* inf = (inflater_impl*) appdata;
+ if (inf->m_error)
+ {
+ return inf->m_logical_stream_pos;
+ }
+
+ // If we're seeking backwards, then restart from the beginning.
+ if (pos < inf->m_logical_stream_pos)
+ {
+ inf->reset();
+ }
+
+ unsigned char temp[ZBUF_SIZE];
+
+ // Now seek forwards, by just reading data in blocks.
+ while (inf->m_logical_stream_pos < pos)
+ {
+ int to_read = pos - inf->m_logical_stream_pos;
+ int to_read_this_time = imin(to_read, ZBUF_SIZE);
+ assert(to_read_this_time > 0);
+
+ int bytes_read = inf->inflate_from_stream(temp,
to_read_this_time);
+ assert(bytes_read <= to_read_this_time);
+ if (bytes_read == 0)
+ {
+ // Trouble; can't seek any further.
+ break;
+ }
+ }
+
+ assert(inf->m_logical_stream_pos <= pos);
+
+ return inf->m_logical_stream_pos;
+ }
+
+
+ int inflate_seek_to_end(void* appdata)
+ {
+ inflater_impl* inf = (inflater_impl*) appdata;
+ if (inf->m_error)
+ {
+ return inf->m_logical_stream_pos;
+ }
+
+ // Keep reading until we can't read any more.
+
+ unsigned char temp[ZBUF_SIZE];
+
+ // Seek forwards.
+ for (;;)
+ {
+ int bytes_read = inf->inflate_from_stream(temp,
ZBUF_SIZE);
+ if (bytes_read == 0)
+ {
+ // We've seeked as far as we can.
+ break;
+ }
+ }
+
+ return inf->m_logical_stream_pos;
+ }
+
+ int inflate_tell(const void* appdata)
+ {
+ inflater_impl* inf = (inflater_impl*) appdata;
+
+ return inf->m_logical_stream_pos;
+ }
+
+ bool inflate_get_eof(void* appdata)
+ {
+ inflater_impl* inf = (inflater_impl*) appdata;
+
+ return inf->m_at_eof;
+ }
+
+ int inflate_close(void* appdata)
+ {
+ inflater_impl* inf = (inflater_impl*) appdata;
+
+ inf->rewind_unused_bytes();
+ int err = inflateEnd(&(inf->m_zstream));
+
+ delete inf;
+
+ if (err != Z_OK)
+ {
+ return TU_FILE_CLOSE_ERROR;
+ }
+
+ return 0;
+ }
+
+
+ tu_file* make_inflater(tu_file* in)
+ {
+ assert(in);
+
+ inflater_impl* inflater = new inflater_impl(in);
+ return new tu_file(
+ inflater,
+ inflate_read,
+ inflate_write,
+ inflate_seek,
+ inflate_seek_to_end,
+ inflate_tell,
+ inflate_get_eof,
+ inflate_close);
+ }
+
+
+ // @@ TODO
+ // tu_file* make_deflater(tu_file* out) { ... }
+}
+
+#endif // TU_CONFIG_LINK_TO_ZLIB
+
+
+// Local Variables:
+// mode: C++
+// c-basic-offset: 8
+// tab-width: 8
+// indent-tabs-mode: t
+// End:
Index: gnash/libgeometry/Makefile.am
diff -u gnash/libgeometry/Makefile.am:1.9 gnash/libgeometry/Makefile.am:1.10
--- gnash/libgeometry/Makefile.am:1.9 Fri Feb 3 20:50:27 2006
+++ gnash/libgeometry/Makefile.am Sun Feb 26 15:49:30 2006
@@ -33,12 +33,10 @@
INCLUDES = -I.. -I$(srcdir) \
-I$(top_srcdir) \
-I$(top_srcdir)/libbase \
+ $(PTHREAD_CFLAGS) \
$(SDL_CFLAGS) \
$(OPENGL_CFLAGS) \
- $(ENGINE_INCLUDE) \
- $(LIBPNG_CFLAGS) \
- $(ZLIB_CFLAGS) \
- $(JPEGLIB_CFLAGS)
+ $(ENGINE_INCLUDE)
libgnashgeo_la_SOURCES = \
axial_box.cpp \
Index: gnash/libgeometry/axial_box.cpp
diff -u gnash/libgeometry/axial_box.cpp:1.2 gnash/libgeometry/axial_box.cpp:1.3
--- gnash/libgeometry/axial_box.cpp:1.2 Wed Feb 1 23:58:32 2006
+++ gnash/libgeometry/axial_box.cpp Sun Feb 26 15:49:30 2006
@@ -1,69 +1,69 @@
-// axial_box.cpp -- by Thatcher Ulrich <address@hidden>
-
-// This source code has been donated to the Public Domain. Do
-// whatever you want with it.
-
-// Simple AABB structure
-
-
-#include "axial_box.h"
-#include "tu_random.h"
-#include "utility.h"
-
-
-vec3 axial_box::get_random_point() const
-// Return a random point inside this box.
-{
- return vec3(
- flerp(m_min[0], m_max[0], tu_random::get_unit_float()),
- flerp(m_min[1], m_max[1], tu_random::get_unit_float()),
- flerp(m_min[2], m_max[2], tu_random::get_unit_float()));
-}
-
-
-void axial_box::set_enclosing(const axial_box& a)
-// Ensure that the box encloses the box.
-{
- m_min.x = fmin(m_min.x, a.get_min().x);
- m_min.y = fmin(m_min.y, a.get_min().y);
- m_min.z = fmin(m_min.z, a.get_min().z);
- m_max.x = fmax(m_max.x, a.get_max().x);
- m_max.y = fmax(m_max.y, a.get_max().y);
- m_max.z = fmax(m_max.z, a.get_max().z);
-
- assert(is_valid());
-}
-
-
-int axial_box::get_longest_axis() const
-// Return axis with the largest size.
-{
- vec3 size = get_size();
- if (size.x > size.y)
- {
- if (size.x > size.z)
- {
- return 0; // x is longest
- }
- return 2; // z is longest
- }
- else
- {
- if (size.y > size.z)
- {
- return 1; // y is longest
- }
- else return 2; // z is longest
- }
-}
-
-
-
-
-
-// local Variables:
-// mode: C++
-// c-basic-offset: 8
-// tab-width: 8
-// indent-tabs-mode: t
-// End:
+// axial_box.cpp -- by Thatcher Ulrich <address@hidden>
+
+// This source code has been donated to the Public Domain. Do
+// whatever you want with it.
+
+// Simple AABB structure
+
+
+#include "axial_box.h"
+#include "tu_random.h"
+#include "utility.h"
+
+
+vec3 axial_box::get_random_point() const
+// Return a random point inside this box.
+{
+ return vec3(
+ flerp(m_min[0], m_max[0], tu_random::get_unit_float()),
+ flerp(m_min[1], m_max[1], tu_random::get_unit_float()),
+ flerp(m_min[2], m_max[2], tu_random::get_unit_float()));
+}
+
+
+void axial_box::set_enclosing(const axial_box& a)
+// Ensure that the box encloses the box.
+{
+ m_min.x = fmin(m_min.x, a.get_min().x);
+ m_min.y = fmin(m_min.y, a.get_min().y);
+ m_min.z = fmin(m_min.z, a.get_min().z);
+ m_max.x = fmax(m_max.x, a.get_max().x);
+ m_max.y = fmax(m_max.y, a.get_max().y);
+ m_max.z = fmax(m_max.z, a.get_max().z);
+
+ assert(is_valid());
+}
+
+
+int axial_box::get_longest_axis() const
+// Return axis with the largest size.
+{
+ vec3 size = get_size();
+ if (size.x > size.y)
+ {
+ if (size.x > size.z)
+ {
+ return 0; // x is longest
+ }
+ return 2; // z is longest
+ }
+ else
+ {
+ if (size.y > size.z)
+ {
+ return 1; // y is longest
+ }
+ else return 2; // z is longest
+ }
+}
+
+
+
+
+
+// local Variables:
+// mode: C++
+// c-basic-offset: 8
+// tab-width: 8
+// indent-tabs-mode: t
+// End:
Index: gnash/libgeometry/axial_box.h
diff -u gnash/libgeometry/axial_box.h:1.2 gnash/libgeometry/axial_box.h:1.3
--- gnash/libgeometry/axial_box.h:1.2 Wed Feb 1 23:58:32 2006
+++ gnash/libgeometry/axial_box.h Sun Feb 26 15:49:30 2006
@@ -1,264 +1,264 @@
-// axial_box.h -- by Thatcher Ulrich <address@hidden>
-
-// This source code has been donated to the Public Domain. Do
-// whatever you want with it.
-
-// simple AABB structure
-
-
-#ifndef AXIAL_BOX_H
-#define AXIAL_BOX_H
-
-
-#include "geometry.h"
-
-
-struct axial_box
-{
- axial_box(); // zero box
- axial_box(const vec3& min, const vec3& max);
-
- enum invalid_ctor
- {
- INVALID
- };
- axial_box(invalid_ctor e, const vec3& min, const vec3& max);
-
- //
- // Getters
- //
-
- bool is_valid() const;
-
- vec3 get_center() const { return (m_min + m_max) * 0.5f; }
- vec3 get_extent() const { return (m_max - m_min) * 0.5f; }
- vec3 get_size() const { return m_max - m_min; }
-
- const vec3& get_min() const { return m_min; }
- const vec3& get_max() const { return m_max; }
-
- // Get one of the 8 corner verts.
- vec3 get_corner(int i) const;
-
- float get_surface_area() const;
-
- vec3 get_random_point() const;
-
- //
- // Setters
- //
-
- void set_min_max(const vec3& min, const vec3& max);
-
- // No validity check -- for intentionally setting an invalid box.
- void set_min_max_invalid(const vec3& min, const vec3& max);
-
- void set_center_extent(const vec3& center, const vec3& extent);
-
- // preserve center
- void set_extent(const vec3& extent);
-
- // preserve extent
- void set_center(const vec3& center);
-
- // adjust bounds along one axis.
- void set_axis_min(int axis, float new_min);
- void set_axis_max(int axis, float new_max);
-
- // Expand the box.
- void set_enclosing(const vec3& v);
- void set_enclosing(const axial_box& a);
-
- //
- // Etc
- //
-
- bool encloses(const vec3& v, float tolerance = 1e-6f) const;
- bool encloses(const axial_box& b, float tolerance = 1e-6f) const;
-
- // this = intersection(this, b)
- void set_intersection(const axial_box& b);
-
- int get_longest_axis() const;
-
-private:
- vec3 m_min, m_max;
-};
-
-
-inline axial_box::axial_box()
-// Construct a zero box.
-{
- m_min = vec3::zero;
- m_max = vec3::zero;
-
- assert(is_valid());
-}
-
-
-inline axial_box::axial_box(const vec3& min, const vec3& max)
-// Init from extremes.
-{
- set_min_max(min, max);
-}
-
-
-inline axial_box::axial_box(invalid_ctor e, const vec3& min, const vec3& max)
-// Init from extremes, don't check validity.
-{
- set_min_max_invalid(min, max);
-}
-
-
-inline bool axial_box::is_valid() const
-// Return true if we're OK.
-{
- return
- m_min.x <= m_max.x
- && m_min.y <= m_max.y
- && m_min.z <= m_max.z;
-}
-
-
-inline vec3 axial_box::get_corner(int i) const
-{
- assert(is_valid());
- assert(i >= 0 && i < 8);
-
- return vec3(
- i & 1 ? m_min.x : m_max.x,
- i & 2 ? m_min.y : m_max.y,
- i & 4 ? m_min.z : m_max.z);
-}
-
-
-inline float axial_box::get_surface_area() const
-{
- assert(is_valid());
-
- vec3 sides(m_max);
- sides -= m_min;
-
- return
- (sides.x * sides.y
- + sides.x * sides.z
- + sides.y * sides.z) * 2;
-}
-
-
-inline void axial_box::set_min_max(const vec3& min, const vec3& max)
-{
- m_min = min;
- m_max = max;
-
- assert(is_valid());
-}
-
-
-inline void axial_box::set_min_max_invalid(const vec3& min, const vec3& max)
-// Don't check validity.
-{
- m_min = min;
- m_max = max;
-}
-
-
-inline void axial_box::set_center_extent(const vec3& center, const vec3&
extent)
-{
- set_min_max(center - extent, center + extent);
-}
-
-
-inline void axial_box::set_extent(const vec3& extent)
-{
- set_center_extent(get_center(), extent);
-}
-
-
-inline void axial_box::set_center(const vec3& center)
-{
- set_center_extent(center, get_extent());
-}
-
-
-inline void axial_box::set_axis_min(int axis, float new_min)
-{
- assert(is_valid());
-
- m_min.set(axis, new_min);
-
- assert(is_valid());
-}
-
-
-inline void axial_box::set_axis_max(int axis, float new_max)
-{
- assert(is_valid());
-
- m_max.set(axis, new_max);
-
- assert(is_valid());
-}
-
-
-// @@ should probably un-inline this...
-inline void axial_box::set_enclosing(const vec3& v)
-// Ensure that the box encloses the point.
-{
- m_min.x = fmin(m_min.x, v.x);
- m_min.y = fmin(m_min.y, v.y);
- m_min.z = fmin(m_min.z, v.z);
- m_max.x = fmax(m_max.x, v.x);
- m_max.y = fmax(m_max.y, v.y);
- m_max.z = fmax(m_max.z, v.z);
-
- assert(is_valid());
-}
-
-
-inline bool axial_box::encloses(const vec3& v, float tolerance) const
-// Return true if the given point is inside this box.
-{
- assert(is_valid());
-
- return
- m_min.x <= v.x + tolerance
- && m_min.y <= v.y + tolerance
- && m_min.z <= v.z + tolerance
- && m_max.x >= v.x - tolerance
- && m_max.y >= v.y - tolerance
- && m_max.z >= v.z - tolerance;
-}
-
-
-inline bool axial_box::encloses(const axial_box& b, float tolerance) const
-// Return true if this box encloses the given box.
-{
- assert(is_valid());
-
- return encloses(b.m_min, tolerance) && encloses(b.m_max, tolerance);
-}
-
-
-inline void axial_box::set_intersection(const axial_box& b)
-// Set this to intersection(this, b)
-{
- if (b.m_min.x > m_min.x) m_min.x = b.m_min.x;
- if (b.m_min.y > m_min.y) m_min.y = b.m_min.y;
- if (b.m_min.z > m_min.z) m_min.z = b.m_min.z;
-
- if (b.m_max.x < m_max.x) m_max.x = b.m_max.x;
- if (b.m_max.y < m_max.y) m_max.y = b.m_max.y;
- if (b.m_max.z < m_max.z) m_max.z = b.m_max.z;
-}
-
-
-#endif // AXIAL_BOX_H
-
-
-// Local Variables:
-// mode: C++
-// c-basic-offset: 8
-// tab-width: 8
-// indent-tabs-mode: t
-// End:
+// axial_box.h -- by Thatcher Ulrich <address@hidden>
+
+// This source code has been donated to the Public Domain. Do
+// whatever you want with it.
+
+// simple AABB structure
+
+
+#ifndef AXIAL_BOX_H
+#define AXIAL_BOX_H
+
+
+#include "geometry.h"
+
+
+struct axial_box
+{
+ axial_box(); // zero box
+ axial_box(const vec3& min, const vec3& max);
+
+ enum invalid_ctor
+ {
+ INVALID
+ };
+ axial_box(invalid_ctor e, const vec3& min, const vec3& max);
+
+ //
+ // Getters
+ //
+
+ bool is_valid() const;
+
+ vec3 get_center() const { return (m_min + m_max) * 0.5f; }
+ vec3 get_extent() const { return (m_max - m_min) * 0.5f; }
+ vec3 get_size() const { return m_max - m_min; }
+
+ const vec3& get_min() const { return m_min; }
+ const vec3& get_max() const { return m_max; }
+
+ // Get one of the 8 corner verts.
+ vec3 get_corner(int i) const;
+
+ float get_surface_area() const;
+
+ vec3 get_random_point() const;
+
+ //
+ // Setters
+ //
+
+ void set_min_max(const vec3& min, const vec3& max);
+
+ // No validity check -- for intentionally setting an invalid box.
+ void set_min_max_invalid(const vec3& min, const vec3& max);
+
+ void set_center_extent(const vec3& center, const vec3& extent);
+
+ // preserve center
+ void set_extent(const vec3& extent);
+
+ // preserve extent
+ void set_center(const vec3& center);
+
+ // adjust bounds along one axis.
+ void set_axis_min(int axis, float new_min);
+ void set_axis_max(int axis, float new_max);
+
+ // Expand the box.
+ void set_enclosing(const vec3& v);
+ void set_enclosing(const axial_box& a);
+
+ //
+ // Etc
+ //
+
+ bool encloses(const vec3& v, float tolerance = 1e-6f) const;
+ bool encloses(const axial_box& b, float tolerance = 1e-6f) const;
+
+ // this = intersection(this, b)
+ void set_intersection(const axial_box& b);
+
+ int get_longest_axis() const;
+
+private:
+ vec3 m_min, m_max;
+};
+
+
+inline axial_box::axial_box()
+// Construct a zero box.
+{
+ m_min = vec3::zero;
+ m_max = vec3::zero;
+
+ assert(is_valid());
+}
+
+
+inline axial_box::axial_box(const vec3& min, const vec3& max)
+// Init from extremes.
+{
+ set_min_max(min, max);
+}
+
+
+inline axial_box::axial_box(invalid_ctor e, const vec3& min, const vec3& max)
+// Init from extremes, don't check validity.
+{
+ set_min_max_invalid(min, max);
+}
+
+
+inline bool axial_box::is_valid() const
+// Return true if we're OK.
+{
+ return
+ m_min.x <= m_max.x
+ && m_min.y <= m_max.y
+ && m_min.z <= m_max.z;
+}
+
+
+inline vec3 axial_box::get_corner(int i) const
+{
+ assert(is_valid());
+ assert(i >= 0 && i < 8);
+
+ return vec3(
+ i & 1 ? m_min.x : m_max.x,
+ i & 2 ? m_min.y : m_max.y,
+ i & 4 ? m_min.z : m_max.z);
+}
+
+
+inline float axial_box::get_surface_area() const
+{
+ assert(is_valid());
+
+ vec3 sides(m_max);
+ sides -= m_min;
+
+ return
+ (sides.x * sides.y
+ + sides.x * sides.z
+ + sides.y * sides.z) * 2;
+}
+
+
+inline void axial_box::set_min_max(const vec3& min, const vec3& max)
+{
+ m_min = min;
+ m_max = max;
+
+ assert(is_valid());
+}
+
+
+inline void axial_box::set_min_max_invalid(const vec3& min, const vec3& max)
+// Don't check validity.
+{
+ m_min = min;
+ m_max = max;
+}
+
+
+inline void axial_box::set_center_extent(const vec3& center, const vec3&
extent)
+{
+ set_min_max(center - extent, center + extent);
+}
+
+
+inline void axial_box::set_extent(const vec3& extent)
+{
+ set_center_extent(get_center(), extent);
+}
+
+
+inline void axial_box::set_center(const vec3& center)
+{
+ set_center_extent(center, get_extent());
+}
+
+
+inline void axial_box::set_axis_min(int axis, float new_min)
+{
+ assert(is_valid());
+
+ m_min.set(axis, new_min);
+
+ assert(is_valid());
+}
+
+
+inline void axial_box::set_axis_max(int axis, float new_max)
+{
+ assert(is_valid());
+
+ m_max.set(axis, new_max);
+
+ assert(is_valid());
+}
+
+
+// @@ should probably un-inline this...
+inline void axial_box::set_enclosing(const vec3& v)
+// Ensure that the box encloses the point.
+{
+ m_min.x = fmin(m_min.x, v.x);
+ m_min.y = fmin(m_min.y, v.y);
+ m_min.z = fmin(m_min.z, v.z);
+ m_max.x = fmax(m_max.x, v.x);
+ m_max.y = fmax(m_max.y, v.y);
+ m_max.z = fmax(m_max.z, v.z);
+
+ assert(is_valid());
+}
+
+
+inline bool axial_box::encloses(const vec3& v, float tolerance) const
+// Return true if the given point is inside this box.
+{
+ assert(is_valid());
+
+ return
+ m_min.x <= v.x + tolerance
+ && m_min.y <= v.y + tolerance
+ && m_min.z <= v.z + tolerance
+ && m_max.x >= v.x - tolerance
+ && m_max.y >= v.y - tolerance
+ && m_max.z >= v.z - tolerance;
+}
+
+
+inline bool axial_box::encloses(const axial_box& b, float tolerance) const
+// Return true if this box encloses the given box.
+{
+ assert(is_valid());
+
+ return encloses(b.m_min, tolerance) && encloses(b.m_max, tolerance);
+}
+
+
+inline void axial_box::set_intersection(const axial_box& b)
+// Set this to intersection(this, b)
+{
+ if (b.m_min.x > m_min.x) m_min.x = b.m_min.x;
+ if (b.m_min.y > m_min.y) m_min.y = b.m_min.y;
+ if (b.m_min.z > m_min.z) m_min.z = b.m_min.z;
+
+ if (b.m_max.x < m_max.x) m_max.x = b.m_max.x;
+ if (b.m_max.y < m_max.y) m_max.y = b.m_max.y;
+ if (b.m_max.z < m_max.z) m_max.z = b.m_max.z;
+}
+
+
+#endif // AXIAL_BOX_H
+
+
+// Local Variables:
+// mode: C++
+// c-basic-offset: 8
+// tab-width: 8
+// indent-tabs-mode: t
+// End:
Index: gnash/libgeometry/collision.cpp
diff -u gnash/libgeometry/collision.cpp:1.2 gnash/libgeometry/collision.cpp:1.3
--- gnash/libgeometry/collision.cpp:1.2 Wed Feb 1 23:58:32 2006
+++ gnash/libgeometry/collision.cpp Sun Feb 26 15:49:30 2006
@@ -1,91 +1,91 @@
-// collision.cpp -- by Thatcher Ulrich <address@hidden>
-
-// This source code has been donated to the Public Domain. Do
-// whatever you want with it.
-
-// Misc helper code for doing collision tests.
-
-
-#include <float.h>
-
-#include "collision.h"
-
-
-ray_query::ray_query(const vec3& start_pos, const vec3& unit_direction, float
distance)
- :
- m_start(start_pos),
- m_end(start_pos + unit_direction * distance),
- m_dir(unit_direction),
- m_length(distance)
-{
- assert(m_length > 0);
-
- compute_inverses();
-}
-
-
-ray_query::ray_query(start_end_enum e, const vec3& start_pos, const vec3&
end_pos)
- :
- m_start(start_pos),
- m_end(end_pos)
-{
- vec3 disp = m_end - m_start;
- m_length = disp.magnitude();
- assert(m_length > 0);
-
- if (m_length > 0)
- {
- m_dir = disp;
- m_dir /= m_length;
- }
-
- compute_inverses();
-}
-
-
-void ray_query::compute_inverses()
-// Compute m_inv_dir and m_inv_displacement
-{
- vec3 disp(m_end);
- disp -= m_start;
-
- // Threshold, below which we don't want to compute 1/x.
- static const float DANGER_LIMIT_MIN = 1e-25f;
-
- for (int i = 0; i < 3; i++)
- {
- // m_inv_dir
- float comp = m_dir[i];
- if (fabsf(comp) <= DANGER_LIMIT_MIN)
- {
- m_inv_dir[i] = -FLT_MAX; // arbitrary crap
- m_dir[i] = 0; // don't tolerate tiny tiny component.
Client code will know not to use this axis.
- }
- else
- {
- m_inv_dir[i] = 1.0f / comp;
- }
-
- // m_inv_displacement
- comp = disp[i];
- if (fabsf(comp) <= DANGER_LIMIT_MIN)
- {
- m_inv_displacement[i] = -FLT_MAX; // arbitrary
crap
- m_dir[i] = 0; // don't tolerate tiny tiny component.
Client code will know not to use this axis.
- }
- else
- {
- m_inv_displacement[i] = 1.0f / comp;
- }
- }
-}
-
-
-
-
-// Local Variables:
-// mode: C++
-// c-basic-offset: 8
-// tab-width: 8
-// indent-tabs-mode: t
-// End:
+// collision.cpp -- by Thatcher Ulrich <address@hidden>
+
+// This source code has been donated to the Public Domain. Do
+// whatever you want with it.
+
+// Misc helper code for doing collision tests.
+
+
+#include <float.h>
+
+#include "collision.h"
+
+
+ray_query::ray_query(const vec3& start_pos, const vec3& unit_direction, float
distance)
+ :
+ m_start(start_pos),
+ m_end(start_pos + unit_direction * distance),
+ m_dir(unit_direction),
+ m_length(distance)
+{
+ assert(m_length > 0);
+
+ compute_inverses();
+}
+
+
+ray_query::ray_query(start_end_enum e, const vec3& start_pos, const vec3&
end_pos)
+ :
+ m_start(start_pos),
+ m_end(end_pos)
+{
+ vec3 disp = m_end - m_start;
+ m_length = disp.magnitude();
+ assert(m_length > 0);
+
+ if (m_length > 0)
+ {
+ m_dir = disp;
+ m_dir /= m_length;
+ }
+
+ compute_inverses();
+}
+
+
+void ray_query::compute_inverses()
+// Compute m_inv_dir and m_inv_displacement
+{
+ vec3 disp(m_end);
+ disp -= m_start;
+
+ // Threshold, below which we don't want to compute 1/x.
+ static const float DANGER_LIMIT_MIN = 1e-25f;
+
+ for (int i = 0; i < 3; i++)
+ {
+ // m_inv_dir
+ float comp = m_dir[i];
+ if (fabsf(comp) <= DANGER_LIMIT_MIN)
+ {
+ m_inv_dir[i] = -FLT_MAX; // arbitrary crap
+ m_dir[i] = 0; // don't tolerate tiny tiny component.
Client code will know not to use this axis.
+ }
+ else
+ {
+ m_inv_dir[i] = 1.0f / comp;
+ }
+
+ // m_inv_displacement
+ comp = disp[i];
+ if (fabsf(comp) <= DANGER_LIMIT_MIN)
+ {
+ m_inv_displacement[i] = -FLT_MAX; // arbitrary
crap
+ m_dir[i] = 0; // don't tolerate tiny tiny component.
Client code will know not to use this axis.
+ }
+ else
+ {
+ m_inv_displacement[i] = 1.0f / comp;
+ }
+ }
+}
+
+
+
+
+// Local Variables:
+// mode: C++
+// c-basic-offset: 8
+// tab-width: 8
+// indent-tabs-mode: t
+// End:
Index: gnash/libgeometry/collision.h
diff -u gnash/libgeometry/collision.h:1.2 gnash/libgeometry/collision.h:1.3
--- gnash/libgeometry/collision.h:1.2 Wed Feb 1 23:58:32 2006
+++ gnash/libgeometry/collision.h Sun Feb 26 15:49:30 2006
@@ -1,45 +1,45 @@
-// collision.h -- by Thatcher Ulrich <address@hidden>
-
-// This source code has been donated to the Public Domain. Do
-// whatever you want with it.
-
-// Basic types needed for doing collision queries.
-
-
-#ifndef COLLISION_H
-#define COLLISION_H
-
-
-#include "geometry.h"
-
-
-// Actually a line-segment query.
-struct ray_query
-{
- ray_query(const vec3& start_pos, const vec3& unit_direction, float
distance);
-
- enum start_end_enum { start_end };
- ray_query(start_end_enum e, const vec3& start_pos, const vec3& end_pos);
-
- // Internal helper to compute m_inv_*
- void compute_inverses();
-
- vec3 m_start;
- vec3 m_end;
- vec3 m_dir;
- vec3 m_inv_dir; // 1/x for each component of m_dir
- vec3 m_inv_displacement; // 1/x for each component of (m_end -
m_start)
- float m_length;
-};
-
-
-#endif // COLLISION_H
-
-
-// Local Variables:
-// mode: C++
-// c-basic-offset: 8
-// tab-width: 8
-// indent-tabs-mode: t
-// End:
-
+// collision.h -- by Thatcher Ulrich <address@hidden>
+
+// This source code has been donated to the Public Domain. Do
+// whatever you want with it.
+
+// Basic types needed for doing collision queries.
+
+
+#ifndef COLLISION_H
+#define COLLISION_H
+
+
+#include "geometry.h"
+
+
+// Actually a line-segment query.
+struct ray_query
+{
+ ray_query(const vec3& start_pos, const vec3& unit_direction, float
distance);
+
+ enum start_end_enum { start_end };
+ ray_query(start_end_enum e, const vec3& start_pos, const vec3& end_pos);
+
+ // Internal helper to compute m_inv_*
+ void compute_inverses();
+
+ vec3 m_start;
+ vec3 m_end;
+ vec3 m_dir;
+ vec3 m_inv_dir; // 1/x for each component of m_dir
+ vec3 m_inv_displacement; // 1/x for each component of (m_end -
m_start)
+ float m_length;
+};
+
+
+#endif // COLLISION_H
+
+
+// Local Variables:
+// mode: C++
+// c-basic-offset: 8
+// tab-width: 8
+// indent-tabs-mode: t
+// End:
+
Index: gnash/libgeometry/kd_tree_dynamic.cpp
diff -u gnash/libgeometry/kd_tree_dynamic.cpp:1.4
gnash/libgeometry/kd_tree_dynamic.cpp:1.5
--- gnash/libgeometry/kd_tree_dynamic.cpp:1.4 Sat Feb 25 03:54:03 2006
+++ gnash/libgeometry/kd_tree_dynamic.cpp Sun Feb 26 15:49:30 2006
@@ -1,1261 +1,1263 @@
-// kd_tree_dynamic.cpp -- by Thatcher Ulrich <address@hidden>
-
-// This source code has been donated to the Public Domain. Do
-// whatever you want with it.
-
-// Utility kd-tree structure, for building kd-trees from triangle
-// soup.
-
-
-#include "kd_tree_dynamic.h"
-#include "tu_file.h"
-#include <float.h>
-
-
-static const float EPSILON = 1e-4f;
-static const int LEAF_FACE_COUNT = 6;
-static const int MAX_SPLIT_PLANES_TESTED = 10;
-
-//#define CARVE_OFF_SPACE
-//#define ADHOC_METRIC
-#define MACDONALD_AND_BOOTH_METRIC
-//#define SORT_VERTICES
-
-// A higher value for MAX_SPLIT_PLANES_TESTED gives faster trees;
-// e.g. on one dataset, MSPT=100 gives 10% faster queries than
-// MSPT=10. But the tree building is much slower.
-
-// On one dataset I checked, SORT_VERTICES makes queries ~10% faster.
-// On most others, it seemed to make no difference. It takes extra
-// time to do the sort, though.
-
-
-float kd_tree_dynamic::face::get_min_coord(int axis, const std::vector<vec3>&
verts) const
-{
- float minval = verts[m_vi[0]][axis];
- minval = fmin(minval, verts[m_vi[1]][axis]);
- minval = fmin(minval, verts[m_vi[2]][axis]);
- return minval;
-}
-
-
-float kd_tree_dynamic::face::get_max_coord(int axis, const std::vector<vec3>&
verts) const
-{
- float maxval = verts[m_vi[0]][axis];
- maxval = fmax(maxval, verts[m_vi[1]][axis]);
- maxval = fmax(maxval, verts[m_vi[2]][axis]);
- return maxval;
-}
-
-
-void split_mesh(
- std::vector<vec3>* verts0,
- std::vector<int>* tris0,
- std::vector<vec3>* verts1,
- std::vector<int>* tris1,
- int vert_count,
- const vec3 verts[],
- int triangle_count,
- const int indices[],
- int axis,
- float offset)
-// Divide a mesh into two pieces, roughly along the plane [axis]=offset.
-// Assign faces to one side or the other based on centroid.
-{
- assert(verts0 && tris0 && verts1 && tris1);
- assert(verts0->size() == 0);
- assert(tris0->size() == 0);
- assert(verts1->size() == 0);
- assert(tris1->size() == 0);
-
- // Remap table from verts array to new verts0/1 arrays.
- hash<int, int> verts_to_verts0;
- hash<int, int> verts_to_verts1;
-
- // Divide the faces.
- for (int i = 0; i < triangle_count; i++)
- {
- int index = i * 3;
- int v[3] = {
- indices[index],
- indices[index + 1],
- indices[index + 2]
- };
-
- float centroid = (verts[v[0]][axis] + verts[v[1]][axis] +
verts[v[2]][axis]) / 3.0f;
-
- if (centroid < offset)
- {
- // Put this face into verts0/tris0
- for (int ax = 0; ax < 3; ax++)
- {
- int new_index;
- if (verts_to_verts0.get(v[ax], &new_index))
- {
- // OK.
- }
- else
- {
- // Must add.
- new_index = verts0->size();
- verts_to_verts0.add(v[ax], new_index);
- verts0->push_back(verts[v[ax]]);
- }
- tris0->push_back(new_index);
- }
- }
- else
- {
- // Put this face into verts1/tris1
- for (int ax = 0; ax < 3; ax++)
- {
- int new_index;
- if (verts_to_verts1.get(v[ax], &new_index))
- {
- // OK.
- }
- else
- {
- // Must add.
- new_index = verts1->size();
- verts_to_verts1.add(v[ax], new_index);
- verts1->push_back(verts[v[ax]]);
- }
- tris1->push_back(new_index);
- }
- }
- }
-}
-
-
-static void remap_vertex_order(kd_tree_dynamic::node* node, hash<int,int>*
map_indices_old_to_new, int* new_vertex_count)
-// Traverse this tree in depth-first order, and remap the vertex
-// indices to go in order.
-{
- if (node == NULL) return;
-
- if (node->m_leaf)
- {
- for (int i = 0, n = node->m_leaf->m_faces.size(); i < n; i++)
- {
- kd_tree_dynamic::face* f = &node->m_leaf->m_faces[i];
- for (int vi = 0; vi < 3; vi++)
- {
- int old_index = f->m_vi[vi];
- int new_index = *new_vertex_count;
- if (map_indices_old_to_new->get(old_index,
&new_index))
- {
- // vert is already remapped; use
existing mapping.
- }
- else
- {
- // vert is not remapped yet; remap it.
- map_indices_old_to_new->add(old_index,
new_index);
- (*new_vertex_count) += 1;
- }
-
- // Remap.
- f->m_vi[vi] = new_index;
- }
- }
- }
- else
- {
- remap_vertex_order(node->m_neg, map_indices_old_to_new,
new_vertex_count);
- remap_vertex_order(node->m_pos, map_indices_old_to_new,
new_vertex_count);
- }
-}
-
-
-/*static*/ void kd_tree_dynamic::build_trees(
- std::vector<kd_tree_dynamic*>* treelist,
- int vert_count,
- const vec3 verts[],
- int triangle_count,
- const int indices[]
- )
-// Build one or more kd trees to represent the given mesh.
-{
- if (vert_count >= 65536)
- {
- // Too many verts for one tree; subdivide.
- axial_box bound;
- compute_actual_bounds(&bound, vert_count, verts);
-
- int longest_axis = bound.get_longest_axis();
- float offset = bound.get_center()[longest_axis];
-
- std::vector<vec3> verts0, verts1;
- std::vector<int> tris0, tris1;
- split_mesh(
- &verts0,
- &tris0,
- &verts1,
- &tris1,
- vert_count,
- verts,
- triangle_count,
- indices,
- longest_axis,
- offset);
-
- if ((int) verts0.size() >= vert_count || (int) verts1.size() >=
vert_count)
- {
- // Trouble: couldn't reduce vert count by
- // splitting.
- assert(0);
- // log error
- return;
- }
-
- build_trees(treelist, verts0.size(), &verts0[0], tris0.size() /
3, &tris0[0]);
- build_trees(treelist, verts1.size(), &verts1[0], tris1.size() /
3, &tris1[0]);
-
- return;
- }
-
- treelist->push_back(new kd_tree_dynamic(vert_count, verts,
triangle_count, indices));
-}
-
-
-kd_tree_dynamic::kd_tree_dynamic(
- int vert_count,
- const vec3 verts[],
- int triangle_count,
- const int indices[])
-// Constructor; build the kd-tree from the given triangle soup.
-{
- assert(vert_count > 0 && vert_count < 65536);
- assert(triangle_count > 0);
-
- // Copy the verts.
- m_verts.resize(vert_count);
- memcpy(&m_verts[0], verts, sizeof(verts[0]) * vert_count);
-
- // Make a mutable array of faces, and also compute our bounds.
- axial_box bounds(axial_box::INVALID, vec3::flt_max,
vec3::minus_flt_max);
- std::vector<face> faces;
- for (int i = 0; i < triangle_count; i++)
- {
- face f;
- f.m_vi[0] = indices[i * 3 + 0];
- f.m_vi[1] = indices[i * 3 + 1];
- f.m_vi[2] = indices[i * 3 + 2];
- f.m_flags = 0; // @@ should be a way to initialize this
-
- faces.push_back(f);
-
- // Update bounds.
- bounds.set_enclosing(m_verts[f.m_vi[0]]);
- bounds.set_enclosing(m_verts[f.m_vi[1]]);
- bounds.set_enclosing(m_verts[f.m_vi[2]]);
- }
-
- m_bound = bounds;
-
- m_root = build_tree(1, faces.size(), &faces[0], bounds);
-
-#ifdef SORT_VERTICES
- // Sort vertices in the order they first appear in a
- // depth-first traversal of the tree. Idea is to exploit
- // cache coherency when traversing tree.
-
- hash<int, int> map_indices_old_to_new;
- int new_vertex_count = 0;
- remap_vertex_order(m_root, &map_indices_old_to_new, &new_vertex_count);
-
- assert(new_vertex_count == m_verts.size());
-
- // Make the re-ordered vertex buffer.
- std::vector<vec3> new_verts;
- new_verts.resize(new_vertex_count);
- for (int i = 0; i < m_verts.size(); i++)
- {
- int new_index = 0;
- bool found = map_indices_old_to_new.get(i, &new_index);
- assert(found);
- if (found)
- {
- new_verts[new_index] = m_verts[i];
- }
- }
-
- // Use the new verts.
- m_verts = new_verts;
-#endif // SORT_VERTICES
-}
-
-
-kd_tree_dynamic::~kd_tree_dynamic()
-// Destructor; make sure to delete the stuff we allocated.
-{
- delete m_root;
-}
-
-
-kd_tree_dynamic::node* kd_tree_dynamic::build_tree(int depth, int face_count,
face faces[], const axial_box& bounds)
-// Recursively build a kd-tree from the given set of faces. Return
-// the root of the tree.
-{
- assert(face_count >= 0);
-
- if (face_count == 0)
- {
- return NULL;
- }
-
- // Should we make a leaf?
- if (face_count <= LEAF_FACE_COUNT)
- {
- // Make a leaf
- node* n = new node;
- n->m_leaf = new leaf;
- n->m_leaf->m_faces.resize(face_count);
- memcpy(&(n->m_leaf->m_faces[0]), faces, sizeof(faces[0]) *
face_count);
-
- return n;
- }
-
- // TODO I believe it may be better to try partitioning planes,
- // which separate the faces according to triangle centroid (or
- // centroid of the bound?), and then compute the actual
- // splitting planes based on the partition. I think this
- // helps avoid some bad situations with large triangles, where
- // a large tri keeps getting pushed down deeper and deeper.
- //
- // Currently we generate a candidate neg_offset plane
- // directly, and include all triangles fully behind the
- // neg_offset in one child, which may tend to be unbalanced.
-
- // Find a good splitting plane.
- float best_split_quality = 0.0f;
- int best_split_axis = -1;
- float best_split_neg_offset = 0.0f;
- float best_split_pos_offset = 0.0f;
-
- for (int axis = 0; axis < 3; axis++)
- {
- if (bounds.get_extent()[axis] < EPSILON)
- {
- // Don't try to divide
- continue;
- }
-
- // Try offsets that correspond to existing face boundaries.
- int step_size = 1;
- if (face_count > MAX_SPLIT_PLANES_TESTED)
- {
- // For the sake of speed & sanity, only try the bounds
- // of every N faces.
- step_size = face_count / MAX_SPLIT_PLANES_TESTED;
- }
- assert(step_size > 0);
-
- float last_offset_tried = -FLT_MAX;
- float pos_offset = 0;
- for (int i = 0; i < face_count; i += step_size)
- {
- float neg_offset = faces[i].get_max_coord(axis,
m_verts);
-
- if (fabsf(neg_offset - last_offset_tried) < EPSILON)
- {
- // Already tried this.
- continue;
- }
-
- last_offset_tried = neg_offset;
-
- // How good is this split?
- float quality = evaluate_split(depth, face_count,
faces, bounds, axis, neg_offset, &pos_offset);
- if (quality > best_split_quality)
- {
- // Best so far.
- best_split_quality = quality;
- best_split_axis = axis;
- best_split_neg_offset = neg_offset;
- best_split_pos_offset = pos_offset;
- }
- }
- }
-
- if (best_split_axis == -1)
- {
- // Couldn't find any acceptable split!
- // Make a leaf.
- node* n = new node;
- n->m_leaf = new leaf;
- n->m_leaf->m_faces.resize(face_count);
- memcpy(&(n->m_leaf->m_faces[0]), faces, sizeof(faces[0]) *
face_count);
-
- return n;
- }
- else
- {
- // Make the split.
- int back_end = 0;
- int front_end = 0;
-
- // We use the implicit node bounds, not the actual bounds of
- // the face sets, for computing split quality etc, since that
- // is what the run-time structures have when they are
- // computing query results.
-
- axial_box back_bounds(bounds);
- back_bounds.set_axis_max(best_split_axis,
best_split_neg_offset);
-
- axial_box front_bounds(bounds);
- front_bounds.set_axis_min(best_split_axis,
best_split_pos_offset);
-
- node* n = new node;
- n->m_axis = best_split_axis;
- n->m_neg_offset = best_split_neg_offset;
- n->m_pos_offset = best_split_pos_offset;
-
- // Recursively build sub-trees.
- do_split(&back_end, &front_end, face_count, faces,
best_split_axis, best_split_neg_offset, best_split_pos_offset);
-
- n->m_neg = build_tree(depth + 1, back_end, faces + 0,
back_bounds);
- n->m_pos = build_tree(depth + 1, front_end - back_end, faces +
back_end, front_bounds);
-
- return n;
- }
-}
-
-
-kd_tree_dynamic::node::node()
-// Default constructor, null everything out.
- :
- m_neg(0),
- m_pos(0),
- m_leaf(0),
- m_axis(0),
- m_neg_offset(0.0f),
- m_pos_offset(0.0f)
-{
-}
-
-
-kd_tree_dynamic::node::~node()
-// Destructor, delete children if any.
-{
- delete m_neg;
- delete m_pos;
- delete m_leaf;
-}
-
-
-bool kd_tree_dynamic::node::is_valid() const
-{
- return
- // internal node.
- (m_leaf == 0
- && m_axis >= 0
- && m_axis < 3)
- ||
- // leaf node
- (m_leaf != 0
- && m_neg == 0
- && m_pos == 0)
- ;
-}
-
-
-void kd_tree_dynamic::compute_actual_bounds(axial_box* result, int
face_count, face faces[])
-// Compute the actual bounding box around the given list of faces.
-{
- assert(face_count > 0);
-
- result->set_min_max_invalid(vec3::flt_max, vec3::minus_flt_max);
-
- for (int i = 0; i < face_count; i++)
- {
- const face& f = faces[i];
-
- // Update bounds.
- result->set_enclosing(m_verts[f.m_vi[0]]);
- result->set_enclosing(m_verts[f.m_vi[1]]);
- result->set_enclosing(m_verts[f.m_vi[2]]);
- }
-}
-
-
-/*static*/ void kd_tree_dynamic::compute_actual_bounds(axial_box*
result, int vert_count, const vec3 verts[])
-// Compute the actual bounding box around the given list of faces.
-{
- assert(vert_count > 0);
-
- result->set_min_max_invalid(vec3::flt_max, vec3::minus_flt_max);
-
- for (int i = 0; i < vert_count; i++)
- {
- // Update bounds.
- result->set_enclosing(verts[i]);
- }
-}
-
-
-static int classify_coord(float coord, float offset)
-{
- if (coord < offset /* - EPSILON */)
- {
- return -1;
- }
- else if (coord > offset /* + EPSILON */)
- {
- return 1;
- }
- else
- {
- return 0;
- }
-}
-
-
-void kd_tree_dynamic::do_split(
- int* back_end,
- int* front_end,
- int face_count,
- face faces[],
- int axis,
- float neg_offset,
- float pos_offset)
-// Classify the given faces as either negative or positive. The faces
-// within faces[] are shuffled. On exit, the faces[] array has the
-// following segments:
-//
-// [0, *neg_end-1] -- the faces behind the plane axis=neg_offset
-// [neg_end, face_count-1] -- the faces in front of axis=pos_offset (i.e.
everything else)
-//
-// pos_offset must be placed so that it catches everything not on the
-// negative side; this routine asserts against that.
-{
- // We do an in-place sort. During sorting, faces[] is divided
- // into three segments: at the beginning are the front faces,
- // in the middle are the unsorted faces, and at the end are
- // the back faces. when we sort a face, we swap it into the
- // next position for either the back or front face segment.
- int back_faces_end = 0;
- int front_faces_start = face_count;
- //int next_face = 0;
-
- while (back_faces_end < front_faces_start)
- {
- const face& f = faces[back_faces_end];
-
- int result = classify_face(f, axis, neg_offset);
- if (result == -1)
- {
- // Behind. Leave this face where it is, and
- // bump back_faces_end so it's now in the back
- // faces segment.
- back_faces_end++;
- }
- else
- {
- // In front.
- assert(f.get_min_coord(axis, m_verts) >= pos_offset);
// should not have any crossing faces!
-
- // Swap this face up to the beginning of the front
faces.
- front_faces_start--;
- swap(&faces[back_faces_end], &faces[front_faces_start]);
- }
- }
-
- *back_end = back_faces_end;
- *front_end = face_count;
- assert(*back_end <= *front_end);
- assert(*front_end == face_count);
-
-#if 0
- std::vector<face> back_faces;
- std::vector<face> front_faces;
-
- for (int i = 0; i < face_count; i++)
- {
- const face& f = faces[i];
-
- int result = classify_face(f, axis, neg_offset);
- if (result == -1)
- {
- // Behind.
- back_faces.push_back(f);
- }
- else
- {
- assert(f.get_min_coord(axis, m_verts) >= pos_offset);
// should not have any crossing faces!
-
- front_faces.push_back(f);
- }
- }
-
- assert(back_faces.size() + front_faces.size() == face_count);
-
- *back_end = back_faces.size();
- if (back_faces.size() > 0)
- {
- memcpy(&(faces[0]), &(back_faces[0]), back_faces.size() *
sizeof(faces[0]));
- }
-
- *front_end = *back_end + front_faces.size();
- if (front_faces.size() > 0)
- {
- memcpy(&faces[*back_end], &front_faces[0], front_faces.size() *
sizeof(faces[0]));
- }
-
- assert(*back_end <= *front_end);
- assert(*front_end == face_count);
-#endif // 0
-}
-
-
-float kd_tree_dynamic::evaluate_split(
- int depth,
- int face_count,
- face faces[],
- const axial_box& bounds,
- int axis,
- float neg_offset,
- float* pos_offset)
-// Compute the "value" of splitting the given set of faces, bounded by
-// the given box, along the plane [axis]=offset. A value of 0 means
-// that a split is possible, but has no value. A negative value means
-// that the split is not valid at all. Positive values indicate
-// increasing goodness.
-//
-// *pos_offset is computed based on the minimum coord of the faces
-// that don't fit behind the neg_offset. Could be greater or less
-// than neg_offset.
-//
-// This is kinda heuristicy -- it's where the "special sauce" comes
-// in.
-{
- // Count the faces that will end up in the groups
- // back,front.
- int back_count = 0;
- int front_count = 0;
-
- *pos_offset = bounds.get_max()[axis];
-
- for (int i = 0; i < face_count; i++)
- {
- const face& f = faces[i];
-
- int result = classify_face(f, axis, neg_offset);
- if (result == -1)
- {
- // Neg.
- back_count++;
- }
- else
- {
- // Pos.
- front_count++;
-
- // Update *pos_offset so it contains this face.
- float mincoord = f.get_min_coord(axis, m_verts);
- if (mincoord < *pos_offset)
- {
- *pos_offset = mincoord;
- assert(mincoord >= bounds.get_min()[axis]);
- }
- }
- }
-
- if ((back_count == 0 && *pos_offset - EPSILON <= bounds.get_min()[axis])
- || (front_count == 0 && neg_offset + EPSILON >=
bounds.get_max()[axis]))
- {
- // No faces are separated by this split; this split is
- // entirely useless.
- return -1;
- }
-
- //float center = bounds.get_center().get(axis);
- //float extent = bounds.get_extent().get(axis);
-
- axial_box back_bounds(bounds);
- back_bounds.set_axis_max(axis, neg_offset);
- axial_box front_bounds(bounds);
- front_bounds.set_axis_min(axis, *pos_offset);
-
-// Probably not a win.
-#ifdef CARVE_OFF_SPACE
- // Special case: if the plane carves off space at one side or the
- // other, without orphaning any faces, then we reward a large
- // empty space.
- float space_quality = 0.0f;
- if (front_count == 0)
- {
- // All the faces are in back -- reward a bigger empty front
volume.
- return space_quality = back_count *
front_bounds.get_surface_area();
- }
- else if (back_count == 0)
- {
- // All the faces are in front.
- return space_quality = front_count *
back_bounds.get_surface_area();
- }
-#endif // CARVE_OFF_SPACE
-
-
-// My ad-hoc metric
-#ifdef ADHOC_METRIC
- // compute a figure for how close to the center this splitting
- // plane is. Normalize in [0,1].
- float volume_balance = 1.0f - fabsf(center - (neg_offset +
*pos_offset) / 2) / extent;
-
- // Compute a figure for how well we balance the faces. 0 == bad,
- // 1 == good.
- float face_balance = 1.0f - (fabsf(float(front_count - back_count)))
/ face_count;
-
- float split_quality = bounds.get_surface_area() * volume_balance *
face_balance;
-
- return split_quality;
-#endif // ADHOC_METRIC
-
-
-#ifdef MACDONALD_AND_BOOTH_METRIC
- // MacDonald and Booth's metric, as quoted by Havran, endorsed by
- // Ville Miettinen and Atman Binstock:
-
- float cost_back = back_bounds.get_surface_area() * (back_count);
- float cost_front = front_bounds.get_surface_area() * (front_count);
-
- float havran_cost = cost_back + cost_front;
-
- float parent_cost = bounds.get_surface_area() * face_count;
-
- // We need to turn the cost into a quality, so subtract it from a
- // big number.
- return parent_cost - havran_cost;
-
-#endif // MACDONALD_AND_BOOTH_METRIC
-}
-
-
-int kd_tree_dynamic::classify_face(const face& f, int axis, float offset)
-// Return -1 if the face is entirely behind the plane [axis]=offset
-// Return 0 if the face spans the plane.
-// Return 1 if the face is entirely in front of the plane.
-//
-// "behind" means on the negative side, "in front" means on the
-// positive side.
-{
- assert(axis >= 0 && axis < 3);
-
- bool has_front_vert = false;
- bool has_back_vert = false;
-
- for (int i = 0; i < 3; i++)
- {
- float coord = m_verts[f.m_vi[i]].get(axis);
- int cr = classify_coord(coord, offset);
-
- if (cr == -1)
- {
- has_back_vert = true;
- }
- else if (cr == 1)
- {
- has_front_vert = true;
- }
- }
-
- if (has_front_vert && has_back_vert)
- {
- return 0; // crossing.
- }
- else if (has_front_vert)
- {
- return 1; // all verts in front.
- }
- else if (has_back_vert)
- {
- return -1; // all verts in back.
- }
- else
- {
- // Face is ON the plane.
- return 0; // call it "crossing".
- }
-}
-
-
-void kd_tree_dynamic::clip_faces(std::vector<face>* faces, int axis, float
offset)
-// Clip the given faces against the plane [axis]=offset. Update the
-// *faces array with the newly clipped faces; add faces and verts as
-// necessary.
-{
- int original_face_count = faces->size();
-
- for (int i = 0; i < original_face_count; i++)
- {
- face f = (*faces)[i];
-
- if (classify_face(f, axis, offset) == 0)
- {
- // Crossing face, probably needs to be clipped.
-
- int vr[3];
- vr[0] = classify_coord(m_verts[f.m_vi[0]].get(axis),
offset);
- vr[1] = classify_coord(m_verts[f.m_vi[1]].get(axis),
offset);
- vr[2] = classify_coord(m_verts[f.m_vi[2]].get(axis),
offset);
-
- // Sort...
- if (vr[0] > vr[1])
- {
- swap(&vr[0], &vr[1]);
- swap(&f.m_vi[0], &f.m_vi[1]);
- }
- if (vr[1] > vr[2])
- {
- swap(&vr[1], &vr[2]);
- swap(&f.m_vi[1], &f.m_vi[2]);
- }
- if (vr[0] > vr[1])
- {
- swap(&vr[0], &vr[1]);
- swap(&f.m_vi[0], &f.m_vi[1]);
- }
-
- if (vr[0] == 0 || vr[2] == 0)
- {
- // Face doesn't actually cross; no need to clip.
- continue;
- }
-
- const vec3 v[3] = {
- m_verts[f.m_vi[0]],
- m_verts[f.m_vi[1]],
- m_verts[f.m_vi[2]]
- };
-
- // Different cases.
- if (vr[1] == 0)
- {
- // Middle vert is on the plane; make two
triangles.
-
- // One new vert.
- float lerper = (offset - v[0].get(axis)) /
(v[2].get(axis) - v[0].get(axis));
- vec3 new_vert = v[0] * (1 - lerper) + v[2] *
lerper;
- new_vert.set(axis, offset); // make damn
sure
- assert(new_vert.checknan() == false);
-
- int new_vi = m_verts.size();
- m_verts.push_back(new_vert);
-
- // New faces.
- face f0 = f;
- f0.m_vi[2] = new_vi;
- (*faces)[i] = f0; // replace original face
-
- assert(classify_face(f0, axis, offset) <= 0);
-
- face f1 = f;
- f1.m_vi[0] = new_vi;
- faces->push_back(f1); // add a face
-
- assert(classify_face(f1, axis, offset) >= 0);
- }
- else if (vr[1] < 0)
- {
- // Middle vert is behind the plane.
- // Make two tris behind, one in front.
-
- // Two new verts.
- float lerper0 = (offset - v[0].get(axis)) /
(v[2].get(axis) - v[0].get(axis));
- vec3 new_vert0 = v[0] * (1 - lerper0) + v[2]
* lerper0;
- new_vert0.set(axis, offset); // make damn
sure
- assert(new_vert0.checknan() == false);
- int new_vi0 = m_verts.size();
- m_verts.push_back(new_vert0);
-
- float lerper1 = (offset - v[1].get(axis)) /
(v[2].get(axis) - v[1].get(axis));
- vec3 new_vert1 = v[1] * (1 - lerper1) + v[2]
* lerper1;
- new_vert1.set(axis, offset); // make damn
sure
- assert(new_vert1.checknan() == false);
- int new_vi1 = m_verts.size();
- m_verts.push_back(new_vert1);
-
- // New faces.
- face f0 = f;
- f0.m_vi[2] = new_vi0;
- (*faces)[i] = f0;
-
- assert(classify_face(f0, axis, offset) <= 0);
-
- face f1 = f;
- f1.m_vi[0] = new_vi0;
- f1.m_vi[2] = new_vi1;
- faces->push_back(f1);
-
- assert(classify_face(f1, axis, offset) <= 0);
-
- face f2 = f;
- f2.m_vi[0] = new_vi0;
- f2.m_vi[1] = new_vi1;
- faces->push_back(f2);
-
- assert(classify_face(f2, axis, offset) >= 0);
- }
- else if (vr[1] > 0)
- {
- // Middle vert is in front of the plane.
- // Make on tri behind, two in front.
-
- // Two new verts.
- float lerper1 = (offset - v[0].get(axis)) /
(v[1].get(axis) - v[0].get(axis));
- vec3 new_vert1 = v[0] * (1 - lerper1) + v[1]
* lerper1;
- new_vert1.set(axis, offset); // make damn
sure
- assert(new_vert1.checknan() == false);
- int new_vi1 = m_verts.size();
- m_verts.push_back(new_vert1);
-
- float lerper2 = (offset - v[0].get(axis)) /
(v[2].get(axis) - v[0].get(axis));
- vec3 new_vert2 = v[0] * (1 - lerper2) + v[2]
* lerper2;
- new_vert2.set(axis, offset); // make damn
sure
- assert(new_vert2.checknan() == false);
- int new_vi2 = m_verts.size();
- m_verts.push_back(new_vert2);
-
- // New faces.
- face f0 = f;
- f0.m_vi[1] = new_vi1;
- f0.m_vi[2] = new_vi2;
- (*faces)[i] = f0;
-
- assert(classify_face(f0, axis, offset) <= 0);
-
- face f1 = f;
- f1.m_vi[0] = new_vi1;
- f1.m_vi[2] = new_vi2;
- faces->push_back(f1);
-
- assert(classify_face(f1, axis, offset) >= 0);
-
- face f2 = f;
- f2.m_vi[0] = new_vi2;
- faces->push_back(f2);
-
- assert(classify_face(f2, axis, offset) >= 0);
- }
- }
-
- }
-}
-
-
-void kd_tree_dynamic::dump(tu_file* out) const
-// Dump some debug info.
-{
- node* n = m_root;
-
- if (n) n->dump(out, 0);
-}
-
-
-void kd_tree_dynamic::node::dump(tu_file* out, int depth) const
-{
- for (int i = 0; i < depth; i++) { out->write_byte(' '); }
-
- if (m_leaf)
- {
- int face_count = m_leaf->m_faces.size();
- char c = ("0123456789X")[iclamp(face_count, 0, 10)];
- out->write_byte(c);
- out->write_byte('\n');
- }
- else
- {
- out->write_byte('+');
- out->write_byte('\n');
- if (m_neg)
- {
- m_neg->dump(out, depth + 1);
- }
- if (m_pos)
- {
- m_pos->dump(out, depth + 1);
- }
- }
-}
-
-
-#include "postscript.h"
-
-
-static const int X_SIZE = 612;
-static const int Y_SIZE = 792;
-static const int MARGIN = 20;
-
-
-struct kd_diagram_dump_info
-{
- postscript* m_ps;
- int m_depth;
- int m_max_depth;
- std::vector<int> m_width; // width of the tree at each
level
- std::vector<int> m_max_width;
- std::vector<int> m_count; // width so far, during drawing
-
- // Some stats.
- int m_leaf_count;
- int m_node_count;
- int m_face_count;
- int m_max_faces_in_leaf;
- int m_null_children;
- int m_depth_times_faces;
-
- kd_diagram_dump_info()
- :
- m_ps(0),
- m_depth(0),
- m_max_depth(0),
- m_leaf_count(0),
- m_node_count(0),
- m_face_count(0),
- m_max_faces_in_leaf(0),
- m_null_children(0),
- m_depth_times_faces(0)
- {
- }
-
- void get_node_coords(int* x, int* y)
- {
- float h_spacing = (X_SIZE - MARGIN*2) /
float(m_max_width.back());
- float adjust = 1.0f;
- if (m_width[m_depth] > 1) adjust = (m_max_width[m_depth] + 1) /
float(m_width[m_depth] + 1);
-
- *x = int(X_SIZE/2 + (m_count[m_depth] - m_width[m_depth] / 2) *
h_spacing * adjust);
- *y = Y_SIZE - MARGIN - m_depth * (Y_SIZE - MARGIN*2) /
(m_max_depth + 1);
- }
-
- void update_stats(kd_tree_dynamic::node* n)
- // Add this node's stats to our totals.
- {
- if (n == 0)
- {
- m_null_children++;
- }
- else if (n->m_leaf)
- {
- m_leaf_count++;
-
- assert(n->m_leaf);
- int faces = n->m_leaf->m_faces.size();
- m_face_count += faces;
- if (faces > m_max_faces_in_leaf) m_max_faces_in_leaf =
faces;
-
- m_depth_times_faces += (m_depth + 1) * faces;
- }
- else
- {
- m_node_count++;
- }
- }
-
- void diagram_stats()
- // Print some textual stats to the given Postscript stream.
- {
- float x = MARGIN;
- float y = Y_SIZE - MARGIN;
- const float LINE = 10;
- y -= LINE; m_ps->printf(x, y, "Loose KD-Tree");
-#ifdef MACDONALD_AND_BOOTH_METRIC
- y -= LINE; m_ps->printf(x, y, "using MacDonald and Booth
metric");
-#endif
-#ifdef ADHOC_METRIC
- y -= LINE; m_ps->printf(x, y, "using ad-hoc metric");
-#endif
-#ifdef CARVE_OFF_SPACE
- y -= LINE; m_ps->printf(x, y, "using carve-off-space
heuristic");
-#endif
- y -= LINE; m_ps->printf(x, y, "leaf face count limit: %d",
LEAF_FACE_COUNT);
- y -= LINE; m_ps->printf(x, y, "face ct: %d", m_face_count);
- y -= LINE; m_ps->printf(x, y, "leaf ct: %d", m_leaf_count);
- y -= LINE; m_ps->printf(x, y, "node ct: %d", m_node_count);
- y -= LINE; m_ps->printf(x, y, "null ct: %d", m_null_children);
- y -= LINE; m_ps->printf(x, y, "worst leaf: %d faces",
m_max_faces_in_leaf);
- y -= LINE; m_ps->printf(x, y, "max depth: %d", m_max_depth + 1);
- y -= LINE; m_ps->printf(x, y, "avg face depth: %3.2f",
m_depth_times_faces / float(m_face_count));
- }
-};
-
-
-static void node_traverse(kd_diagram_dump_info* inf, kd_tree_dynamic::node*
n)
-// Traverse the tree, updating inf->m_width. That's helpful for
-// formatting the diagram.
-{
- inf->update_stats(n);
-
- if (inf->m_depth > inf->m_max_depth)
- {
- inf->m_max_depth = inf->m_depth;
- }
-
- while ((int) inf->m_width.size() <= inf->m_max_depth)
- {
- inf->m_width.push_back(0);
- }
-
- inf->m_width[inf->m_depth]++; // count this node.
-
- if (n && n->m_leaf == 0)
- {
- // Count children.
- inf->m_depth++;
- node_traverse(inf, n->m_neg);
- node_traverse(inf, n->m_pos);
- inf->m_depth--;
-
- assert(inf->m_depth >= 0);
- }
-}
-
-
-static void node_diagram(kd_diagram_dump_info* inf, kd_tree_dynamic::node*
n, int parent_x, int parent_y)
-// Emit Postscript drawing commands to diagram this node in the tree.
-{
- // Diagram this node.
- int x, y;
- inf->get_node_coords(&x, &y);
-
- // Line to parent.
- inf->m_ps->line((float) x, (float) y, (float) parent_x, (float)
parent_y);
-
- if (n == 0)
- {
- // NULL --> show a circle w/ slash
- inf->m_ps->circle((float) x, (float) y, 1);
- inf->m_ps->line((float) x + 1, (float) y + 1, (float) x - 1,
(float) y - 1);
- }
- else if (n->m_leaf)
- {
- // Leaf. Draw concentric circles.
- int face_count = n->m_leaf->m_faces.size();
- for (int i = 0; i < face_count + 1; i++)
- {
- inf->m_ps->circle((float) x, (float) y, 2 + i * 1.0f);
- }
- }
- else
- {
- // Internal node.
-
- // draw disk
- inf->m_ps->disk((float) x, (float) y, 1);
-
- // draw children.
- inf->m_depth++;
- node_diagram(inf, n->m_neg, x, y);
- node_diagram(inf, n->m_pos, x, y);
- inf->m_depth--;
-
- assert(inf->m_depth >= 0);
- }
-
- // count this node.
- inf->m_count[inf->m_depth]++;
-}
-
-
-void kd_tree_dynamic::diagram_dump(tu_file* out) const
-// Generate a Postscript schematic diagram of the tree.
-{
- postscript* ps = new postscript(out, "kd-tree diagram");
-
- kd_diagram_dump_info inf;
- inf.m_ps = ps;
- inf.m_depth = 0;
-
- node_traverse(&inf, m_root);
-
- while ((int) inf.m_count.size() <= inf.m_max_depth)
- {
- inf.m_count.push_back(0);
- }
-
- int max_width = 1;
- for (int i = 0; i <= inf.m_max_depth; i++)
- {
- if (inf.m_width[i] > max_width)
- {
- max_width = inf.m_width[i];
- }
- inf.m_max_width.push_back(max_width);
- }
-
- inf.diagram_stats();
-
- int root_x = 0, root_y = 0;
- inf.get_node_coords(&root_x, &root_y);
-
- node_diagram(&inf, m_root, root_x, root_y);
-
- delete ps;
-}
-
-
-static void mesh_node_dump(
- postscript* ps,
- int axis,
- kd_tree_dynamic::node* node,
- const axial_box& bound,
- const std::vector<vec3>& verts)
-// Draw faces under node, projected onto given axis plane. Scale to fit paper.
-{
- if (node == NULL) return;
-
- if (node->m_leaf)
- {
- // Draw faces.
- for (int i = 0, n = node->m_leaf->m_faces.size(); i < n; i++)
- {
- vec3 v[3] = {
- verts[node->m_leaf->m_faces[i].m_vi[0]],
- verts[node->m_leaf->m_faces[i].m_vi[1]],
- verts[node->m_leaf->m_faces[i].m_vi[2]]
- };
-
- float x[3], y[3];
- int axis1 = (axis + 1) % 3;
- int axis2 = (axis + 2) % 3;
- for (int vert = 0; vert < 3; vert++)
- {
- x[vert] = (v[vert][axis1] -
bound.get_min()[axis1]) / bound.get_size()[axis1];
- y[vert] = (v[vert][axis2] -
bound.get_min()[axis2]) / bound.get_size()[axis2];
-
- x[vert] = flerp(float(MARGIN), float(X_SIZE -
MARGIN), x[vert]);
- y[vert] = flerp(float(MARGIN), float(Y_SIZE -
MARGIN), y[vert]);
- }
-
- // Draw triangle.
- ps->line(x[0], y[0], x[1], y[1]);
- ps->line(x[1], y[1], x[2], y[2]);
- ps->line(x[2], y[2], x[0], y[0]);
- }
-
- return;
- }
-
- mesh_node_dump(ps, axis, node->m_neg, bound, verts);
- mesh_node_dump(ps, axis, node->m_pos, bound, verts);
-}
-
-
-void kd_tree_dynamic::mesh_diagram_dump(tu_file* out, int axis) const
-// Generate a Postscript schematic diagram of the mesh, orthogonal to
-// the given axis.
-{
- postscript* ps = new postscript(out, "kd-tree diagram");
-
- mesh_node_dump(ps, axis, m_root, get_bound(), m_verts);
-
- delete ps;
-}
-
-
-// Local Variables:
-// mode: C++
-// c-basic-offset: 8
-// tab-width: 8
-// indent-tabs-mode: t
-// End:
+// kd_tree_dynamic.cpp -- by Thatcher Ulrich <address@hidden>
+
+// This source code has been donated to the Public Domain. Do
+// whatever you want with it.
+
+// Utility kd-tree structure, for building kd-trees from triangle
+// soup.
+
+
+#include <stdio.h>
+
+#include "kd_tree_dynamic.h"
+#include "tu_file.h"
+#include <float.h>
+
+
+static const float EPSILON = 1e-4f;
+static const int LEAF_FACE_COUNT = 6;
+static const int MAX_SPLIT_PLANES_TESTED = 10;
+
+//#define CARVE_OFF_SPACE
+//#define ADHOC_METRIC
+#define MACDONALD_AND_BOOTH_METRIC
+//#define SORT_VERTICES
+
+// A higher value for MAX_SPLIT_PLANES_TESTED gives faster trees;
+// e.g. on one dataset, MSPT=100 gives 10% faster queries than
+// MSPT=10. But the tree building is much slower.
+
+// On one dataset I checked, SORT_VERTICES makes queries ~10% faster.
+// On most others, it seemed to make no difference. It takes extra
+// time to do the sort, though.
+
+
+float kd_tree_dynamic::face::get_min_coord(int axis, const std::vector<vec3>&
verts) const
+{
+ float minval = verts[m_vi[0]][axis];
+ minval = fmin(minval, verts[m_vi[1]][axis]);
+ minval = fmin(minval, verts[m_vi[2]][axis]);
+ return minval;
+}
+
+
+float kd_tree_dynamic::face::get_max_coord(int axis, const std::vector<vec3>&
verts) const
+{
+ float maxval = verts[m_vi[0]][axis];
+ maxval = fmax(maxval, verts[m_vi[1]][axis]);
+ maxval = fmax(maxval, verts[m_vi[2]][axis]);
+ return maxval;
+}
+
+
+void split_mesh(
+ std::vector<vec3>* verts0,
+ std::vector<int>* tris0,
+ std::vector<vec3>* verts1,
+ std::vector<int>* tris1,
+ int vert_count,
+ const vec3 verts[],
+ int triangle_count,
+ const int indices[],
+ int axis,
+ float offset)
+// Divide a mesh into two pieces, roughly along the plane [axis]=offset.
+// Assign faces to one side or the other based on centroid.
+{
+ assert(verts0 && tris0 && verts1 && tris1);
+ assert(verts0->size() == 0);
+ assert(tris0->size() == 0);
+ assert(verts1->size() == 0);
+ assert(tris1->size() == 0);
+
+ // Remap table from verts array to new verts0/1 arrays.
+ hash<int, int> verts_to_verts0;
+ hash<int, int> verts_to_verts1;
+
+ // Divide the faces.
+ for (int i = 0; i < triangle_count; i++)
+ {
+ int index = i * 3;
+ int v[3] = {
+ indices[index],
+ indices[index + 1],
+ indices[index + 2]
+ };
+
+ float centroid = (verts[v[0]][axis] + verts[v[1]][axis] +
verts[v[2]][axis]) / 3.0f;
+
+ if (centroid < offset)
+ {
+ // Put this face into verts0/tris0
+ for (int ax = 0; ax < 3; ax++)
+ {
+ int new_index;
+ if (verts_to_verts0.get(v[ax], &new_index))
+ {
+ // OK.
+ }
+ else
+ {
+ // Must add.
+ new_index = verts0->size();
+ verts_to_verts0.add(v[ax], new_index);
+ verts0->push_back(verts[v[ax]]);
+ }
+ tris0->push_back(new_index);
+ }
+ }
+ else
+ {
+ // Put this face into verts1/tris1
+ for (int ax = 0; ax < 3; ax++)
+ {
+ int new_index;
+ if (verts_to_verts1.get(v[ax], &new_index))
+ {
+ // OK.
+ }
+ else
+ {
+ // Must add.
+ new_index = verts1->size();
+ verts_to_verts1.add(v[ax], new_index);
+ verts1->push_back(verts[v[ax]]);
+ }
+ tris1->push_back(new_index);
+ }
+ }
+ }
+}
+
+
+static void remap_vertex_order(kd_tree_dynamic::node* node, hash<int,int>*
map_indices_old_to_new, int* new_vertex_count)
+// Traverse this tree in depth-first order, and remap the vertex
+// indices to go in order.
+{
+ if (node == NULL) return;
+
+ if (node->m_leaf)
+ {
+ for (int i = 0, n = node->m_leaf->m_faces.size(); i < n; i++)
+ {
+ kd_tree_dynamic::face* f = &node->m_leaf->m_faces[i];
+ for (int vi = 0; vi < 3; vi++)
+ {
+ int old_index = f->m_vi[vi];
+ int new_index = *new_vertex_count;
+ if (map_indices_old_to_new->get(old_index,
&new_index))
+ {
+ // vert is already remapped; use
existing mapping.
+ }
+ else
+ {
+ // vert is not remapped yet; remap it.
+ map_indices_old_to_new->add(old_index,
new_index);
+ (*new_vertex_count) += 1;
+ }
+
+ // Remap.
+ f->m_vi[vi] = new_index;
+ }
+ }
+ }
+ else
+ {
+ remap_vertex_order(node->m_neg, map_indices_old_to_new,
new_vertex_count);
+ remap_vertex_order(node->m_pos, map_indices_old_to_new,
new_vertex_count);
+ }
+}
+
+
+/*static*/ void kd_tree_dynamic::build_trees(
+ std::vector<kd_tree_dynamic*>* treelist,
+ int vert_count,
+ const vec3 verts[],
+ int triangle_count,
+ const int indices[]
+ )
+// Build one or more kd trees to represent the given mesh.
+{
+ if (vert_count >= 65536)
+ {
+ // Too many verts for one tree; subdivide.
+ axial_box bound;
+ compute_actual_bounds(&bound, vert_count, verts);
+
+ int longest_axis = bound.get_longest_axis();
+ float offset = bound.get_center()[longest_axis];
+
+ std::vector<vec3> verts0, verts1;
+ std::vector<int> tris0, tris1;
+ split_mesh(
+ &verts0,
+ &tris0,
+ &verts1,
+ &tris1,
+ vert_count,
+ verts,
+ triangle_count,
+ indices,
+ longest_axis,
+ offset);
+
+ if ((int) verts0.size() >= vert_count || (int) verts1.size() >=
vert_count)
+ {
+ // Trouble: couldn't reduce vert count by
+ // splitting.
+ assert(0);
+ // log error
+ return;
+ }
+
+ build_trees(treelist, verts0.size(), &verts0[0], tris0.size() /
3, &tris0[0]);
+ build_trees(treelist, verts1.size(), &verts1[0], tris1.size() /
3, &tris1[0]);
+
+ return;
+ }
+
+ treelist->push_back(new kd_tree_dynamic(vert_count, verts,
triangle_count, indices));
+}
+
+
+kd_tree_dynamic::kd_tree_dynamic(
+ int vert_count,
+ const vec3 verts[],
+ int triangle_count,
+ const int indices[])
+// Constructor; build the kd-tree from the given triangle soup.
+{
+ assert(vert_count > 0 && vert_count < 65536);
+ assert(triangle_count > 0);
+
+ // Copy the verts.
+ m_verts.resize(vert_count);
+ memcpy(&m_verts[0], verts, sizeof(verts[0]) * vert_count);
+
+ // Make a mutable array of faces, and also compute our bounds.
+ axial_box bounds(axial_box::INVALID, vec3::flt_max,
vec3::minus_flt_max);
+ std::vector<face> faces;
+ for (int i = 0; i < triangle_count; i++)
+ {
+ face f;
+ f.m_vi[0] = indices[i * 3 + 0];
+ f.m_vi[1] = indices[i * 3 + 1];
+ f.m_vi[2] = indices[i * 3 + 2];
+ f.m_flags = 0; // @@ should be a way to initialize this
+
+ faces.push_back(f);
+
+ // Update bounds.
+ bounds.set_enclosing(m_verts[f.m_vi[0]]);
+ bounds.set_enclosing(m_verts[f.m_vi[1]]);
+ bounds.set_enclosing(m_verts[f.m_vi[2]]);
+ }
+
+ m_bound = bounds;
+
+ m_root = build_tree(1, faces.size(), &faces[0], bounds);
+
+#ifdef SORT_VERTICES
+ // Sort vertices in the order they first appear in a
+ // depth-first traversal of the tree. Idea is to exploit
+ // cache coherency when traversing tree.
+
+ hash<int, int> map_indices_old_to_new;
+ int new_vertex_count = 0;
+ remap_vertex_order(m_root, &map_indices_old_to_new, &new_vertex_count);
+
+ assert(new_vertex_count == m_verts.size());
+
+ // Make the re-ordered vertex buffer.
+ std::vector<vec3> new_verts;
+ new_verts.resize(new_vertex_count);
+ for (int i = 0; i < m_verts.size(); i++)
+ {
+ int new_index = 0;
+ bool found = map_indices_old_to_new.get(i, &new_index);
+ assert(found);
+ if (found)
+ {
+ new_verts[new_index] = m_verts[i];
+ }
+ }
+
+ // Use the new verts.
+ m_verts = new_verts;
+#endif // SORT_VERTICES
+}
+
+
+kd_tree_dynamic::~kd_tree_dynamic()
+// Destructor; make sure to delete the stuff we allocated.
+{
+ delete m_root;
+}
+
+
+kd_tree_dynamic::node* kd_tree_dynamic::build_tree(int depth, int face_count,
face faces[], const axial_box& bounds)
+// Recursively build a kd-tree from the given set of faces. Return
+// the root of the tree.
+{
+ assert(face_count >= 0);
+
+ if (face_count == 0)
+ {
+ return NULL;
+ }
+
+ // Should we make a leaf?
+ if (face_count <= LEAF_FACE_COUNT)
+ {
+ // Make a leaf
+ node* n = new node;
+ n->m_leaf = new leaf;
+ n->m_leaf->m_faces.resize(face_count);
+ memcpy(&(n->m_leaf->m_faces[0]), faces, sizeof(faces[0]) *
face_count);
+
+ return n;
+ }
+
+ // TODO I believe it may be better to try partitioning planes,
+ // which separate the faces according to triangle centroid (or
+ // centroid of the bound?), and then compute the actual
+ // splitting planes based on the partition. I think this
+ // helps avoid some bad situations with large triangles, where
+ // a large tri keeps getting pushed down deeper and deeper.
+ //
+ // Currently we generate a candidate neg_offset plane
+ // directly, and include all triangles fully behind the
+ // neg_offset in one child, which may tend to be unbalanced.
+
+ // Find a good splitting plane.
+ float best_split_quality = 0.0f;
+ int best_split_axis = -1;
+ float best_split_neg_offset = 0.0f;
+ float best_split_pos_offset = 0.0f;
+
+ for (int axis = 0; axis < 3; axis++)
+ {
+ if (bounds.get_extent()[axis] < EPSILON)
+ {
+ // Don't try to divide
+ continue;
+ }
+
+ // Try offsets that correspond to existing face boundaries.
+ int step_size = 1;
+ if (face_count > MAX_SPLIT_PLANES_TESTED)
+ {
+ // For the sake of speed & sanity, only try the bounds
+ // of every N faces.
+ step_size = face_count / MAX_SPLIT_PLANES_TESTED;
+ }
+ assert(step_size > 0);
+
+ float last_offset_tried = -FLT_MAX;
+ float pos_offset = 0;
+ for (int i = 0; i < face_count; i += step_size)
+ {
+ float neg_offset = faces[i].get_max_coord(axis,
m_verts);
+
+ if (fabsf(neg_offset - last_offset_tried) < EPSILON)
+ {
+ // Already tried this.
+ continue;
+ }
+
+ last_offset_tried = neg_offset;
+
+ // How good is this split?
+ float quality = evaluate_split(depth, face_count,
faces, bounds, axis, neg_offset, &pos_offset);
+ if (quality > best_split_quality)
+ {
+ // Best so far.
+ best_split_quality = quality;
+ best_split_axis = axis;
+ best_split_neg_offset = neg_offset;
+ best_split_pos_offset = pos_offset;
+ }
+ }
+ }
+
+ if (best_split_axis == -1)
+ {
+ // Couldn't find any acceptable split!
+ // Make a leaf.
+ node* n = new node;
+ n->m_leaf = new leaf;
+ n->m_leaf->m_faces.resize(face_count);
+ memcpy(&(n->m_leaf->m_faces[0]), faces, sizeof(faces[0]) *
face_count);
+
+ return n;
+ }
+ else
+ {
+ // Make the split.
+ int back_end = 0;
+ int front_end = 0;
+
+ // We use the implicit node bounds, not the actual bounds of
+ // the face sets, for computing split quality etc, since that
+ // is what the run-time structures have when they are
+ // computing query results.
+
+ axial_box back_bounds(bounds);
+ back_bounds.set_axis_max(best_split_axis,
best_split_neg_offset);
+
+ axial_box front_bounds(bounds);
+ front_bounds.set_axis_min(best_split_axis,
best_split_pos_offset);
+
+ node* n = new node;
+ n->m_axis = best_split_axis;
+ n->m_neg_offset = best_split_neg_offset;
+ n->m_pos_offset = best_split_pos_offset;
+
+ // Recursively build sub-trees.
+ do_split(&back_end, &front_end, face_count, faces,
best_split_axis, best_split_neg_offset, best_split_pos_offset);
+
+ n->m_neg = build_tree(depth + 1, back_end, faces + 0,
back_bounds);
+ n->m_pos = build_tree(depth + 1, front_end - back_end, faces +
back_end, front_bounds);
+
+ return n;
+ }
+}
+
+
+kd_tree_dynamic::node::node()
+// Default constructor, null everything out.
+ :
+ m_neg(0),
+ m_pos(0),
+ m_leaf(0),
+ m_axis(0),
+ m_neg_offset(0.0f),
+ m_pos_offset(0.0f)
+{
+}
+
+
+kd_tree_dynamic::node::~node()
+// Destructor, delete children if any.
+{
+ delete m_neg;
+ delete m_pos;
+ delete m_leaf;
+}
+
+
+bool kd_tree_dynamic::node::is_valid() const
+{
+ return
+ // internal node.
+ (m_leaf == 0
+ && m_axis >= 0
+ && m_axis < 3)
+ ||
+ // leaf node
+ (m_leaf != 0
+ && m_neg == 0
+ && m_pos == 0)
+ ;
+}
+
+
+void kd_tree_dynamic::compute_actual_bounds(axial_box* result, int
face_count, face faces[])
+// Compute the actual bounding box around the given list of faces.
+{
+ assert(face_count > 0);
+
+ result->set_min_max_invalid(vec3::flt_max, vec3::minus_flt_max);
+
+ for (int i = 0; i < face_count; i++)
+ {
+ const face& f = faces[i];
+
+ // Update bounds.
+ result->set_enclosing(m_verts[f.m_vi[0]]);
+ result->set_enclosing(m_verts[f.m_vi[1]]);
+ result->set_enclosing(m_verts[f.m_vi[2]]);
+ }
+}
+
+
+/*static*/ void kd_tree_dynamic::compute_actual_bounds(axial_box*
result, int vert_count, const vec3 verts[])
+// Compute the actual bounding box around the given list of faces.
+{
+ assert(vert_count > 0);
+
+ result->set_min_max_invalid(vec3::flt_max, vec3::minus_flt_max);
+
+ for (int i = 0; i < vert_count; i++)
+ {
+ // Update bounds.
+ result->set_enclosing(verts[i]);
+ }
+}
+
+
+static int classify_coord(float coord, float offset)
+{
+ if (coord < offset /* - EPSILON */)
+ {
+ return -1;
+ }
+ else if (coord > offset /* + EPSILON */)
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+
+void kd_tree_dynamic::do_split(
+ int* back_end,
+ int* front_end,
+ int face_count,
+ face faces[],
+ int axis,
+ float neg_offset,
+ float pos_offset)
+// Classify the given faces as either negative or positive. The faces
+// within faces[] are shuffled. On exit, the faces[] array has the
+// following segments:
+//
+// [0, *neg_end-1] -- the faces behind the plane axis=neg_offset
+// [neg_end, face_count-1] -- the faces in front of axis=pos_offset (i.e.
everything else)
+//
+// pos_offset must be placed so that it catches everything not on the
+// negative side; this routine asserts against that.
+{
+ // We do an in-place sort. During sorting, faces[] is divided
+ // into three segments: at the beginning are the front faces,
+ // in the middle are the unsorted faces, and at the end are
+ // the back faces. when we sort a face, we swap it into the
+ // next position for either the back or front face segment.
+ int back_faces_end = 0;
+ int front_faces_start = face_count;
+ //int next_face = 0;
+
+ while (back_faces_end < front_faces_start)
+ {
+ const face& f = faces[back_faces_end];
+
+ int result = classify_face(f, axis, neg_offset);
+ if (result == -1)
+ {
+ // Behind. Leave this face where it is, and
+ // bump back_faces_end so it's now in the back
+ // faces segment.
+ back_faces_end++;
+ }
+ else
+ {
+ // In front.
+ assert(f.get_min_coord(axis, m_verts) >= pos_offset);
// should not have any crossing faces!
+
+ // Swap this face up to the beginning of the front
faces.
+ front_faces_start--;
+ swap(&faces[back_faces_end], &faces[front_faces_start]);
+ }
+ }
+
+ *back_end = back_faces_end;
+ *front_end = face_count;
+ assert(*back_end <= *front_end);
+ assert(*front_end == face_count);
+
+#if 0
+ std::vector<face> back_faces;
+ std::vector<face> front_faces;
+
+ for (int i = 0; i < face_count; i++)
+ {
+ const face& f = faces[i];
+
+ int result = classify_face(f, axis, neg_offset);
+ if (result == -1)
+ {
+ // Behind.
+ back_faces.push_back(f);
+ }
+ else
+ {
+ assert(f.get_min_coord(axis, m_verts) >= pos_offset);
// should not have any crossing faces!
+
+ front_faces.push_back(f);
+ }
+ }
+
+ assert(back_faces.size() + front_faces.size() == face_count);
+
+ *back_end = back_faces.size();
+ if (back_faces.size() > 0)
+ {
+ memcpy(&(faces[0]), &(back_faces[0]), back_faces.size() *
sizeof(faces[0]));
+ }
+
+ *front_end = *back_end + front_faces.size();
+ if (front_faces.size() > 0)
+ {
+ memcpy(&faces[*back_end], &front_faces[0], front_faces.size() *
sizeof(faces[0]));
+ }
+
+ assert(*back_end <= *front_end);
+ assert(*front_end == face_count);
+#endif // 0
+}
+
+
+float kd_tree_dynamic::evaluate_split(
+ int depth,
+ int face_count,
+ face faces[],
+ const axial_box& bounds,
+ int axis,
+ float neg_offset,
+ float* pos_offset)
+// Compute the "value" of splitting the given set of faces, bounded by
+// the given box, along the plane [axis]=offset. A value of 0 means
+// that a split is possible, but has no value. A negative value means
+// that the split is not valid at all. Positive values indicate
+// increasing goodness.
+//
+// *pos_offset is computed based on the minimum coord of the faces
+// that don't fit behind the neg_offset. Could be greater or less
+// than neg_offset.
+//
+// This is kinda heuristicy -- it's where the "special sauce" comes
+// in.
+{
+ // Count the faces that will end up in the groups
+ // back,front.
+ int back_count = 0;
+ int front_count = 0;
+
+ *pos_offset = bounds.get_max()[axis];
+
+ for (int i = 0; i < face_count; i++)
+ {
+ const face& f = faces[i];
+
+ int result = classify_face(f, axis, neg_offset);
+ if (result == -1)
+ {
+ // Neg.
+ back_count++;
+ }
+ else
+ {
+ // Pos.
+ front_count++;
+
+ // Update *pos_offset so it contains this face.
+ float mincoord = f.get_min_coord(axis, m_verts);
+ if (mincoord < *pos_offset)
+ {
+ *pos_offset = mincoord;
+ assert(mincoord >= bounds.get_min()[axis]);
+ }
+ }
+ }
+
+ if ((back_count == 0 && *pos_offset - EPSILON <= bounds.get_min()[axis])
+ || (front_count == 0 && neg_offset + EPSILON >=
bounds.get_max()[axis]))
+ {
+ // No faces are separated by this split; this split is
+ // entirely useless.
+ return -1;
+ }
+
+ //float center = bounds.get_center().get(axis);
+ //float extent = bounds.get_extent().get(axis);
+
+ axial_box back_bounds(bounds);
+ back_bounds.set_axis_max(axis, neg_offset);
+ axial_box front_bounds(bounds);
+ front_bounds.set_axis_min(axis, *pos_offset);
+
+// Probably not a win.
+#ifdef CARVE_OFF_SPACE
+ // Special case: if the plane carves off space at one side or the
+ // other, without orphaning any faces, then we reward a large
+ // empty space.
+ float space_quality = 0.0f;
+ if (front_count == 0)
+ {
+ // All the faces are in back -- reward a bigger empty front
volume.
+ return space_quality = back_count *
front_bounds.get_surface_area();
+ }
+ else if (back_count == 0)
+ {
+ // All the faces are in front.
+ return space_quality = front_count *
back_bounds.get_surface_area();
+ }
+#endif // CARVE_OFF_SPACE
+
+
+// My ad-hoc metric
+#ifdef ADHOC_METRIC
+ // compute a figure for how close to the center this splitting
+ // plane is. Normalize in [0,1].
+ float volume_balance = 1.0f - fabsf(center - (neg_offset +
*pos_offset) / 2) / extent;
+
+ // Compute a figure for how well we balance the faces. 0 == bad,
+ // 1 == good.
+ float face_balance = 1.0f - (fabsf(float(front_count - back_count)))
/ face_count;
+
+ float split_quality = bounds.get_surface_area() * volume_balance *
face_balance;
+
+ return split_quality;
+#endif // ADHOC_METRIC
+
+
+#ifdef MACDONALD_AND_BOOTH_METRIC
+ // MacDonald and Booth's metric, as quoted by Havran, endorsed by
+ // Ville Miettinen and Atman Binstock:
+
+ float cost_back = back_bounds.get_surface_area() * (back_count);
+ float cost_front = front_bounds.get_surface_area() * (front_count);
+
+ float havran_cost = cost_back + cost_front;
+
+ float parent_cost = bounds.get_surface_area() * face_count;
+
+ // We need to turn the cost into a quality, so subtract it from a
+ // big number.
+ return parent_cost - havran_cost;
+
+#endif // MACDONALD_AND_BOOTH_METRIC
+}
+
+
+int kd_tree_dynamic::classify_face(const face& f, int axis, float offset)
+// Return -1 if the face is entirely behind the plane [axis]=offset
+// Return 0 if the face spans the plane.
+// Return 1 if the face is entirely in front of the plane.
+//
+// "behind" means on the negative side, "in front" means on the
+// positive side.
+{
+ assert(axis >= 0 && axis < 3);
+
+ bool has_front_vert = false;
+ bool has_back_vert = false;
+
+ for (int i = 0; i < 3; i++)
+ {
+ float coord = m_verts[f.m_vi[i]].get(axis);
+ int cr = classify_coord(coord, offset);
+
+ if (cr == -1)
+ {
+ has_back_vert = true;
+ }
+ else if (cr == 1)
+ {
+ has_front_vert = true;
+ }
+ }
+
+ if (has_front_vert && has_back_vert)
+ {
+ return 0; // crossing.
+ }
+ else if (has_front_vert)
+ {
+ return 1; // all verts in front.
+ }
+ else if (has_back_vert)
+ {
+ return -1; // all verts in back.
+ }
+ else
+ {
+ // Face is ON the plane.
+ return 0; // call it "crossing".
+ }
+}
+
+
+void kd_tree_dynamic::clip_faces(std::vector<face>* faces, int axis, float
offset)
+// Clip the given faces against the plane [axis]=offset. Update the
+// *faces array with the newly clipped faces; add faces and verts as
+// necessary.
+{
+ int original_face_count = faces->size();
+
+ for (int i = 0; i < original_face_count; i++)
+ {
+ face f = (*faces)[i];
+
+ if (classify_face(f, axis, offset) == 0)
+ {
+ // Crossing face, probably needs to be clipped.
+
+ int vr[3];
+ vr[0] = classify_coord(m_verts[f.m_vi[0]].get(axis),
offset);
+ vr[1] = classify_coord(m_verts[f.m_vi[1]].get(axis),
offset);
+ vr[2] = classify_coord(m_verts[f.m_vi[2]].get(axis),
offset);
+
+ // Sort...
+ if (vr[0] > vr[1])
+ {
+ swap(&vr[0], &vr[1]);
+ swap(&f.m_vi[0], &f.m_vi[1]);
+ }
+ if (vr[1] > vr[2])
+ {
+ swap(&vr[1], &vr[2]);
+ swap(&f.m_vi[1], &f.m_vi[2]);
+ }
+ if (vr[0] > vr[1])
+ {
+ swap(&vr[0], &vr[1]);
+ swap(&f.m_vi[0], &f.m_vi[1]);
+ }
+
+ if (vr[0] == 0 || vr[2] == 0)
+ {
+ // Face doesn't actually cross; no need to clip.
+ continue;
+ }
+
+ const vec3 v[3] = {
+ m_verts[f.m_vi[0]],
+ m_verts[f.m_vi[1]],
+ m_verts[f.m_vi[2]]
+ };
+
+ // Different cases.
+ if (vr[1] == 0)
+ {
+ // Middle vert is on the plane; make two
triangles.
+
+ // One new vert.
+ float lerper = (offset - v[0].get(axis)) /
(v[2].get(axis) - v[0].get(axis));
+ vec3 new_vert = v[0] * (1 - lerper) + v[2] *
lerper;
+ new_vert.set(axis, offset); // make damn
sure
+ assert(new_vert.checknan() == false);
+
+ int new_vi = m_verts.size();
+ m_verts.push_back(new_vert);
+
+ // New faces.
+ face f0 = f;
+ f0.m_vi[2] = new_vi;
+ (*faces)[i] = f0; // replace original face
+
+ assert(classify_face(f0, axis, offset) <= 0);
+
+ face f1 = f;
+ f1.m_vi[0] = new_vi;
+ faces->push_back(f1); // add a face
+
+ assert(classify_face(f1, axis, offset) >= 0);
+ }
+ else if (vr[1] < 0)
+ {
+ // Middle vert is behind the plane.
+ // Make two tris behind, one in front.
+
+ // Two new verts.
+ float lerper0 = (offset - v[0].get(axis)) /
(v[2].get(axis) - v[0].get(axis));
+ vec3 new_vert0 = v[0] * (1 - lerper0) + v[2]
* lerper0;
+ new_vert0.set(axis, offset); // make damn
sure
+ assert(new_vert0.checknan() == false);
+ int new_vi0 = m_verts.size();
+ m_verts.push_back(new_vert0);
+
+ float lerper1 = (offset - v[1].get(axis)) /
(v[2].get(axis) - v[1].get(axis));
+ vec3 new_vert1 = v[1] * (1 - lerper1) + v[2]
* lerper1;
+ new_vert1.set(axis, offset); // make damn
sure
+ assert(new_vert1.checknan() == false);
+ int new_vi1 = m_verts.size();
+ m_verts.push_back(new_vert1);
+
+ // New faces.
+ face f0 = f;
+ f0.m_vi[2] = new_vi0;
+ (*faces)[i] = f0;
+
+ assert(classify_face(f0, axis, offset) <= 0);
+
+ face f1 = f;
+ f1.m_vi[0] = new_vi0;
+ f1.m_vi[2] = new_vi1;
+ faces->push_back(f1);
+
+ assert(classify_face(f1, axis, offset) <= 0);
+
+ face f2 = f;
+ f2.m_vi[0] = new_vi0;
+ f2.m_vi[1] = new_vi1;
+ faces->push_back(f2);
+
+ assert(classify_face(f2, axis, offset) >= 0);
+ }
+ else if (vr[1] > 0)
+ {
+ // Middle vert is in front of the plane.
+ // Make on tri behind, two in front.
+
+ // Two new verts.
+ float lerper1 = (offset - v[0].get(axis)) /
(v[1].get(axis) - v[0].get(axis));
+ vec3 new_vert1 = v[0] * (1 - lerper1) + v[1]
* lerper1;
+ new_vert1.set(axis, offset); // make damn
sure
+ assert(new_vert1.checknan() == false);
+ int new_vi1 = m_verts.size();
+ m_verts.push_back(new_vert1);
+
+ float lerper2 = (offset - v[0].get(axis)) /
(v[2].get(axis) - v[0].get(axis));
+ vec3 new_vert2 = v[0] * (1 - lerper2) + v[2]
* lerper2;
+ new_vert2.set(axis, offset); // make damn
sure
+ assert(new_vert2.checknan() == false);
+ int new_vi2 = m_verts.size();
+ m_verts.push_back(new_vert2);
+
+ // New faces.
+ face f0 = f;
+ f0.m_vi[1] = new_vi1;
+ f0.m_vi[2] = new_vi2;
+ (*faces)[i] = f0;
+
+ assert(classify_face(f0, axis, offset) <= 0);
+
+ face f1 = f;
+ f1.m_vi[0] = new_vi1;
+ f1.m_vi[2] = new_vi2;
+ faces->push_back(f1);
+
+ assert(classify_face(f1, axis, offset) >= 0);
+
+ face f2 = f;
+ f2.m_vi[0] = new_vi2;
+ faces->push_back(f2);
+
+ assert(classify_face(f2, axis, offset) >= 0);
+ }
+ }
+
+ }
+}
+
+
+void kd_tree_dynamic::dump(tu_file* out) const
+// Dump some debug info.
+{
+ node* n = m_root;
+
+ if (n) n->dump(out, 0);
+}
+
+
+void kd_tree_dynamic::node::dump(tu_file* out, int depth) const
+{
+ for (int i = 0; i < depth; i++) { out->write_byte(' '); }
+
+ if (m_leaf)
+ {
+ int face_count = m_leaf->m_faces.size();
+ char c = ("0123456789X")[iclamp(face_count, 0, 10)];
+ out->write_byte(c);
+ out->write_byte('\n');
+ }
+ else
+ {
+ out->write_byte('+');
+ out->write_byte('\n');
+ if (m_neg)
+ {
+ m_neg->dump(out, depth + 1);
+ }
+ if (m_pos)
+ {
+ m_pos->dump(out, depth + 1);
+ }
+ }
+}
+
+
+#include "postscript.h"
+
+
+static const int X_SIZE = 612;
+static const int Y_SIZE = 792;
+static const int MARGIN = 20;
+
+
+struct kd_diagram_dump_info
+{
+ postscript* m_ps;
+ int m_depth;
+ int m_max_depth;
+ std::vector<int> m_width; // width of the tree at each
level
+ std::vector<int> m_max_width;
+ std::vector<int> m_count; // width so far, during drawing
+
+ // Some stats.
+ int m_leaf_count;
+ int m_node_count;
+ int m_face_count;
+ int m_max_faces_in_leaf;
+ int m_null_children;
+ int m_depth_times_faces;
+
+ kd_diagram_dump_info()
+ :
+ m_ps(0),
+ m_depth(0),
+ m_max_depth(0),
+ m_leaf_count(0),
+ m_node_count(0),
+ m_face_count(0),
+ m_max_faces_in_leaf(0),
+ m_null_children(0),
+ m_depth_times_faces(0)
+ {
+ }
+
+ void get_node_coords(int* x, int* y)
+ {
+ float h_spacing = (X_SIZE - MARGIN*2) /
float(m_max_width.back());
+ float adjust = 1.0f;
+ if (m_width[m_depth] > 1) adjust = (m_max_width[m_depth] + 1) /
float(m_width[m_depth] + 1);
+
+ *x = int(X_SIZE/2 + (m_count[m_depth] - m_width[m_depth] / 2) *
h_spacing * adjust);
+ *y = Y_SIZE - MARGIN - m_depth * (Y_SIZE - MARGIN*2) /
(m_max_depth + 1);
+ }
+
+ void update_stats(kd_tree_dynamic::node* n)
+ // Add this node's stats to our totals.
+ {
+ if (n == 0)
+ {
+ m_null_children++;
+ }
+ else if (n->m_leaf)
+ {
+ m_leaf_count++;
+
+ assert(n->m_leaf);
+ int faces = n->m_leaf->m_faces.size();
+ m_face_count += faces;
+ if (faces > m_max_faces_in_leaf) m_max_faces_in_leaf =
faces;
+
+ m_depth_times_faces += (m_depth + 1) * faces;
+ }
+ else
+ {
+ m_node_count++;
+ }
+ }
+
+ void diagram_stats()
+ // Print some textual stats to the given Postscript stream.
+ {
+ float x = MARGIN;
+ float y = Y_SIZE - MARGIN;
+ const float LINE = 10;
+ y -= LINE; m_ps->printf(x, y, "Loose KD-Tree");
+#ifdef MACDONALD_AND_BOOTH_METRIC
+ y -= LINE; m_ps->printf(x, y, "using MacDonald and Booth
metric");
+#endif
+#ifdef ADHOC_METRIC
+ y -= LINE; m_ps->printf(x, y, "using ad-hoc metric");
+#endif
+#ifdef CARVE_OFF_SPACE
+ y -= LINE; m_ps->printf(x, y, "using carve-off-space
heuristic");
+#endif
+ y -= LINE; m_ps->printf(x, y, "leaf face count limit: %d",
LEAF_FACE_COUNT);
+ y -= LINE; m_ps->printf(x, y, "face ct: %d", m_face_count);
+ y -= LINE; m_ps->printf(x, y, "leaf ct: %d", m_leaf_count);
+ y -= LINE; m_ps->printf(x, y, "node ct: %d", m_node_count);
+ y -= LINE; m_ps->printf(x, y, "null ct: %d", m_null_children);
+ y -= LINE; m_ps->printf(x, y, "worst leaf: %d faces",
m_max_faces_in_leaf);
+ y -= LINE; m_ps->printf(x, y, "max depth: %d", m_max_depth + 1);
+ y -= LINE; m_ps->printf(x, y, "avg face depth: %3.2f",
m_depth_times_faces / float(m_face_count));
+ }
+};
+
+
+static void node_traverse(kd_diagram_dump_info* inf, kd_tree_dynamic::node*
n)
+// Traverse the tree, updating inf->m_width. That's helpful for
+// formatting the diagram.
+{
+ inf->update_stats(n);
+
+ if (inf->m_depth > inf->m_max_depth)
+ {
+ inf->m_max_depth = inf->m_depth;
+ }
+
+ while ((int) inf->m_width.size() <= inf->m_max_depth)
+ {
+ inf->m_width.push_back(0);
+ }
+
+ inf->m_width[inf->m_depth]++; // count this node.
+
+ if (n && n->m_leaf == 0)
+ {
+ // Count children.
+ inf->m_depth++;
+ node_traverse(inf, n->m_neg);
+ node_traverse(inf, n->m_pos);
+ inf->m_depth--;
+
+ assert(inf->m_depth >= 0);
+ }
+}
+
+
+static void node_diagram(kd_diagram_dump_info* inf, kd_tree_dynamic::node*
n, int parent_x, int parent_y)
+// Emit Postscript drawing commands to diagram this node in the tree.
+{
+ // Diagram this node.
+ int x, y;
+ inf->get_node_coords(&x, &y);
+
+ // Line to parent.
+ inf->m_ps->line((float) x, (float) y, (float) parent_x, (float)
parent_y);
+
+ if (n == 0)
+ {
+ // NULL --> show a circle w/ slash
+ inf->m_ps->circle((float) x, (float) y, 1);
+ inf->m_ps->line((float) x + 1, (float) y + 1, (float) x - 1,
(float) y - 1);
+ }
+ else if (n->m_leaf)
+ {
+ // Leaf. Draw concentric circles.
+ int face_count = n->m_leaf->m_faces.size();
+ for (int i = 0; i < face_count + 1; i++)
+ {
+ inf->m_ps->circle((float) x, (float) y, 2 + i * 1.0f);
+ }
+ }
+ else
+ {
+ // Internal node.
+
+ // draw disk
+ inf->m_ps->disk((float) x, (float) y, 1);
+
+ // draw children.
+ inf->m_depth++;
+ node_diagram(inf, n->m_neg, x, y);
+ node_diagram(inf, n->m_pos, x, y);
+ inf->m_depth--;
+
+ assert(inf->m_depth >= 0);
+ }
+
+ // count this node.
+ inf->m_count[inf->m_depth]++;
+}
+
+
+void kd_tree_dynamic::diagram_dump(tu_file* out) const
+// Generate a Postscript schematic diagram of the tree.
+{
+ postscript* ps = new postscript(out, "kd-tree diagram");
+
+ kd_diagram_dump_info inf;
+ inf.m_ps = ps;
+ inf.m_depth = 0;
+
+ node_traverse(&inf, m_root);
+
+ while ((int) inf.m_count.size() <= inf.m_max_depth)
+ {
+ inf.m_count.push_back(0);
+ }
+
+ int max_width = 1;
+ for (int i = 0; i <= inf.m_max_depth; i++)
+ {
+ if (inf.m_width[i] > max_width)
+ {
+ max_width = inf.m_width[i];
+ }
+ inf.m_max_width.push_back(max_width);
+ }
+
+ inf.diagram_stats();
+
+ int root_x = 0, root_y = 0;
+ inf.get_node_coords(&root_x, &root_y);
+
+ node_diagram(&inf, m_root, root_x, root_y);
+
+ delete ps;
+}
+
+
+static void mesh_node_dump(
+ postscript* ps,
+ int axis,
+ kd_tree_dynamic::node* node,
+ const axial_box& bound,
+ const std::vector<vec3>& verts)
+// Draw faces under node, projected onto given axis plane. Scale to fit paper.
+{
+ if (node == NULL) return;
+
+ if (node->m_leaf)
+ {
+ // Draw faces.
+ for (int i = 0, n = node->m_leaf->m_faces.size(); i < n; i++)
+ {
+ vec3 v[3] = {
+ verts[node->m_leaf->m_faces[i].m_vi[0]],
+ verts[node->m_leaf->m_faces[i].m_vi[1]],
+ verts[node->m_leaf->m_faces[i].m_vi[2]]
+ };
+
+ float x[3], y[3];
+ int axis1 = (axis + 1) % 3;
+ int axis2 = (axis + 2) % 3;
+ for (int vert = 0; vert < 3; vert++)
+ {
+ x[vert] = (v[vert][axis1] -
bound.get_min()[axis1]) / bound.get_size()[axis1];
+ y[vert] = (v[vert][axis2] -
bound.get_min()[axis2]) / bound.get_size()[axis2];
+
+ x[vert] = flerp(float(MARGIN), float(X_SIZE -
MARGIN), x[vert]);
+ y[vert] = flerp(float(MARGIN), float(Y_SIZE -
MARGIN), y[vert]);
+ }
+
+ // Draw triangle.
+ ps->line(x[0], y[0], x[1], y[1]);
+ ps->line(x[1], y[1], x[2], y[2]);
+ ps->line(x[2], y[2], x[0], y[0]);
+ }
+
+ return;
+ }
+
+ mesh_node_dump(ps, axis, node->m_neg, bound, verts);
+ mesh_node_dump(ps, axis, node->m_pos, bound, verts);
+}
+
+
+void kd_tree_dynamic::mesh_diagram_dump(tu_file* out, int axis) const
+// Generate a Postscript schematic diagram of the mesh, orthogonal to
+// the given axis.
+{
+ postscript* ps = new postscript(out, "kd-tree diagram");
+
+ mesh_node_dump(ps, axis, m_root, get_bound(), m_verts);
+
+ delete ps;
+}
+
+
+// Local Variables:
+// mode: C++
+// c-basic-offset: 8
+// tab-width: 8
+// indent-tabs-mode: t
+// End:
Index: gnash/libgeometry/kd_tree_dynamic.h
diff -u gnash/libgeometry/kd_tree_dynamic.h:1.3
gnash/libgeometry/kd_tree_dynamic.h:1.4
--- gnash/libgeometry/kd_tree_dynamic.h:1.3 Sat Feb 25 03:54:03 2006
+++ gnash/libgeometry/kd_tree_dynamic.h Sun Feb 26 15:49:30 2006
@@ -1,150 +1,150 @@
-// kd_tree_dynamic.h -- by Thatcher Ulrich <address@hidden>
-
-// This source code has been donated to the Public Domain. Do
-// whatever you want with it.
-
-// Data structure for building a kd-tree from a triangle mesh.
-
-
-#ifndef KD_TREE_DYNAMIC_H
-#define KD_TREE_DYNAMIC_H
-
-
-#include "container.h"
-#include "geometry.h"
-#include "axial_box.h"
-
-
-class tu_file;
-struct kd_diagram_dump_info;
-
-
-struct kd_tree_dynamic
-{
- // Build tree(s) from the given mesh.
- static void build_trees(
- std::vector<kd_tree_dynamic*>* treelist,
- int vert_count,
- const vec3 verts[],
- int triangle_count,
- const int indices[]
- );
-
- // vert count must be under 64K
- kd_tree_dynamic(
- int vert_count,
- const vec3 verts[],
- int triangle_count,
- const int indices[]
- );
- ~kd_tree_dynamic();
-
- struct face
- {
- Uint16 m_vi[3]; // indices of verts
- Uint16 m_flags;
-
- float get_min_coord(int axis, const std::vector<vec3>& verts)
const;
- float get_max_coord(int axis, const std::vector<vec3>& verts)
const;
- };
-
- struct leaf
- {
- std::vector<face> m_faces;
- };
-
- // Internal node. Not too tidy; would use unions etc. if it were
- // important.
- //
- // This is a "loose" kdtree in the sense that there are two
- // independent splitting planes on the chosen axis. This
- // ensures that all faces can be classified onto one side or
- // the other. Almost the same as a binary AABB tree.
- //
- // | |
- // +--------------+---+----------------+
- // | / / \ | |/ -- \ |
- // | / / \+---/ \ \ |
- // | | --- \ | /|--\ \ / |
- // | | \ -- | / | \ / ---|
- // +--------------+---+----------------+
- // | |
- // axis *--> + neg pos
- //
- // So the idea here is that the neg node contains all faces
- // that are strictly on the negative side of the neg_offset,
- // and the pos node has all the rest of the faces, and the
- // pos_offset is placed so that all the pos node faces are
- // strictly on the positive side of pos_offset.
- //
- // Note that the pos and neg nodes could overlap, or could be
- // disjoint.
- struct node
- {
- node* m_neg;
- node* m_pos;
- leaf* m_leaf;
- int m_axis; // split axis: 0 = x, 1 = y, 2 = z
- float m_neg_offset; // where the back split occurs
- float m_pos_offset; // where the front split occurs
-
- node();
- ~node();
- bool is_valid() const;
- void dump(tu_file* out, int depth) const;
- };
-
- const std::vector<vec3>& get_verts() const { return m_verts; }
- const node* get_root() const { return m_root; }
- const axial_box& get_bound() const { return m_bound; }
-
- // For debugging/evaluating.
- void dump(tu_file* out) const;
- void diagram_dump(tu_file* out) const; // make a Postscript
diagram.
- void mesh_diagram_dump(tu_file* out, int axis) const; // make
a Postscript diagram of the mesh data.
-
-private:
- static void compute_actual_bounds(axial_box* result, int
vert_count, const vec3 verts[]);
-
- void compute_actual_bounds(axial_box* result, int face_count, face
faces[]);
- node* build_tree(int depth, int face_count, face faces[], const
axial_box& bounds);
-
- void do_split(
- int* neg_end,
- int* pos_end,
- int face_count,
- face faces[],
- int axis,
- float neg_offset,
- float pos_offset);
-
- float evaluate_split(
- int depth,
- int face_count,
- face faces[],
- const axial_box& bounds,
- int axis,
- float neg_offset,
- float* pos_offset);
-
- int classify_face(const face& f, int axis, float offset);
-
- // Utility, for testing a clipping non-loose kdtree. Duping
- // is probably much preferable to clipping though.
- void clip_faces(std::vector<face>* faces, int axis, float offset);
-
- std::vector<vec3> m_verts;
- node* m_root;
- axial_box m_bound;
-};
-
-
-#endif // KD_TREE_DYNAMIC_H
-
-
-// Local Variables:
-// mode: C++
-// c-basic-offset: 8
-// tab-width: 8
-// indent-tabs-mode: t
-// End:
+// kd_tree_dynamic.h -- by Thatcher Ulrich <address@hidden>
+
+// This source code has been donated to the Public Domain. Do
+// whatever you want with it.
+
+// Data structure for building a kd-tree from a triangle mesh.
+
+
+#ifndef KD_TREE_DYNAMIC_H
+#define KD_TREE_DYNAMIC_H
+
+
+#include "container.h"
+#include "geometry.h"
+#include "axial_box.h"
+
+
+class tu_file;
+struct kd_diagram_dump_info;
+
+
+struct kd_tree_dynamic
+{
+ // Build tree(s) from the given mesh.
+ static void build_trees(
+ std::vector<kd_tree_dynamic*>* treelist,
+ int vert_count,
+ const vec3 verts[],
+ int triangle_count,
+ const int indices[]
+ );
+
+ // vert count must be under 64K
+ kd_tree_dynamic(
+ int vert_count,
+ const vec3 verts[],
+ int triangle_count,
+ const int indices[]
+ );
+ ~kd_tree_dynamic();
+
+ struct face
+ {
+ Uint16 m_vi[3]; // indices of verts
+ Uint16 m_flags;
+
+ float get_min_coord(int axis, const std::vector<vec3>& verts)
const;
+ float get_max_coord(int axis, const std::vector<vec3>& verts)
const;
+ };
+
+ struct leaf
+ {
+ std::vector<face> m_faces;
+ };
+
+ // Internal node. Not too tidy; would use unions etc. if it were
+ // important.
+ //
+ // This is a "loose" kdtree in the sense that there are two
+ // independent splitting planes on the chosen axis. This
+ // ensures that all faces can be classified onto one side or
+ // the other. Almost the same as a binary AABB tree.
+ //
+ // | |
+ // +--------------+---+----------------+
+ // | / / \ | |/ -- \ |
+ // | / / \+---/ \ \ |
+ // | | --- \ | /|--\ \ / |
+ // | | \ -- | / | \ / ---|
+ // +--------------+---+----------------+
+ // | |
+ // axis *--> + neg pos
+ //
+ // So the idea here is that the neg node contains all faces
+ // that are strictly on the negative side of the neg_offset,
+ // and the pos node has all the rest of the faces, and the
+ // pos_offset is placed so that all the pos node faces are
+ // strictly on the positive side of pos_offset.
+ //
+ // Note that the pos and neg nodes could overlap, or could be
+ // disjoint.
+ struct node
+ {
+ node* m_neg;
+ node* m_pos;
+ leaf* m_leaf;
+ int m_axis; // split axis: 0 = x, 1 = y, 2 = z
+ float m_neg_offset; // where the back split occurs
+ float m_pos_offset; // where the front split occurs
+
+ node();
+ ~node();
+ bool is_valid() const;
+ void dump(tu_file* out, int depth) const;
+ };
+
+ const std::vector<vec3>& get_verts() const { return m_verts; }
+ const node* get_root() const { return m_root; }
+ const axial_box& get_bound() const { return m_bound; }
+
+ // For debugging/evaluating.
+ void dump(tu_file* out) const;
+ void diagram_dump(tu_file* out) const; // make a Postscript
diagram.
+ void mesh_diagram_dump(tu_file* out, int axis) const; // make
a Postscript diagram of the mesh data.
+
+private:
+ static void compute_actual_bounds(axial_box* result, int
vert_count, const vec3 verts[]);
+
+ void compute_actual_bounds(axial_box* result, int face_count, face
faces[]);
+ node* build_tree(int depth, int face_count, face faces[], const
axial_box& bounds);
+
+ void do_split(
+ int* neg_end,
+ int* pos_end,
+ int face_count,
+ face faces[],
+ int axis,
+ float neg_offset,
+ float pos_offset);
+
+ float evaluate_split(
+ int depth,
+ int face_count,
+ face faces[],
+ const axial_box& bounds,
+ int axis,
+ float neg_offset,
+ float* pos_offset);
+
+ int classify_face(const face& f, int axis, float offset);
+
+ // Utility, for testing a clipping non-loose kdtree. Duping
+ // is probably much preferable to clipping though.
+ void clip_faces(std::vector<face>* faces, int axis, float offset);
+
+ std::vector<vec3> m_verts;
+ node* m_root;
+ axial_box m_bound;
+};
+
+
+#endif // KD_TREE_DYNAMIC_H
+
+
+// Local Variables:
+// mode: C++
+// c-basic-offset: 8
+// tab-width: 8
+// indent-tabs-mode: t
+// End:
Index: gnash/macros/jpeg.m4
diff -u gnash/macros/jpeg.m4:1.7 gnash/macros/jpeg.m4:1.8
--- gnash/macros/jpeg.m4:1.7 Fri Feb 24 00:06:21 2006
+++ gnash/macros/jpeg.m4 Sun Feb 26 15:49:30 2006
@@ -85,7 +85,7 @@
dnl If the header doesn't exist, there is no point looking for the
library.
if test x"${ac_cv_path_jpeg_lib}" = x; then
- AC_CHECK_LIB(jpeg, jpeg_mem_init, [ac_cv_path_jpeg_lib="-ljpeg"],[
+ AC_CHECK_LIB(jpeg, jpeg_mem_init, [ac_cv_path_jpeg_lib=""],[
AC_MSG_CHECKING([for libjpeg library])
libslist="${prefix}/lib64 ${prefix}/lib /usr/lib64 /usr/lib /sw/lib
/usr/local/lib /home/latest/lib /opt/lib /usr/pkg/lib .. ../.."
for i in $libslist; do
@@ -121,7 +121,9 @@
fi
if test x"${ac_cv_path_jpeg_lib}" != x ; then
- JPEG_LIBS="${ac_cv_path_jpeg_lib}"
+ JPEG_LIBS="${ac_cv_path_jpeg_lib} -ljpeg"
+ else
+ JPEG_LIBS="-ljpeg"
fi
AM_CONDITIONAL(HAVE_JPEG, [test x$jpeg = xyes])
Index: gnash/macros/opengl.m4
diff -u gnash/macros/opengl.m4:1.10 gnash/macros/opengl.m4:1.11
--- gnash/macros/opengl.m4:1.10 Fri Feb 24 00:06:21 2006
+++ gnash/macros/opengl.m4 Sun Feb 26 15:49:30 2006
@@ -85,13 +85,13 @@
dnl If the header doesn't exist, there is no point looking for the library.
if test x"${ac_cv_path_opengl_libraries}" = x; then
- AC_CHECK_LIB(GL, glBegin, [ac_cv_path_opengl_libraries="-lGL -lGLU"],[
+ AC_CHECK_LIB(GL, glBegin, [ac_cv_path_opengl_libraries=""],[
AC_MSG_CHECKING([for libGL library])
libslist="${prefix}/lib64 ${prefix}/lib /usr/X11R6/lib /usr/lib64
/usr/lib /usr/local/lib /opt/lib /usr/pkg/lib .. ../.."
for i in $libslist; do
if test -f $i/libGL.a -o -f $i/libGL.so; then
if test x"$i" != x"/usr/lib"; then
- ac_cv_path_opengl_libraries="-L$i"
+ ac_cv_path_opengl_libraries="$i"
AC_MSG_RESULT(${ac_cv_path_opengl_libraries})
break
else
@@ -104,7 +104,7 @@
else
if test -f ${ac_cv_path_opengl_libraries}/libGL.a -o -f
${ac_cv_path_opengl_libraries}/libGL.so; then
if test x"${ac_cv_path_opengl_libraries}" != x"/usr/lib"; then
- ac_cv_path_opengl_libraries="-L${ac_cv_path_opengl_libraries}"
+ ac_cv_path_opengl_libraries="${ac_cv_path_opengl_libraries}"
else
ac_cv_path_opengl_libraries=""
fi
@@ -119,7 +119,9 @@
fi
if test x"${ac_cv_path_opengl_libraries}" != x ; then
- OPENGL_LIBS="${ac_cv_path_opengl_libraries}"
+ OPENGL_LIBS="-L${ac_cv_path_opengl_libraries} -lGL -lGLU"
+ else
+ OPENGL_LIBS="-lGL -lGLU"
fi
AM_CONDITIONAL(opengl, [test x$opengl = xyes])
Index: gnash/macros/png.m4
diff -u gnash/macros/png.m4:1.9 gnash/macros/png.m4:1.10
--- gnash/macros/png.m4:1.9 Fri Feb 24 00:06:21 2006
+++ gnash/macros/png.m4 Sun Feb 26 15:49:30 2006
@@ -51,25 +51,31 @@
for i in $incllist; do
if test -f $i/png.h; then
if test x"$i" != x"/usr/include"; then
- ac_cv_path_png_incl="-I$i"
+ ac_cv_path_png_incl="$i"
break
else
ac_cv_path_png_incl=""
break
fi
+ else
+dnl
+ if test -f $i/libpng/png.h; then
+ ac_cv_path_png_incl="$i/libpng"
+ break
+ fi
fi
done
fi])
else
if test x"${ac_cv_path_png_incl}" != x"/usr/include"; then
- ac_cv_path_png_incl="-I${ac_cv_path_png_incl}"
+ ac_cv_path_png_incl="${ac_cv_path_png_incl}"
else
ac_cv_path_png_incl=""
fi
fi
if test x"${ac_cv_path_png_incl}" != x ; then
- PNG_CFLAGS="${ac_cv_path_png_incl}"
+ PNG_CFLAGS="-I${ac_cv_path_png_incl}"
else
PNG_CFLAGS=""
fi
@@ -92,7 +98,7 @@
dnl If the header doesn't exist, there is no point looking for the
library.
if test x"${ac_cv_path_png_lib}" = x; then
- AC_CHECK_LIB(png, png_check_sig, [ac_cv_path_png_lib="-lpng"],[
+ AC_CHECK_LIB(png, png_check_sig, [ac_cv_path_png_lib=""],[
AC_MSG_CHECKING([for libpng library])
libslist="${prefix}/lib64 ${prefix}/lib /usr/lib64 /usr/lib /sw/lib
/usr/local/lib /home/latest/lib /opt/lib /usr/pkg/lib /usr/X11R6/lib .. ../.."
for i in $libslist; do
@@ -112,7 +118,9 @@
fi
if test x"${ac_cv_path_png_lib}" != x ; then
- PNG_LIBS="${ac_cv_path_png_lib}"
+ PNG_LIBS="${ac_cv_path_png_lib} -lpng"
+ else
+ PNG_LIBS="-lpng"
fi
AM_CONDITIONAL(HAVE_PNG, [test x$png = xyes])
Index: gnash/macros/pthreads.m4
diff -u gnash/macros/pthreads.m4:1.4 gnash/macros/pthreads.m4:1.5
--- gnash/macros/pthreads.m4:1.4 Mon Feb 20 17:05:34 2006
+++ gnash/macros/pthreads.m4 Sun Feb 26 15:49:30 2006
@@ -26,89 +26,70 @@
if test x"$pthreads" = x"yes"; then
dnl Look for the header
- AC_ARG_WITH(pthreads_incl, [ --with-pthreads_incl directory where
libpthreads header is], with_pthreads_incl=${withval})
+ AC_ARG_WITH(pthreads_incl, [ --with-pthread-incl directory where Pthread
header is], with_pthread_incl=${withval})
AC_CACHE_VAL(ac_cv_path_pthread_incl,[
- if test x"${with_pthreads_incl}" != x ; then
- if test -f ${with_pthreads_incl}/pthread.h ; then
- ac_cv_path_pthread_incl=`(cd ${with_pthreads_incl}; pwd)`
+ if test x"${with_pthread_incl}" != x ; then
+ if test -f ${with_pthread_incl}/pthread.h ; then
+ ac_cv_path_pthread_incl=`(cd ${with_pthread_incl}; pwd)`
else
- AC_MSG_ERROR([${with_pthreads_incl} directory doesn't contain
pthread.h])
+ AC_MSG_ERROR([${with_pthread_incl} directory doesn't contain pthread.h])
fi
fi
])
dnl If the path hasn't been specified, go look for it.
if test x"${ac_cv_path_pthread_incl}" = x; then
- if test -d /usr/pkg/pthreads; then
+ AC_CHECK_HEADERS(pthread.h, [ac_cv_path_pthread_incl=""], [
+ if test x"${ac_cv_path_pthread_incl}" = x; then
AC_MSG_CHECKING([for libpthread header])
- if test -f /usr/pkg/pthreads/include/pthread.h; then
- ac_cv_path_pthread_incl="-I/usr/pkg/pthreads/include"
- fi
- else
- AC_CHECK_HEADERS(pthread.h, [ac_cv_path_pthread_incl=""], [
- if test x"${ac_cv_path_pthread_incl}" = x; then
- AC_MSG_CHECKING([for libpthread header])
- incllist="/usr/pkg/pthreads/include /sw/include /usr/local/include
/home/latest/include /opt/include /usr/include /usr/pkg/include .. ../.."
-
- for i in $incllist; do
- if test -f $i/pthreads/pthread.h -o -f $i/pthread.h; then
- if test x"$i" != x"/usr/include"; then
- ac_cv_path_pthread_incl="-I$i"
- break
- else
- ac_cv_path_pthread_incl=""
- break
- fi
+ incllist="${prefix}/include /sw/include /usr/pkg/pthreads/include
/usr/local/include /home/latest/include /opt/include /usr/include .. ../.."
+ for i in $incllist; do
+ if test -f $i/pthreads/pthread.h -o -f $i/pthread.h; then
+ if test x"$i" != x"/usr/include"; then
+ ac_cv_path_pthread_incl="$i"
+ break
+ else
+ ac_cv_path_pthread_incl=""
+ break
fi
- done
- fi])
- fi
+ fi
+ done
+ fi], [INCLUDES = -I/usr/pkg/pthreads/include])
else
- AC_MSG_RESULT(-I${ac_cv_path_pthread_incl})
+ AC_MSG_RESULT(${ac_cv_path_pthread_incl})
if test x"${ac_cv_path_pthread_incl}" != x"/usr/include"; then
- ac_cv_path_pthread_incl="-I${ac_cv_path_pthread_incl}"
+ ac_cv_path_pthread_incl="${ac_cv_path_pthread_incl}"
else
ac_cv_path_pthread_incl=""
fi
fi
if test x"${ac_cv_path_pthread_incl}" != x ; then
- PTHREAD_CFLAGS="${ac_cv_path_pthread_incl}"
+ PTHREAD_CFLAGS="-I${ac_cv_path_pthread_incl}"
AC_MSG_RESULT(yes)
else
PTHREAD_CFLAGS=""
fi
dnl Look for the library
- AC_ARG_WITH(pthreads_lib, [ --with-pthreads-lib directory where
pthreads library is], with_pthreads_lib=${withval})
- AC_CACHE_VAL(ac_cv_path_pthreads_lib,[
- if test x"${with_pthreads_lib}" != x ; then
- if test -f ${with_pthreads_lib}/libpthread.a -o -f
${with_pthreads_lib}/libpthread.so; then
- ac_cv_path_pthreads_lib=`(cd ${with_pthreads_incl}; pwd)`
+ AC_ARG_WITH(pthread_lib, [ --with-pthread-lib directory where
pthreads library is], with_pthread_lib=${withval})
+ AC_CACHE_VAL(ac_cv_path_pthread_lib,[
+ if test x"${with_pthread_lib}" != x ; then
+ if test -f ${with_pthread_lib}/libpthread.a -o -f
${with_pthread_lib}/libpthread.so; then
+ ac_cv_path_pthread_lib=`(cd ${with_pthread_incl}; pwd)`
else
- AC_MSG_ERROR([${with_pthreads_lib} directory doesn't contain
libpthreads.])
+ AC_MSG_ERROR([${with_pthread_lib} directory doesn't contain Pthread
library.])
fi
fi
])
dnl If the header doesn't exist, there is no point looking for the
library.
if test x"${ac_cv_path_pthread_lib}" = x; then
- if test -d /usr/pkg/pthreads; then
- AC_MSG_CHECKING([for libpthreads library])
- if test -f /usr/pkg/pthreads/lib/libpthreads.a -o -f
/usr/pkg/pthreads/lib/libpthreads.so; then
- ac_cv_path_pthread_lib="-L/usr/pkg/pthreads/lib -lpthreads"
- fi
- if test x"${ac_cv_path_pthread_lib}" != x ; then
- AC_MSG_RESULT(yes)
- else
- AC_MSG_RESULT(yes)
- fi
- else
- AC_CHECK_LIB(pthread, pthread_kill,
[ac_cv_path_pthread_lib="-lpthreads"],[
+ AC_CHECK_LIB(pthread, pthread_kill,
[ac_cv_path_pthread_lib="-lpthread"],[
AC_MSG_CHECKING([for libpthreads library])
- libslist="/usr/lib64 /usr/lib /usr/pkg/pthreads/lib /sw/lib
/usr/local/lib /home/latest/lib /opt/lib /usr/pkg/lib .. ../.."
+ libslist="${prefix}/lib64 ${prefix}/lib /usr/lib64 /usr/lib
/usr/pkg/pthreads/lib /sw/lib /usr/local/lib /home/latest/lib /opt/lib
/usr/pkg/lib .. ../.."
for i in $libslist; do
- if test -f $i/libpthreads.a -o -f $i/libpthreads.so; then
+ if test -f $i/libpthread.a -o -f $i/libpthread.so; then
if test x"$i" != x"/usr/lib"; then
ac_cv_path_pthread_lib="-L$i"
AC_MSG_RESULT(${ac_cv_path_pthread_lib})
@@ -121,9 +102,8 @@
fi
done
])
- fi
else
- if test -f ${ac_cv_path_pthread_lib}/libpthreads.a -o -f
${ac_cv_path_pthread_lib}/libpthreads.so; then
+ if test -f ${ac_cv_path_pthread_lib}/libpthread.a -o -f
${ac_cv_path_pthread_lib}/libpthread.so; then
if test x"${ac_cv_path_pthread_lib}" != x"/usr/lib"; then
ac_cv_path_pthread_lib="-L${ac_cv_path_pthread_lib} -lpthread"
@@ -134,7 +114,7 @@
fi
if test x"${ac_cv_path_pthread_lib}" != x ; then
- PTHREAD_LIBS="${ac_cv_path_pthread_lib} -lpthreads"
+ PTHREAD_LIBS="${ac_cv_path_pthread_lib} -lpthread"
else
PTHREAD_LIBS="-lpthread"
fi
Index: gnash/macros/sdl.m4
diff -u gnash/macros/sdl.m4:1.9 gnash/macros/sdl.m4:1.10
--- gnash/macros/sdl.m4:1.9 Fri Feb 24 00:06:21 2006
+++ gnash/macros/sdl.m4 Sun Feb 26 15:49:30 2006
@@ -1,188 +1,112 @@
-# Configure paths for SDL
-# Sam Lantinga 9/21/99
-# stolen from Manish Singh
-# stolen back from Frank Belew
-# stolen from Manish Singh
-# Shamelessly stolen from Owen Taylor
-
-dnl AM_PATH_SDL([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
-dnl Test for SDL, and define SDL_CFLAGS and SDL_LIBS
dnl
-AC_DEFUN([GNASH_PATH_SDL],
-[dnl
-dnl Get the cflags and libraries from the sdl-config script
+dnl Copyright (C) 2005, 2006 Free Software Foundation, Inc.
dnl
-AC_ARG_WITH(sdl-prefix,[ --with-sdl-prefix=PFX Prefix where SDL is
installed (optional)],
- sdl_prefix="$withval", sdl_prefix="")
-AC_ARG_WITH(sdl-exec-prefix,[ --with-sdl-exec-prefix=PFX Exec prefix where
SDL is installed (optional)],
- sdl_exec_prefix="$withval", sdl_exec_prefix="")
-AC_ARG_ENABLE(sdltest, [ --disable-sdltest Do not try to compile and
run a test SDL program],
- , enable_sdltest=yes)
-
- if test x$sdl_exec_prefix != x ; then
- sdl_args="$sdl_args --exec-prefix=$sdl_exec_prefix"
- if test x${SDL_CONFIG+set} != xset ; then
- SDL_CONFIG=$sdl_exec_prefix/bin/sdl-config
- fi
- fi
- if test x$sdl_prefix != x ; then
- sdl_args="$sdl_args --prefix=$sdl_prefix"
- if test x${SDL_CONFIG+set} != xset ; then
- SDL_CONFIG=$sdl_prefix/bin/sdl-config
- fi
- fi
-
- AC_REQUIRE([AC_CANONICAL_TARGET])
- PATH="$prefix/bin:$prefix/usr/bin:/usr/bin/X11:$PATH"
- AC_PATH_PROG(SDL_CONFIG, sdl-config, no, [$PATH])
- min_sdl_version=ifelse([$1], ,0.11.0,$1)
- AC_MSG_CHECKING(for SDL - version >= $min_sdl_version)
- no_sdl=""
- if test "$SDL_CONFIG" = "no" ; then
- no_sdl=yes
- else
- SDL_CFLAGS=`$SDL_CONFIG $sdlconf_args --cflags`
- SDL_LIBS=`$SDL_CONFIG $sdlconf_args --libs`
-
- sdl_major_version=`$SDL_CONFIG $sdl_args --version | \
- sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
- sdl_minor_version=`$SDL_CONFIG $sdl_args --version | \
- sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
- sdl_micro_version=`$SDL_CONFIG $sdl_config_args --version | \
- sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
- if test "x$enable_sdltest" = "xyes" ; then
- ac_save_CFLAGS="$CFLAGS"
- ac_save_CXXFLAGS="$CXXFLAGS"
- ac_save_LIBS="$LIBS"
- CFLAGS="$CFLAGS $SDL_CFLAGS"
- CXXFLAGS="$CXXFLAGS $SDL_CFLAGS"
- LIBS="$LIBS $SDL_LIBS"
+dnl This program is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 2 of the License, or
+dnl (at your option) any later version.
dnl
-dnl Now check if the installed SDL is sufficiently new. (Also sanity
-dnl checks the results of sdl-config to some extent
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+dnl GNU General Public License for more details.
dnl
- rm -f conf.sdltest
- AC_TRY_RUN([
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "SDL.h"
-
-char*
-my_strdup (char *str)
-{
- char *new_str;
-
- if (str)
- {
- new_str = (char *)malloc ((strlen (str) + 1) * sizeof(char));
- strcpy (new_str, str);
- }
- else
- new_str = NULL;
-
- return new_str;
-}
-
-int main (int argc, char *argv[])
-{
- int major, minor, micro;
- char *tmp_version;
-
- /* This hangs on some systems (?)
- system ("touch conf.sdltest");
- */
- { FILE *fp = fopen("conf.sdltest", "a"); if ( fp ) fclose(fp); }
-
- /* HP/UX 9 (address@hidden) writes to sscanf strings */
- tmp_version = my_strdup("$min_sdl_version");
- if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) {
- printf("%s, bad version string\n", "$min_sdl_version");
- exit(1);
- }
-
- if (($sdl_major_version > major) ||
- (($sdl_major_version == major) && ($sdl_minor_version > minor)) ||
- (($sdl_major_version == major) && ($sdl_minor_version == minor) &&
($sdl_micro_version >= micro)))
- {
- return 0;
- }
- else
- {
- printf("\n*** 'sdl-config --version' returned %d.%d.%d, but the minimum
version\n", $sdl_major_version, $sdl_minor_version, $sdl_micro_version);
- printf("*** of SDL required is %d.%d.%d. If sdl-config is correct, then
it is\n", major, minor, micro);
- printf("*** best to upgrade to the required version.\n");
- printf("*** If sdl-config was wrong, set the environment variable
SDL_CONFIG\n");
- printf("*** to point to the correct copy of sdl-config, and remove the
file\n");
- printf("*** config.cache before re-running configure\n");
- return 1;
- }
-}
-
-],, no_sdl=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
- CFLAGS="$ac_save_CFLAGS"
- CXXFLAGS="$ac_save_CXXFLAGS"
- LIBS="$ac_save_LIBS"
- fi
- fi
- if test "x$no_sdl" = x ; then
- AC_MSG_RESULT(yes)
- ifelse([$2], , :, [$2])
- else
- AC_MSG_RESULT(no)
- if test "$SDL_CONFIG" = "no" ; then
- echo "*** The sdl-config script installed by SDL could not be found"
- echo "*** If SDL was installed in PREFIX, make sure PREFIX/bin is in"
- echo "*** your path, or set the SDL_CONFIG environment variable to the"
- echo "*** full path to sdl-config."
- else
- if test -f conf.sdltest ; then
- :
- else
- echo "*** Could not run SDL test program, checking why..."
- CFLAGS="$CFLAGS $SDL_CFLAGS"
- CXXFLAGS="$CXXFLAGS $SDL_CFLAGS"
- LIBS="$LIBS $SDL_LIBS"
- AC_TRY_LINK([
-#include <stdio.h>
-#include "SDL.h"
-
-int main(int argc, char *argv[])
-{ return 0; }
-#undef main
-#define main K_and_R_C_main
-], [ return 0; ],
- [ echo "*** The test program compiled, but did not run. This usually
means"
- echo "*** that the run-time linker is not finding SDL or finding the
wrong"
- echo "*** version of SDL. If it is not finding SDL, you'll need to
set your"
- echo "*** LD_LIBRARY_PATH environment variable, or edit
/etc/ld.so.conf to point"
- echo "*** to the installed location Also, make sure you have run
ldconfig if that"
- echo "*** is required on your system"
- echo "***"
- echo "*** If you have an old version installed, it is best to remove
it, although"
- echo "*** you may also be able to get things to work by modifying
LD_LIBRARY_PATH"],
- [ echo "*** The test program failed to compile or link. See the file
config.log for the"
- echo "*** exact error that occured. This usually means SDL was
incorrectly installed"
- echo "*** or that you have moved SDL since it was installed. In the
latter case, you"
- echo "*** may want to edit the sdl-config script: $SDL_CONFIG" ])
- CFLAGS="$ac_save_CFLAGS"
- CXXFLAGS="$ac_save_CXXFLAGS"
- LIBS="$ac_save_LIBS"
- fi
- fi
- SDL_CFLAGS=""
- SDL_LIBS=""
- ifelse([$3], , :, [$3])
+dnl You should have received a copy of the GNU General Public License
+dnl along with this program; if not, write to the Free Software
+dnl Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+AC_DEFUN([GNASH_PATH_SDL],
+[dnl
+ dnl Lool for the header
+ AC_ARG_WITH(sdl_incl, [ --with-sdl-incl directory where sdl header is],
with_sdl_incl=${withval})
+ AC_CACHE_VAL(ac_cv_path_sdl_incl,[
+ if test x"${with_sdl_incl}" != x ; then
+ if test -f ${with_sdl_incl}/SDL.h ; then
+ ac_cv_path_sdl_incl=`(cd ${with_sdl_incl}; pwd)`
+ else
+ AC_MSG_ERROR([${with_sdl_incl} directory doesn't contain SDL.h])
+ fi
+ fi
+ ])
+ if test x"${ac_cv_path_sdl_incl}" = x ; then
+ AC_MSG_CHECKING([for SDL header])
+ incllist="${prefix} /usr /usr/pkg /sw /usr/local /home/latest /opt /usr ..
../.."
+
+ for i in $incllist; do
+ if test -f $i/SDL/include/SDL.h; then
+ ac_cv_path_sdl_incl=$i/SDL/include
+ break
+ fi
+ if test -f $i/include/SDL/SDL.h; then
+ ac_cv_path_sdl_incl=$i/include/SDL
+ break
+ fi
+ done
+
+ SDL_CFLAGS=""
+ if test x"${ac_cv_path_sdl_incl}" = x ; then
+ AC_MSG_RESULT(none)
+ AC_CHECK_HEADERS(SDL.h, [ac_cv_path_sdl_incl=""])
+ else
+ AC_MSG_RESULT(${ac_cv_path_sdl_incl})
+ if test x"${ac_cv_path_sdl_incl}" != x"/usr/include"; then
+ ac_cv_path_sdl_incl="${ac_cv_path_sdl_incl}"
+ else
+ ac_cv_path_sdl_incl=""
+ fi
+ fi
fi
+
+ if test x"${ac_cv_path_sdl_incl}" != x ; then
+ SDL_CFLAGS="-I${ac_cv_path_sdl_incl}"
+ fi
+
+ dnl Look for the library
+ AC_ARG_WITH(sdl_lib, [ --with-sdl-lib directory where sdl library is],
with_sdl_lib=${withval})
+ AC_MSG_CHECKING([for sdl library])
+ AC_CACHE_VAL(ac_cv_path_sdl_lib,[
+ if test x"${with_sdl_libs}" != x ; then
+ if test -f ${with_sdl_libs}/libSDL.a -o -f ${with_sdl_libs}/libSDL.so; then
+ ac_cv_path_sdl_lib=`(cd ${with_sdl_libs}; pwd)`
+ else
+ AC_MSG_ERROR([${with_sdl_libs} directory doesn't contain libsdl.a])
+ fi
+ fi
+ ])
+
+ SDL_LIBS=""
+ if test x"${ac_cv_path_sdl_lib}" = x ; then
+ AC_CHECK_LIB(SDL, SDL_Init, [ac_cv_path_sdl_lib="-lSDL"],[
+ AC_MSG_CHECKING([for SDL library])
+ liblist="${prefix}/lib64 ${prefix}/lib /usr/lib64 /usr/lib /usr/pkg/lib
/sw/lib /usr/local/lib /home/latest/lib /opt/lib.. ../.."
+ for i in $liblist; do
+ if test -f $i/libSDL.a -o -f $i/libSDl.so; then
+ if test x"$i" != x"/usr/lib"; then
+ ac_cv_path_sdl_lib="-L$i -lSDL"
+ AC_MSG_RESULT(${ac_cv_path_sdl_lib})
+ break
+ else
+ ac_cv_path_sdl_lib="-lSDL"
+ AC_MSG_RESULT([yes])
+ break
+ fi
+ fi
+ done
+ ])
+ fi
+
+ if test x"${ac_cv_path_sdl_lib}" != x ; then
+ SDL_LIBS="${ac_cv_path_sdl_lib}"
+ AC_DEFINE(HAVE_SDL_H, [], [We have SDL support])
+ fi
+
AC_SUBST(SDL_CFLAGS)
AC_SUBST(SDL_LIBS)
- rm -f conf.sdltest
])
AC_DEFUN([GNASH_PATH_SDL_MIXER],
[
dnl Lool for the header
- AC_ARG_WITH(sdl_mixer_incl, [ --with-sdl_mixer-incl directory where
sdl_mixer header is], with_sdl_mixer_incl=${withval})
+ AC_ARG_WITH(sdl_mixer_incl, [ --with-sdl-mixer-incl directory where
sdl_mixer header is], with_sdl_mixer_incl=${withval})
AC_CACHE_VAL(ac_cv_path_sdl_mixer_incl,[
if test x"${with_sdl_mixer_incl}" != x ; then
if test -f ${with_sdl_mixer_incl}/SDL_mixer.h ; then
@@ -192,7 +116,6 @@
fi
fi
])
-
if test x"${ac_cv_path_sdl_mixer_incl}" = x ; then
AC_MSG_CHECKING([for SDL_mixer header])
incllist="${prefix} /usr/pkg /sw /usr/local /home/latest /opt /usr ..
../.."
@@ -214,16 +137,17 @@
AC_CHECK_HEADERS(SDL_mixer.h, [ac_cv_path_sdl_mixer_incl=""])
else
AC_MSG_RESULT(${ac_cv_path_sdl_mixer_incl})
- if test x"${ac_cv_path_sdl_mixer_incl}" != x"/usr/include"; then
- ac_cv_path_sdl_mixer_incl="${ac_cv_path_sdl_mixer_incl}"
- else
- ac_cv_path_sdl_mixer_incl=""
- fi
fi
fi
if test x"${ac_cv_path_sdl_mixer_incl}" != x ; then
- SDL_MIXER_CFLAGS="-I${ac_cv_path_sdl_mixer_incl}"
+ if test x"${ac_cv_path_sdl_mixer_incl}" != x"/usr/include"; then
+ ac_cv_path_sdl_mixer_incl="${ac_cv_path_sdl_mixer_incl}"
+ SDL_MIXER_CFLAGS="-I${ac_cv_path_sdl_mixer_incl}"
+ AC_DEFINE(HAVE_SDL_MIXER_H, [], [We have SDL Mixer support])
+ else
+ ac_cv_path_sdl_mixer_incl=""
+ fi
fi
dnl Look for the library
@@ -231,7 +155,7 @@
AC_MSG_CHECKING([for sdl_mixer library])
AC_CACHE_VAL(ac_cv_path_sdl_mixer_lib,[
if test x"${with_sdl_mixer_libs}" != x ; then
- if test -f ${with_sdl_mixer_libs}/libSDL_mixer.a -o -f
${with_sdl_mixer_libs}/libSDL_mixer.so; then
+ if test -f ${with_sdl_mixer_libs}/libSDL_mixer.a -o -f
${with_sdl_mixer_libs}/libSDL_mixer.so -o -f $i/libSDL_mixer-1.2.a -o -f
$i/libSDL_mixer-1.2.so; then
ac_cv_path_sdl_mixer_lib=`(cd ${with_sdl_mixer_libs}; pwd)`
else
AC_MSG_ERROR([${with_sdl_mixer_libs} directory doesn't contain
libsdl_mixer.a])
@@ -239,41 +163,53 @@
fi
])
+ dnl Some systems ubnfortunately use the version on this library,
+ dnl and don't have a symbolic link without a version number,
+dnl if test -f $i/libSDL_mixer-1.2.a -o -f $i/libSDL_mixer-1.2.so; then
+dnl ac_cv_path_sdl_mixer_lib=$i
+dnl withver="-1.2"
+
+ SDL_MIXER_LIBS=""
+
if test x"${ac_cv_path_sdl_mixer_lib}" = x ; then
- liblist="${prefix}/lib64 ${prefix}/lib /usr/lib64 /usr/lib /usr/pkg/lib
/sw/lib /usr/local/lib /home/latest/lib /opt/lib.. ../.."
+ AC_CHECK_LIB(SDL_mixer, Mix_Linked_Version, [], AC_MSG_RESULT([no]))
+ if test x"${ac_cv_path_sdl_mixer_lib}" = x ; then
+ AC_CHECK_LIB(SDL_mixer-1.2, Mix_Linked_Version,
[ac_cv_path_sdl_mixer_lib="-lSDL_mixer-1.2"], AC_MSG_RESULT([no]))
+ fi
+ else
+ AC_MSG_RESULT([yes])
+ fi
+ if test x"${ac_cv_path_sdl_mixer_lib}" = x ; then
+ AC_MSG_CHECKING([for SDL_mixer library])
+ liblist="${prefix}/lib64 ${prefix}/lib /usr/lib64 /usr/lib /usr/pkg/lib
/sw/lib /usr/local/lib /home/latest/lib /opt/lib.. ../.."
for i in $liblist; do
- if test -f $i/libSDL_mixer.a -o -f $i/libSDL_mixer.so -o -f
$i/libSDL_mixer.dylib; then
- ac_cv_path_sdl_mixer_lib=$i
- break
- else
-dnl Some systems ubnfortunately use the version on this library, and don't
-dnl have a symbolic link without a version number,
- if test -f $i/libSDL_mixer-1.2.a -o -f $i/libSDL_mixer-1.2.so -o -f
$i/libSDL_mixer.dylib; then
- ac_cv_path_sdl_mixer_lib=$i
- break
+ if test -f $i/libSDL_mixer.a -o -f $i/libSDl_mixer.so; then
+ if test x"$i" != x"/usr/lib"; then
+ ac_cv_path_sdl_mixer_lib="-L$i -lSDL_mixer"
+ break
+ else
+ ac_cv_path_sdl_mixer_lib="-lSDL_mixer"
+ break
+ fi
fi
- fi
- done
-
- SDL_MIXER_LIBS=""
- if test x"${ac_cv_path_sdl_mixer_lib}" = x ; then
- AC_MSG_RESULT(none)
- dnl if we can't find libsdl_mixer via the path, see if it's in the
compiler path
- AC_CHECK_LIB(SDL_mixer, Mix_Linked_Version, SDL_MIXER_LIBS="-lSDL_mixer")
- else
- AC_MSG_RESULT(${ac_cv_path_sdl_mixer_lib})
- if test x"${ac_cv_path_sdl_mixer_lib}" != x"/usr/lib"; then
- ac_cv_path_sdl_mixer_lib="-L${ac_cv_path_sdl_mixer_lib} -lSDL_mixer"
- else
- ac_cv_path_sdl_mixer_lib="-lSDL_mixer"
+ if test -f $i/libSDL_mixer-1.2.a -o -f $i/libSDl_mixer-1.2.so; then
+ if test x"$i" != x"/usr/lib"; then
+ ac_cv_path_sdl_mixer_lib="-L$i -lSDL_mixer-1.2"
+ AC_MSG_RESULT(${ac_cv_path_sdl_mixer_lib})
+ break
+ else
+ ac_cv_path_sdl_mixer_lib="-lSDL_mixer-1.2"
+ AC_MSG_RESULT([yes])
+ break
+ fi
fi
- fi
+ done
fi
if test x"${ac_cv_path_sdl_mixer_lib}" != x ; then
SDL_MIXER_LIBS="${ac_cv_path_sdl_mixer_lib}"
- AC_DEFINE(HAVE_SDL_MIXER_H, [], [We have SDL Mixer support])
+ AC_DEFINE(HAVE_SDL_MIXER, [], [We have full SDL Mixer support])
fi
AC_SUBST(SDL_MIXER_CFLAGS)
Index: gnash/server/Makefile.am
diff -u gnash/server/Makefile.am:1.21 gnash/server/Makefile.am:1.22
--- gnash/server/Makefile.am:1.21 Mon Feb 13 10:44:12 2006
+++ gnash/server/Makefile.am Sun Feb 26 15:49:30 2006
@@ -30,6 +30,7 @@
-I$(top_srcdir) \
-I$(top_srcdir)/libbase \
-I$(top_srcdir) \
+ $(PTHREAD_CFLAGS) \
$(ENGINE_INCLUDE) \
$(ZLIB_CFLAGS) \
$(OGG_CFLAGS) \
Index: gnash/utilities/Makefile.am
diff -u gnash/utilities/Makefile.am:1.9 gnash/utilities/Makefile.am:1.10
--- gnash/utilities/Makefile.am:1.9 Fri Feb 3 20:50:27 2006
+++ gnash/utilities/Makefile.am Sun Feb 26 15:49:30 2006
@@ -41,13 +41,16 @@
$(LIBXML_LIBS) \
$(DMALLOC_LIBS) \
$(MP3_LIBS) \
- $(OGG_LIBS)
+ $(OGG_LIBS) \
+ $(PTHREAD_LIBS)
+
INCLUDES = -I.. \
-I$(top_srcdir) \
-I$(top_srcdir)/libbase \
-I$(top_srcdir)/server \
-I$(top_srcdir)/libgeometry \
+ $(PTHREAD_CFLAGS) \
$(LIBXML_CFLAGS) \
$(OPENGL_CFLAGS) \
$(DMALLOC_CFLAGS) \
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Gnash-commit] gnash ./ChangeLog backend/Makefile.am backend/r...,
Rob Savoye <=