From 6d90cf5b700447e15fb61cdf91622ed97c471162 Mon Sep 17 00:00:00 2001 From: David Rose Date: Wed, 30 Apr 2008 22:21:24 +0000 Subject: [PATCH] tinydisplay --- dtool/Config.pp | 6 + dtool/pptempl/Global.pp | 7 + panda/src/display/graphicsStateGuardian.cxx | 2 +- panda/src/glstuff/glGeomMunger_src.cxx | 2 +- panda/src/tinydisplay/Sources.pp | 34 + panda/src/tinydisplay/config_tinydisplay.cxx | 64 + panda/src/tinydisplay/config_tinydisplay.h | 29 + panda/src/tinydisplay/tinyGeomMunger.I | 18 + panda/src/tinydisplay/tinyGeomMunger.cxx | 118 ++ panda/src/tinydisplay/tinyGeomMunger.h | 67 + panda/src/tinydisplay/tinyGraphicsPipe.I | 18 + panda/src/tinydisplay/tinyGraphicsPipe.cxx | 125 ++ panda/src/tinydisplay/tinyGraphicsPipe.h | 71 + .../tinydisplay/tinyGraphicsStateGuardian.I | 28 + .../tinydisplay/tinyGraphicsStateGuardian.cxx | 1309 +++++++++++++++++ .../tinydisplay/tinyGraphicsStateGuardian.h | 132 ++ panda/src/tinydisplay/tinyGraphicsWindow.I | 18 + panda/src/tinydisplay/tinyGraphicsWindow.cxx | 472 ++++++ panda/src/tinydisplay/tinyGraphicsWindow.h | 89 ++ .../src/tinydisplay/tinyImmediateModeSender.I | 101 ++ .../tinydisplay/tinyImmediateModeSender.cxx | 232 +++ .../src/tinydisplay/tinyImmediateModeSender.h | 114 ++ panda/src/tinydisplay/tinyTextureContext.I | 30 + panda/src/tinydisplay/tinyTextureContext.cxx | 21 + panda/src/tinydisplay/tinyTextureContext.h | 61 + 25 files changed, 3166 insertions(+), 2 deletions(-) create mode 100644 panda/src/tinydisplay/Sources.pp create mode 100644 panda/src/tinydisplay/config_tinydisplay.cxx create mode 100644 panda/src/tinydisplay/config_tinydisplay.h create mode 100644 panda/src/tinydisplay/tinyGeomMunger.I create mode 100644 panda/src/tinydisplay/tinyGeomMunger.cxx create mode 100644 panda/src/tinydisplay/tinyGeomMunger.h create mode 100644 panda/src/tinydisplay/tinyGraphicsPipe.I create mode 100644 panda/src/tinydisplay/tinyGraphicsPipe.cxx create mode 100644 panda/src/tinydisplay/tinyGraphicsPipe.h create mode 100644 panda/src/tinydisplay/tinyGraphicsStateGuardian.I create mode 100644 panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx create mode 100644 panda/src/tinydisplay/tinyGraphicsStateGuardian.h create mode 100644 panda/src/tinydisplay/tinyGraphicsWindow.I create mode 100644 panda/src/tinydisplay/tinyGraphicsWindow.cxx create mode 100644 panda/src/tinydisplay/tinyGraphicsWindow.h create mode 100644 panda/src/tinydisplay/tinyImmediateModeSender.I create mode 100644 panda/src/tinydisplay/tinyImmediateModeSender.cxx create mode 100644 panda/src/tinydisplay/tinyImmediateModeSender.h create mode 100644 panda/src/tinydisplay/tinyTextureContext.I create mode 100644 panda/src/tinydisplay/tinyTextureContext.cxx create mode 100644 panda/src/tinydisplay/tinyTextureContext.h diff --git a/dtool/Config.pp b/dtool/Config.pp index caeded5d37..159aa4677f 100644 --- a/dtool/Config.pp +++ b/dtool/Config.pp @@ -616,6 +616,12 @@ // Similar to MIN_GL_VERSION, above. #define MIN_MESA_VERSION 1 1 +// Experimental: TinySDGL, a variant on TinyGL ported to SDL. Used +// for fast but cheesy software rendering. +#define TINYSDGL_IPATH +#define TINYSDGL_LPATH +#define TINYSDGL_LIBS TinySDGL TinyGLU SDL +#defer HAVE_TINYSDGL $[libtest $[TINYSDGL_LPATH],$[TINYSDGL_LIBS]] // Is the Chromium remote-rendering library installed, and where? // This should include libcr_opengl32. diff --git a/dtool/pptempl/Global.pp b/dtool/pptempl/Global.pp index 34bfbe017e..32a21e3b71 100644 --- a/dtool/pptempl/Global.pp +++ b/dtool/pptempl/Global.pp @@ -127,6 +127,13 @@ #define gl_framework $[GL_FRAMEWORK] #endif +#if $[HAVE_TINYSDGL] + #define tinysdgl_ipath $[wildcard $[TINYSDGL_IPATH]] + #define tinysdgl_lpath $[wildcard $[TINYSDGL_LPATH]] + #define tinysdgl_cflags $[TINYSDGL_CFLAGS] + #define tinysdgl_libs $[TINYSDGL_LIBS] +#endif + #if $[HAVE_MESA] #define mesa_ipath $[wildcard $[MESA_IPATH]] #define mesa_lpath $[wildcard $[MESA_LPATH]] diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index ff31694c2a..df97227b21 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -688,7 +688,7 @@ get_geom_munger(const RenderState *state, Thread *current_thread) { // Nothing in the map; create a new entry. PT(GeomMunger) munger = make_geom_munger(nc_state, current_thread); - nassertr(munger->is_registered(), munger); + nassertr(munger != (GeomMunger *)NULL && munger->is_registered(), munger); mi = nc_state->_mungers.insert(RenderState::Mungers::value_type(this, munger)).first; nc_state->_last_mi = mi; diff --git a/panda/src/glstuff/glGeomMunger_src.cxx b/panda/src/glstuff/glGeomMunger_src.cxx index f41fd18417..7d38053134 100644 --- a/panda/src/glstuff/glGeomMunger_src.cxx +++ b/panda/src/glstuff/glGeomMunger_src.cxx @@ -27,7 +27,7 @@ ALLOC_DELETED_CHAIN_DEF(CLP(GeomMunger)); // Access: Public // Description: //////////////////////////////////////////////////////////////////// -INLINE CLP(GeomMunger):: +CLP(GeomMunger):: CLP(GeomMunger)(GraphicsStateGuardian *gsg, const RenderState *state) : StandardMunger(gsg, state, 4, NT_uint8, C_color), _texture(state->get_texture()), diff --git a/panda/src/tinydisplay/Sources.pp b/panda/src/tinydisplay/Sources.pp new file mode 100644 index 0000000000..cfc1b97f1e --- /dev/null +++ b/panda/src/tinydisplay/Sources.pp @@ -0,0 +1,34 @@ +#define BUILD_DIRECTORY $[HAVE_TINYSDGL] +//#define BUILDING_DLL BUILDING_PANDATINYSDGL + +#define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \ + dtoolutil:c dtoolbase:c dtool:m +#define USE_PACKAGES tinysdgl + +#begin lib_target + #define TARGET tinydisplay + #define LOCAL_LIBS \ + gsgmisc gsgbase gobj display \ + putil linmath mathutil pnmimage + + #define SOURCES \ + config_tinydisplay.cxx config_tinydisplay.h \ + tinyGeomMunger.I tinyGeomMunger.cxx tinyGeomMunger.h \ + tinyGraphicsPipe.I tinyGraphicsPipe.cxx tinyGraphicsPipe.h \ + tinyGraphicsWindow.h tinyGraphicsWindow.I tinyGraphicsWindow.cxx \ + tinyGraphicsStateGuardian.h tinyGraphicsStateGuardian.I \ + tinyGraphicsStateGuardian.cxx \ + tinyImmediateModeSender.h tinyImmediateModeSender.I \ + tinyImmediateModeSender.cxx \ + tinyTextureContext.I tinyTextureContext.cxx tinyTextureContext.h + + #define INSTALL_HEADERS \ + tinyGeomMunger.I tinyGeomMunger.h \ + tinyGraphicsPipe.I tinyGraphicsPipe.h \ + tinyGraphicsWindow.I tinyGraphicsWindow.h \ + tinyGraphicsStateGuardian.h tinyGraphicsStateGuardian.I \ + tinyImmediateModeSender.h tinyImmediateModeSender.I \ + tinyTextureContext.I tinyTextureContext.h + +#end lib_target + diff --git a/panda/src/tinydisplay/config_tinydisplay.cxx b/panda/src/tinydisplay/config_tinydisplay.cxx new file mode 100644 index 0000000000..906b2b39d3 --- /dev/null +++ b/panda/src/tinydisplay/config_tinydisplay.cxx @@ -0,0 +1,64 @@ +// Filename: config_tinydisplay.cxx +// Created by: drose (24Apr08) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "config_tinydisplay.h" +#include "tinyGraphicsPipe.h" +#include "tinyGraphicsWindow.h" +#include "tinyGraphicsStateGuardian.h" +#include "tinyGeomMunger.h" +#include "tinyTextureContext.h" +#include "graphicsPipeSelection.h" +#include "dconfig.h" +#include "pandaSystem.h" + +Configure(config_tinydisplay); +NotifyCategoryDef(tinydisplay, "display"); + +ConfigureFn(config_tinydisplay) { + init_libtinydisplay(); +} + +//////////////////////////////////////////////////////////////////// +// Function: init_libtinydisplay +// Description: Initializes the library. This must be called at +// least once before any of the functions or classes in +// this library can be used. Normally it will be +// called by the static initializers and need not be +// called explicitly, but special cases exist. +//////////////////////////////////////////////////////////////////// +void +init_libtinydisplay() { + static bool initialized = false; + if (initialized) { + return; + } + initialized = true; + + TinyGraphicsPipe::init_type(); + TinyGraphicsWindow::init_type(); + TinyGraphicsStateGuardian::init_type(); + TinyGeomMunger::init_type(); + TinyTextureContext::init_type(); + + GraphicsPipeSelection *selection = GraphicsPipeSelection::get_global_ptr(); + selection->add_pipe_type(TinyGraphicsPipe::get_class_type(), + TinyGraphicsPipe::pipe_constructor); + + PandaSystem *ps = PandaSystem::get_global_ptr(); + ps->add_system("TinyGL"); +} diff --git a/panda/src/tinydisplay/config_tinydisplay.h b/panda/src/tinydisplay/config_tinydisplay.h new file mode 100644 index 0000000000..c2997fd64e --- /dev/null +++ b/panda/src/tinydisplay/config_tinydisplay.h @@ -0,0 +1,29 @@ +// Filename: config_tinydisplay.h +// Created by: drose (24Apr08) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef CONFIG_TINYDISPLAY_H +#define CONFIG_TINYDISPLAY_H + +#include "pandabase.h" +#include "notifyCategoryProxy.h" + +NotifyCategoryDecl(tinydisplay, EXPCL_PANDAGL, EXPTP_PANDAGL); + +extern EXPCL_PANDAGL void init_libtinydisplay(); + +#endif diff --git a/panda/src/tinydisplay/tinyGeomMunger.I b/panda/src/tinydisplay/tinyGeomMunger.I new file mode 100644 index 0000000000..bbcf232c8e --- /dev/null +++ b/panda/src/tinydisplay/tinyGeomMunger.I @@ -0,0 +1,18 @@ +// Filename: tinyGeomMunger.I +// Created by: drose (29Apr08) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + diff --git a/panda/src/tinydisplay/tinyGeomMunger.cxx b/panda/src/tinydisplay/tinyGeomMunger.cxx new file mode 100644 index 0000000000..3077b798cc --- /dev/null +++ b/panda/src/tinydisplay/tinyGeomMunger.cxx @@ -0,0 +1,118 @@ +// Filename: tinyGeomMunger.cxx +// Created by: drose (29Apr08) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "tinyGeomMunger.h" +#include "dcast.h" + +TypeHandle TinyGeomMunger::_type_handle; + +ALLOC_DELETED_CHAIN_DEF(TinyGeomMunger); + +//////////////////////////////////////////////////////////////////// +// Function: TinyGeomMunger::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +TinyGeomMunger:: +TinyGeomMunger(GraphicsStateGuardian *gsg, const RenderState *state) : + StandardMunger(gsg, state, 4, NT_uint8, C_color) +{ + // The TinyGSG can apply the color and color scale at runtime. + // _munge_color = false; + // _munge_color_scale = false; +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGeomMunger::Destructor +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +TinyGeomMunger:: +~TinyGeomMunger() { +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGeomMunger::munge_format_impl +// Access: Protected, Virtual +// Description: Given a source GeomVertexFormat, converts it if +// necessary to the appropriate format for rendering. +//////////////////////////////////////////////////////////////////// +CPT(GeomVertexFormat) TinyGeomMunger:: +munge_format_impl(const GeomVertexFormat *orig, + const GeomVertexAnimationSpec &animation) { + PT(GeomVertexFormat) new_format = new GeomVertexFormat(*orig); + new_format->set_animation(animation); + + /* + const GeomVertexColumn *color_type = orig->get_color_column(); + if (color_type != (GeomVertexColumn *)NULL && + color_type->get_numeric_type() == NT_packed_dabc) { + // We need to convert the color format; OpenGL doesn't support the + // byte order of DirectX's packed ARGB format. + int color_array = orig->get_array_with(InternalName::get_color()); + + PT(GeomVertexArrayFormat) new_array_format = new_format->modify_array(color_array); + + // Replace the existing color format with the new format. + new_array_format->add_column + (InternalName::get_color(), 4, NT_uint8, + C_color, color_type->get_start()); + } + */ + + CPT(GeomVertexFormat) format = GeomVertexFormat::register_format(new_format); + + return format; +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGeomMunger::premunge_format_impl +// Access: Protected, Virtual +// Description: Given a source GeomVertexFormat, converts it if +// necessary to the appropriate format for rendering. +//////////////////////////////////////////////////////////////////// +CPT(GeomVertexFormat) TinyGeomMunger:: +premunge_format_impl(const GeomVertexFormat *orig) { + return orig; +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGeomMunger::compare_to_impl +// Access: Protected, Virtual +// Description: Called to compare two GeomMungers who are known to be +// of the same type, for an apples-to-apples comparison. +// This will never be called on two pointers of a +// different type. +//////////////////////////////////////////////////////////////////// +int TinyGeomMunger:: +compare_to_impl(const GeomMunger *other) const { + return StandardMunger::compare_to_impl(other); +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGeomMunger::geom_compare_to_impl +// Access: Protected, Virtual +// Description: Called to compare two GeomMungers who are known to be +// of the same type, for an apples-to-apples comparison. +// This will never be called on two pointers of a +// different type. +//////////////////////////////////////////////////////////////////// +int TinyGeomMunger:: +geom_compare_to_impl(const GeomMunger *other) const { + return StandardMunger::compare_to_impl(other); +} diff --git a/panda/src/tinydisplay/tinyGeomMunger.h b/panda/src/tinydisplay/tinyGeomMunger.h new file mode 100644 index 0000000000..1ab044fea0 --- /dev/null +++ b/panda/src/tinydisplay/tinyGeomMunger.h @@ -0,0 +1,67 @@ +// Filename: tinyGeomMunger.h +// Created by: drose (29Apr08) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef TINYGEOMMUNGER_H +#define TINYGEOMMUNGER_H + +#include "pandabase.h" +#include "standardMunger.h" +#include "graphicsStateGuardian.h" +#include "renderState.h" + +//////////////////////////////////////////////////////////////////// +// Class : TinyGeomMunger +// Description : This specialization on GeomMunger finesses vertices +// for TinyGL rendering. In particular, it makes sure +// colors aren't stored in DirectX's packed_argb format. +//////////////////////////////////////////////////////////////////// +class TinyGeomMunger : public StandardMunger { +public: + TinyGeomMunger(GraphicsStateGuardian *gsg, const RenderState *state); + virtual ~TinyGeomMunger(); + ALLOC_DELETED_CHAIN_DECL(TinyGeomMunger); + +protected: + virtual CPT(GeomVertexFormat) munge_format_impl(const GeomVertexFormat *orig, + const GeomVertexAnimationSpec &animation); + virtual CPT(GeomVertexFormat) premunge_format_impl(const GeomVertexFormat *orig); + + virtual int compare_to_impl(const GeomMunger *other) const; + virtual int geom_compare_to_impl(const GeomMunger *other) const; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + StandardMunger::init_type(); + register_type(_type_handle, "TinyGeomMunger", + StandardMunger::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +private: + static TypeHandle _type_handle; +}; + +#include "tinyGeomMunger.I" + +#endif diff --git a/panda/src/tinydisplay/tinyGraphicsPipe.I b/panda/src/tinydisplay/tinyGraphicsPipe.I new file mode 100644 index 0000000000..ae8b199173 --- /dev/null +++ b/panda/src/tinydisplay/tinyGraphicsPipe.I @@ -0,0 +1,18 @@ +// Filename: tinyGraphicsPipe.I +// Created by: drose (24Apr08) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + diff --git a/panda/src/tinydisplay/tinyGraphicsPipe.cxx b/panda/src/tinydisplay/tinyGraphicsPipe.cxx new file mode 100644 index 0000000000..964dd423b3 --- /dev/null +++ b/panda/src/tinydisplay/tinyGraphicsPipe.cxx @@ -0,0 +1,125 @@ +// Filename: tinyGraphicsPipe.cxx +// Created by: drose (24Apr08) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "tinyGraphicsPipe.h" +#include "tinyGraphicsWindow.h" +#include "tinyGraphicsStateGuardian.h" +#include "config_tinydisplay.h" +#include "frameBufferProperties.h" + +TypeHandle TinyGraphicsPipe::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsPipe::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +TinyGraphicsPipe:: +TinyGraphicsPipe() { + _is_valid = true; + + if (SDL_Init(SDL_INIT_VIDEO) < 0) { + tinydisplay_cat.error() + << "Cannot initialize SDL video.\n"; + _is_valid = false; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsPipe::Destructor +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +TinyGraphicsPipe:: +~TinyGraphicsPipe() { + if (SDL_WasInit(SDL_INIT_VIDEO)) { + SDL_QuitSubSystem(SDL_INIT_VIDEO); + } + + SDL_Quit(); +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsPipe::get_interface_name +// Access: Published, Virtual +// Description: Returns the name of the rendering interface +// associated with this GraphicsPipe. This is used to +// present to the user to allow him/her to choose +// between several possible GraphicsPipes available on a +// particular platform, so the name should be meaningful +// and unique for a given platform. +//////////////////////////////////////////////////////////////////// +string TinyGraphicsPipe:: +get_interface_name() const { + return "TinyGL"; +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsPipe::pipe_constructor +// Access: Public, Static +// Description: This function is passed to the GraphicsPipeSelection +// object to allow the user to make a default +// TinyGraphicsPipe. +//////////////////////////////////////////////////////////////////// +PT(GraphicsPipe) TinyGraphicsPipe:: +pipe_constructor() { + return new TinyGraphicsPipe; +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsPipe::make_output +// Access: Protected, Virtual +// Description: Creates a new window on the pipe, if possible. +//////////////////////////////////////////////////////////////////// +PT(GraphicsOutput) TinyGraphicsPipe:: +make_output(const string &name, + const FrameBufferProperties &fb_prop, + const WindowProperties &win_prop, + int flags, + GraphicsStateGuardian *gsg, + GraphicsOutput *host, + int retry, + bool &precertify) { + if (!_is_valid) { + return NULL; + } + + TinyGraphicsStateGuardian *glxgsg = 0; + if (gsg != 0) { + DCAST_INTO_R(glxgsg, gsg, NULL); + } + + // First thing to try: a TinyGraphicsWindow + + if (retry == 0) { + if (((flags&BF_require_parasite)!=0)|| + ((flags&BF_refuse_window)!=0)|| + ((flags&BF_resizeable)!=0)|| + ((flags&BF_size_track_host)!=0)|| + ((flags&BF_rtt_cumulative)!=0)|| + ((flags&BF_can_bind_color)!=0)|| + ((flags&BF_can_bind_every)!=0)) { + return NULL; + } + return new TinyGraphicsWindow(this, name, fb_prop, win_prop, + flags, gsg, host); + } + + // Nothing else left to try. + return NULL; +} diff --git a/panda/src/tinydisplay/tinyGraphicsPipe.h b/panda/src/tinydisplay/tinyGraphicsPipe.h new file mode 100644 index 0000000000..89d03528c4 --- /dev/null +++ b/panda/src/tinydisplay/tinyGraphicsPipe.h @@ -0,0 +1,71 @@ +// Filename: tinyGraphicsPipe.h +// Created by: drose (24Apr08) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef TINYGRAPHICSPIPE_H +#define TINYGRAPHICSPIPE_H + +#include "pandabase.h" +#include "graphicsWindow.h" +#include "graphicsPipe.h" + +class FrameBufferProperties; + +//////////////////////////////////////////////////////////////////// +// Class : TinyGraphicsPipe +// Description : This graphics pipe represents the interface for +// to TinySDGL (an implementation of TinyGL over SDL). +//////////////////////////////////////////////////////////////////// +class TinyGraphicsPipe : public GraphicsPipe { +public: + TinyGraphicsPipe(); + virtual ~TinyGraphicsPipe(); + + virtual string get_interface_name() const; + static PT(GraphicsPipe) pipe_constructor(); + +protected: + virtual PT(GraphicsOutput) make_output(const string &name, + const FrameBufferProperties &fb_prop, + const WindowProperties &win_prop, + int flags, + GraphicsStateGuardian *gsg, + GraphicsOutput *host, + int retry, + bool &precertify); + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + GraphicsPipe::init_type(); + register_type(_type_handle, "TinyGraphicsPipe", + GraphicsPipe::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +private: + static TypeHandle _type_handle; +}; + +#include "tinyGraphicsPipe.I" + +#endif diff --git a/panda/src/tinydisplay/tinyGraphicsStateGuardian.I b/panda/src/tinydisplay/tinyGraphicsStateGuardian.I new file mode 100644 index 0000000000..553e03de64 --- /dev/null +++ b/panda/src/tinydisplay/tinyGraphicsStateGuardian.I @@ -0,0 +1,28 @@ +// Filename: tinyGraphicsStateGuardian.I +// Created by: drose (24Apr08) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsStateGuardian::get_light_id +// Access: Private, Static +// Description: Convert index to gl light id +//////////////////////////////////////////////////////////////////// +INLINE GLenum TinyGraphicsStateGuardian:: +get_light_id(int index) { + return GL_LIGHT0 + index; +} diff --git a/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx b/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx new file mode 100644 index 0000000000..d7b143c0cb --- /dev/null +++ b/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx @@ -0,0 +1,1309 @@ +// Filename: tinyGraphicsStateGuardian.cxx +// Created by: drose (24Apr08) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "tinyGraphicsStateGuardian.h" +#include "tinyGeomMunger.h" +#include "tinyTextureContext.h" +#include "config_tinydisplay.h" +#include "pStatTimer.h" + +TypeHandle TinyGraphicsStateGuardian::_type_handle; + +PStatCollector TinyGraphicsStateGuardian::_vertices_immediate_pcollector("Vertices:Immediate mode"); + +//////////////////////////////////////////////////////////////////// +// Function: uchar_bgr_to_rgb +// Description: Recopies the given array of pixels, converting from +// BGR to RGB arrangement. +//////////////////////////////////////////////////////////////////// +static void +uchar_bgr_to_rgb(unsigned char *dest, const unsigned char *source, + int num_pixels) { + for (int i = 0; i < num_pixels; i++) { + dest[0] = source[2]; + dest[1] = source[1]; + dest[2] = source[0]; + dest += 3; + source += 3; + } +} + +/* +//////////////////////////////////////////////////////////////////// +// Function: uchar_bgra_to_rgba +// Description: Recopies the given array of pixels, converting from +// BGRA to RGBA arrangement. +//////////////////////////////////////////////////////////////////// +static void +uchar_bgra_to_rgba(unsigned char *dest, const unsigned char *source, + int num_pixels) { + for (int i = 0; i < num_pixels; i++) { + dest[0] = source[2]; + dest[1] = source[1]; + dest[2] = source[0]; + dest[3] = source[3]; + dest += 4; + source += 4; + } +} +*/ + +//////////////////////////////////////////////////////////////////// +// Function: uchar_bgra_to_rgb +// Description: Recopies the given array of pixels, converting from +// BGRA to RGB arrangement, dropping alpha. +//////////////////////////////////////////////////////////////////// +static void +uchar_bgra_to_rgb(unsigned char *dest, const unsigned char *source, + int num_pixels) { + for (int i = 0; i < num_pixels; i++) { + dest[0] = source[2] * source[3] / 255; + dest[1] = source[1] * source[3] / 255; + dest[2] = source[0] * source[3] / 255; + dest += 3; + source += 4; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: uchar_lum_to_rgb +// Description: Recopies the given array of pixels, converting from +// luminance to RGB arrangement. +//////////////////////////////////////////////////////////////////// +static void +uchar_lum_to_rgb(unsigned char *dest, const unsigned char *source, + int num_pixels) { + for (int i = 0; i < num_pixels; i++) { + dest[0] = source[0]; + dest[1] = source[0]; + dest[2] = source[0]; + dest += 3; + source += 1; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: uchar_la_to_rgb +// Description: Recopies the given array of pixels, converting from +// luminance-alpha to RGB arrangement. +//////////////////////////////////////////////////////////////////// +static void +uchar_la_to_rgb(unsigned char *dest, const unsigned char *source, + int num_pixels) { + for (int i = 0; i < num_pixels; i++) { + dest[2] = dest[1] = dest[0] = source[0] * source[1] / 255; + dest += 3; + source += 2; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: restructure_image +// Description: Converts the pixels of the image to the appropriate +// format for TinyGL (i.e. GL_RGB). +//////////////////////////////////////////////////////////////////// +static PTA_uchar +restructure_image(Texture *tex) { + int num_pixels = tex->get_x_size() * tex->get_y_size(); + CPTA_uchar orig_image = tex->get_ram_image(); + PTA_uchar new_image = PTA_uchar::empty_array(num_pixels * 3); + + switch (tex->get_format()) { + case Texture::F_rgb: + case Texture::F_rgb5: + case Texture::F_rgb8: + case Texture::F_rgb12: + case Texture::F_rgb332: + uchar_bgr_to_rgb(new_image, orig_image, num_pixels); + break; + + case Texture::F_rgba: + case Texture::F_rgbm: + case Texture::F_rgba4: + case Texture::F_rgba5: + case Texture::F_rgba8: + case Texture::F_rgba12: + case Texture::F_rgba16: + case Texture::F_rgba32: + uchar_bgra_to_rgb(new_image, orig_image, num_pixels); + break; + + case Texture::F_luminance: + case Texture::F_alpha: + uchar_lum_to_rgb(new_image, orig_image, num_pixels); + break; + + case Texture::F_luminance_alphamask: + case Texture::F_luminance_alpha: + uchar_la_to_rgb(new_image, orig_image, num_pixels); + break; + + default: + break; + } + + return new_image; +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsStateGuardian::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +TinyGraphicsStateGuardian:: +TinyGraphicsStateGuardian(GraphicsPipe *pipe, + TinyGraphicsStateGuardian *share_with) : + GraphicsStateGuardian(CS_yup_right, pipe) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsStateGuardian::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +TinyGraphicsStateGuardian:: +~TinyGraphicsStateGuardian() { +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsStateGuardian::reset +// Access: Public, Virtual +// Description: Resets all internal state as if the gsg were newly +// created. +//////////////////////////////////////////////////////////////////// +void TinyGraphicsStateGuardian:: +reset() { + free_pointers(); + GraphicsStateGuardian::reset(); + + _supported_geom_rendering = + Geom::GR_point | + Geom::GR_indexed_other | + Geom::GR_flat_last_vertex; + + _max_texture_dimension = 256; + + // Count the max number of lights + GLint max_lights; + glGetIntegerv(GL_MAX_LIGHTS, &max_lights); + _max_lights = max_lights; + + _color_scale_via_lighting = false; + _alpha_scale_via_texture = false; + + // Now that the GSG has been initialized, make it available for + // optimizations. + add_gsg(this); +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsStateGuardian::make_geom_munger +// Access: Public, Virtual +// Description: Creates a new GeomMunger object to munge vertices +// appropriate to this GSG for the indicated state. +//////////////////////////////////////////////////////////////////// +PT(GeomMunger) TinyGraphicsStateGuardian:: +make_geom_munger(const RenderState *state, Thread *current_thread) { + PT(TinyGeomMunger) munger = new TinyGeomMunger(this, state); + return GeomMunger::register_munger(munger, current_thread); +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsStateGuardian::clear +// Access: Public +// Description: Clears the framebuffer within the current +// DisplayRegion, according to the flags indicated by +// the given DrawableRegion object. +// +// This does not set the DisplayRegion first. You +// should call prepare_display_region() to specify the +// region you wish the clear operation to apply to. +//////////////////////////////////////////////////////////////////// +void TinyGraphicsStateGuardian:: +clear(DrawableRegion *clearable) { + PStatTimer timer(_clear_pcollector); + + if ((!clearable->get_clear_color_active())&& + (!clearable->get_clear_depth_active())&& + (!clearable->get_clear_stencil_active())) { + return; + } + + set_state_and_transform(RenderState::make_empty(), _internal_transform); + + int mask = 0; + + if (clearable->get_clear_color_active()) { + Colorf v = clearable->get_clear_color(); + glClearColor(v[0],v[1],v[2],v[3]); + mask |= GL_COLOR_BUFFER_BIT; + } + + if (clearable->get_clear_depth_active()) { + glClearDepth(clearable->get_clear_depth()); + mask |= GL_DEPTH_BUFFER_BIT; + } + + glClear(mask); +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsStateGuardian::prepare_display_region +// Access: Public, Virtual +// Description: Prepare a display region for rendering (set up +// scissor region and viewport) +//////////////////////////////////////////////////////////////////// +void TinyGraphicsStateGuardian:: +prepare_display_region(DisplayRegionPipelineReader *dr, + Lens::StereoChannel stereo_channel) { + nassertv(dr != (DisplayRegionPipelineReader *)NULL); + GraphicsStateGuardian::prepare_display_region(dr, stereo_channel); + + int l, b, w, h; + dr->get_region_pixels(l, b, w, h); + GLint x = GLint(l); + GLint y = GLint(b); + GLsizei width = GLsizei(w); + GLsizei height = GLsizei(h); + + glViewport(x, y, width, height); +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsStateGuardian::calc_projection_mat +// Access: Public, Virtual +// Description: Given a lens, calculates the appropriate projection +// matrix for use with this gsg. Note that the +// projection matrix depends a lot upon the coordinate +// system of the rendering API. +// +// The return value is a TransformState if the lens is +// acceptable, NULL if it is not. +//////////////////////////////////////////////////////////////////// +CPT(TransformState) TinyGraphicsStateGuardian:: +calc_projection_mat(const Lens *lens) { + if (lens == (Lens *)NULL) { + return NULL; + } + + if (!lens->is_linear()) { + return NULL; + } + + // The projection matrix must always be right-handed Y-up, even if + // our coordinate system of choice is otherwise, because certain GL + // calls (specifically glTexGen(GL_SPHERE_MAP)) assume this kind of + // a coordinate system. Sigh. In order to implement a Z-up (or + // other arbitrary) coordinate system, we'll use a Y-up projection + // matrix, and store the conversion to our coordinate system of + // choice in the modelview matrix. + + LMatrix4f result = + LMatrix4f::convert_mat(CS_yup_right, _current_lens->get_coordinate_system()) * + lens->get_projection_mat(_current_stereo_channel); + + if (_scene_setup->get_inverted()) { + // If the scene is supposed to be inverted, then invert the + // projection matrix. + result *= LMatrix4f::scale_mat(1.0f, -1.0f, 1.0f); + } + + return TransformState::make_mat(result); +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsStateGuardian::prepare_lens +// Access: Public, Virtual +// Description: Makes the current lens (whichever lens was most +// recently specified with set_scene()) active, so +// that it will transform future rendered geometry. +// Normally this is only called from the draw process, +// and usually it is called by set_scene(). +// +// The return value is true if the lens is acceptable, +// false if it is not. +//////////////////////////////////////////////////////////////////// +bool TinyGraphicsStateGuardian:: +prepare_lens() { + if (tinydisplay_cat.is_spam()) { + tinydisplay_cat.spam() + << "glLoadMatrix(GL_PROJECTION): " << _projection_mat->get_mat() << endl; + } + glMatrixMode(GL_PROJECTION); + glLoadMatrixf(_projection_mat->get_mat().get_data()); + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::begin_frame +// Access: Public, Virtual +// Description: Called before each frame is rendered, to allow the +// GSG a chance to do any internal cleanup before +// beginning the frame. +// +// The return value is true if successful (in which case +// the frame will be drawn and end_frame() will be +// called later), or false if unsuccessful (in which +// case nothing will be drawn and end_frame() will not +// be called). +//////////////////////////////////////////////////////////////////// +bool TinyGraphicsStateGuardian:: +begin_frame(Thread *current_thread) { + if (!GraphicsStateGuardian::begin_frame(current_thread)) { + return false; + } + +#ifdef DO_PSTATS + _vertices_immediate_pcollector.clear_level(); +#endif + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::begin_scene +// Access: Public, Virtual +// Description: Called between begin_frame() and end_frame() to mark +// the beginning of drawing commands for a "scene" +// (usually a particular DisplayRegion) within a frame. +// All 3-D drawing commands, except the clear operation, +// must be enclosed within begin_scene() .. end_scene(). +// +// The return value is true if successful (in which case +// the scene will be drawn and end_scene() will be +// called later), or false if unsuccessful (in which +// case nothing will be drawn and end_scene() will not +// be called). +//////////////////////////////////////////////////////////////////// +bool TinyGraphicsStateGuardian:: +begin_scene() { + return GraphicsStateGuardian::begin_scene(); +} + +//////////////////////////////////////////////////////////////////// +// Function: GLGraphicsStateGuardian::end_scene +// Access: Protected, Virtual +// Description: Called between begin_frame() and end_frame() to mark +// the end of drawing commands for a "scene" (usually a +// particular DisplayRegion) within a frame. All 3-D +// drawing commands, except the clear operation, must be +// enclosed within begin_scene() .. end_scene(). +//////////////////////////////////////////////////////////////////// +void TinyGraphicsStateGuardian:: +end_scene() { + GraphicsStateGuardian::end_scene(); +} + +//////////////////////////////////////////////////////////////////// +// Function: GLGraphicsStateGuardian::end_frame +// Access: Public, Virtual +// Description: Called after each frame is rendered, to allow the +// GSG a chance to do any internal cleanup after +// rendering the frame, and before the window flips. +//////////////////////////////////////////////////////////////////// +void TinyGraphicsStateGuardian:: +end_frame(Thread *current_thread) { + GraphicsStateGuardian::end_frame(current_thread); + + // Flush any PCollectors specific to this kind of GSG. + _vertices_immediate_pcollector.flush_level(); +} + + +//////////////////////////////////////////////////////////////////// +// Function: GLGraphicsStateGuardian::begin_draw_primitives +// Access: Public, Virtual +// Description: Called before a sequence of draw_primitive() +// functions are called, this should prepare the vertex +// data for rendering. It returns true if the vertices +// are ok, false to abort this group of primitives. +//////////////////////////////////////////////////////////////////// +bool TinyGraphicsStateGuardian:: +begin_draw_primitives(const GeomPipelineReader *geom_reader, + const GeomMunger *munger, + const GeomVertexDataPipelineReader *data_reader, + bool force) { +#ifndef NDEBUG + if (tinydisplay_cat.is_spam()) { + tinydisplay_cat.spam() << "begin_draw_primitives: " << *(data_reader->get_object()) << "\n"; + } +#endif // NDEBUG + + if (!GraphicsStateGuardian::begin_draw_primitives(geom_reader, munger, data_reader, force)) { + return false; + } + nassertr(_data_reader != (GeomVertexDataPipelineReader *)NULL, false); + + // We must use immediate mode to render primitives. + _sender.clear(); + + _sender.add_column(_data_reader, InternalName::get_normal(), + NULL, NULL, glNormal3f, NULL); + if (!_sender.add_column(_data_reader, InternalName::get_color(), + NULL, NULL, glColor3f, glColor4f)) { + // If we didn't have a color column, the item color is white. + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + } + + // TinyGL only supports single-texturing, so only bother with the + // first texture stage. + int max_stage_index = _effective_texture->get_num_on_ff_stages(); + if (max_stage_index > 0) { + TextureStage *stage = _effective_texture->get_on_ff_stage(0); + const InternalName *name = stage->get_texcoord_name(); + _sender.add_column(_data_reader, name, + NULL, glTexCoord2f, NULL, NULL); + } + + // We must add vertex last, because glVertex3f() is the key + // function call that actually issues the vertex. + _sender.add_column(_data_reader, InternalName::get_vertex(), + NULL, glVertex2f, glVertex3f, glVertex4f); + + if (_transform_stale) { + glMatrixMode(GL_MODELVIEW); + glLoadMatrixf(_internal_transform->get_mat().get_data()); + } + + if (_data_reader->is_vertex_transformed()) { + // If the vertex data claims to be already transformed into clip + // coordinates, wipe out the current projection and modelview + // matrix (so we don't attempt to transform it again). + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: GLGraphicsStateGuardian::draw_triangles +// Access: Public, Virtual +// Description: Draws a series of disconnected triangles. +//////////////////////////////////////////////////////////////////// +bool TinyGraphicsStateGuardian:: +draw_triangles(const GeomPrimitivePipelineReader *reader, bool force) { + PStatTimer timer(_draw_primitive_pcollector, reader->get_current_thread()); + +#ifndef NDEBUG + if (tinydisplay_cat.is_spam()) { + tinydisplay_cat.spam() << "draw_triangles: " << *(reader->get_object()) << "\n"; + } +#endif // NDEBUG + + draw_immediate_simple_primitives(reader, GL_TRIANGLES); + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: GLGraphicsStateGuardian::draw_lines +// Access: Public, Virtual +// Description: Draws a series of disconnected line segments. +//////////////////////////////////////////////////////////////////// +bool TinyGraphicsStateGuardian:: +draw_lines(const GeomPrimitivePipelineReader *reader, bool force) { + PStatTimer timer(_draw_primitive_pcollector, reader->get_current_thread()); +#ifndef NDEBUG + if (tinydisplay_cat.is_spam()) { + tinydisplay_cat.spam() << "draw_lines: " << *(reader->get_object()) << "\n"; + } +#endif // NDEBUG + + draw_immediate_simple_primitives(reader, GL_LINES); + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: GLGraphicsStateGuardian::draw_points +// Access: Public, Virtual +// Description: Draws a series of disconnected points. +//////////////////////////////////////////////////////////////////// +bool TinyGraphicsStateGuardian:: +draw_points(const GeomPrimitivePipelineReader *reader, bool force) { + PStatTimer timer(_draw_primitive_pcollector, reader->get_current_thread()); +#ifndef NDEBUG + if (tinydisplay_cat.is_spam()) { + tinydisplay_cat.spam() << "draw_points: " << *(reader->get_object()) << "\n"; + } +#endif // NDEBUG + + draw_immediate_simple_primitives(reader, GL_POINTS); + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: GLGraphicsStateGuardian::end_draw_primitives() +// Access: Public, Virtual +// Description: Called after a sequence of draw_primitive() +// functions are called, this should do whatever cleanup +// is appropriate. +//////////////////////////////////////////////////////////////////// +void TinyGraphicsStateGuardian:: +end_draw_primitives() { + if (_transform_stale) { + glMatrixMode(GL_MODELVIEW); + glLoadMatrixf(_internal_transform->get_mat().get_data()); + } + + if (_data_reader->is_vertex_transformed()) { + // Restore the matrices that we pushed above. + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + } + + GraphicsStateGuardian::end_draw_primitives(); +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsStateGuardian::framebuffer_copy_to_texture +// Access: Public, Virtual +// Description: Copy the pixels within the indicated display +// region from the framebuffer into texture memory. +// +// If z > -1, it is the cube map index into which to +// copy. +//////////////////////////////////////////////////////////////////// +void TinyGraphicsStateGuardian:: +framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr, + const RenderBuffer &rb) { +} + + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsStateGuardian::framebuffer_copy_to_ram +// Access: Public, Virtual +// Description: Copy the pixels within the indicated display region +// from the framebuffer into system memory, not texture +// memory. Returns true on success, false on failure. +// +// This completely redefines the ram image of the +// indicated texture. +//////////////////////////////////////////////////////////////////// +bool TinyGraphicsStateGuardian:: +framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr, + const RenderBuffer &rb) { + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsStateGuardian::set_state_and_transform +// Access: Public, Virtual +// Description: Simultaneously resets the render state and the +// transform state. +// +// This transform specified is the "internal" net +// transform, already converted into the GSG's internal +// coordinate space by composing it to +// get_cs_transform(). (Previously, this used to be the +// "external" net transform, with the assumption that +// that GSG would convert it internally, but that is no +// longer the case.) +// +// Special case: if (state==NULL), then the target +// state is already stored in _target. +//////////////////////////////////////////////////////////////////// +void TinyGraphicsStateGuardian:: +set_state_and_transform(const RenderState *target, + const TransformState *transform) { +#ifndef NDEBUG + if (tinydisplay_cat.is_spam()) { + tinydisplay_cat.spam() + << "Setting GSG state to " << (void *)target << ":\n"; + target->write(tinydisplay_cat.spam(false), 2); + } +#endif + + _state_pcollector.add_level(1); + PStatTimer timer1(_draw_set_state_pcollector); + + if (transform != _internal_transform) { + PStatTimer timer(_draw_set_state_transform_pcollector); + _state_pcollector.add_level(1); + _internal_transform = transform; + do_issue_transform(); + } + + if (target == _state_rs) { + return; + } + _target_rs = target; + _target.clear_to_defaults(); + target->store_into_slots(&_target); + _state_rs = 0; + + if (_target._color != _state._color || + _target._color_scale != _state._color_scale) { + PStatTimer timer(_draw_set_state_color_pcollector); + do_issue_color(); + do_issue_color_scale(); + _state._color = _target._color; + _state._color_scale = _target._color_scale; + } + + if (_target._cull_face != _state._cull_face) { + PStatTimer timer(_draw_set_state_cull_face_pcollector); + do_issue_cull_face(); + _state._cull_face = _target._cull_face; + } + + if (_target._render_mode != _state._render_mode) { + PStatTimer timer(_draw_set_state_render_mode_pcollector); + do_issue_render_mode(); + _state._render_mode = _target._render_mode; + } + + if (_target._shade_model != _state._shade_model) { + PStatTimer timer(_draw_set_state_shade_model_pcollector); + do_issue_shade_model(); + _state._shade_model = _target._shade_model; + } + + if ((_target._transparency != _state._transparency)|| + (_target._color_write != _state._color_write)|| + (_target._color_blend != _state._color_blend)) { + PStatTimer timer(_draw_set_state_blending_pcollector); + do_issue_blending(); + _state._transparency = _target._transparency; + _state._color_write = _target._color_write; + _state._color_blend = _target._color_blend; + } + + if (_target._texture != _state._texture) { + PStatTimer timer(_draw_set_state_texture_pcollector); + determine_effective_texture(); + do_issue_texture(); + _state._texture = _target._texture; + } + + if (_target._material != _state._material) { + PStatTimer timer(_draw_set_state_material_pcollector); + do_issue_material(); + _state._material = _target._material; + } + + if (_target._light != _state._light) { + PStatTimer timer(_draw_set_state_light_pcollector); + do_issue_light(); + _state._light = _target._light; + } + + _state_rs = _target_rs; +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsStateGuardian::prepare_texture +// Access: Public, Virtual +// Description: Creates whatever structures the GSG requires to +// represent the texture internally, and returns a +// newly-allocated TextureContext object with this data. +// It is the responsibility of the calling function to +// later call release_texture() with this same pointer +// (which will also delete the pointer). +// +// This function should not be called directly to +// prepare a texture. Instead, call Texture::prepare(). +//////////////////////////////////////////////////////////////////// +TextureContext *TinyGraphicsStateGuardian:: +prepare_texture(Texture *tex) { + if (tex->get_texture_type() != Texture::TT_2d_texture) { + tinydisplay_cat.info() + << "not loading texture " << tex->get_name() << ": " + << tex->get_texture_type() << "\n"; + return NULL; + } + if (tex->get_ram_image_compression() != Texture::CM_off) { + tinydisplay_cat.info() + << "not loading texture " << tex->get_name() << ": " + << tex->get_ram_image_compression() << "\n"; + return NULL; + } + if (tex->get_component_type() != Texture::T_unsigned_byte) { + tinydisplay_cat.info() + << "not loading texture " << tex->get_name() << ": " + << tex->get_component_type() << "\n"; + return NULL; + } + + TinyTextureContext *gtc = new TinyTextureContext(_prepared_objects, tex); + glGenTextures(1, >c->_index); + + apply_texture(gtc); + return gtc; +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsStateGuardian::release_texture +// Access: Public, Virtual +// Description: Frees the GL resources previously allocated for the +// texture. This function should never be called +// directly; instead, call Texture::release() (or simply +// let the Texture destruct). +//////////////////////////////////////////////////////////////////// +void TinyGraphicsStateGuardian:: +release_texture(TextureContext *tc) { + TinyTextureContext *gtc = DCAST(TinyTextureContext, tc); + + glDeleteTextures(1, >c->_index); + + gtc->_index = 0; + delete gtc; +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsStateGuardian::enable_lighting +// Access: Protected, Virtual +// Description: Intended to be overridden by a derived class to +// enable or disable the use of lighting overall. This +// is called by do_issue_light() according to whether any +// lights are in use or not. +//////////////////////////////////////////////////////////////////// +void TinyGraphicsStateGuardian:: +enable_lighting(bool enable) { + static PStatCollector _draw_set_state_light_enable_lighting_pcollector("Draw:Set State:Light:Enable lighting"); + PStatTimer timer(_draw_set_state_light_enable_lighting_pcollector); + + if (enable) { + glEnable(GL_LIGHTING); + } else { + glDisable(GL_LIGHTING); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsStateGuardian::set_ambient_light +// Access: Protected, Virtual +// Description: Intended to be overridden by a derived class to +// indicate the color of the ambient light that should +// be in effect. This is called by do_issue_light() after +// all other lights have been enabled or disabled. +//////////////////////////////////////////////////////////////////// +void TinyGraphicsStateGuardian:: +set_ambient_light(const Colorf &color) { + static PStatCollector _draw_set_state_light_ambient_pcollector("Draw:Set State:Light:Ambient"); + PStatTimer timer(_draw_set_state_light_ambient_pcollector); + + glLightModelfv(GL_LIGHT_MODEL_AMBIENT, (float *)color.get_data()); +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsStateGuardian::enable_light +// Access: Protected, Virtual +// Description: Intended to be overridden by a derived class to +// enable the indicated light id. A specific Light will +// already have been bound to this id via bind_light(). +//////////////////////////////////////////////////////////////////// +void TinyGraphicsStateGuardian:: +enable_light(int light_id, bool enable) { + static PStatCollector _draw_set_state_light_enable_light_pcollector("Draw:Set State:Light:Enable light"); + PStatTimer timer(_draw_set_state_light_enable_light_pcollector); + + if (enable) { + glEnable(get_light_id(light_id)); + } else { + glDisable(get_light_id(light_id)); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsStateGuardian::begin_bind_lights +// Access: Protected, Virtual +// Description: Called immediately before bind_light() is called, +// this is intended to provide the derived class a hook +// in which to set up some state (like transform) that +// might apply to several lights. +// +// The sequence is: begin_bind_lights() will be called, +// then one or more bind_light() calls, then +// end_bind_lights(). +//////////////////////////////////////////////////////////////////// +void TinyGraphicsStateGuardian:: +begin_bind_lights() { + static PStatCollector _draw_set_state_light_begin_bind_pcollector("Draw:Set State:Light:Begin bind"); + PStatTimer timer(_draw_set_state_light_begin_bind_pcollector); + + // We need to temporarily load a new matrix so we can define the + // light in a known coordinate system. We pick the transform of the + // root. (Alternatively, we could leave the current transform where + // it is and compute the light position relative to that transform + // instead of relative to the root, by composing with the matrix + // computed by _internal_transform->invert_compose(render_transform). + // But I think loading a completely new matrix is simpler.) + CPT(TransformState) render_transform = + _cs_transform->compose(_scene_setup->get_world_transform()); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadMatrixf(render_transform->get_mat().get_data()); +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsStateGuardian::end_bind_lights +// Access: Protected, Virtual +// Description: Called after before bind_light() has been called one +// or more times (but before any geometry is issued or +// additional state is changed), this is intended to +// clean up any temporary changes to the state that may +// have been made by begin_bind_lights(). +//////////////////////////////////////////////////////////////////// +void TinyGraphicsStateGuardian:: +end_bind_lights() { + static PStatCollector _draw_set_state_light_end_bind_pcollector("Draw:Set State:Light:End bind"); + PStatTimer timer(_draw_set_state_light_end_bind_pcollector); + + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsStateGuardian::do_issue_transform +// Access: Protected +// Description: Sends the indicated transform matrix to the graphics +// API to be applied to future vertices. +// +// This transform is the internal_transform, already +// converted into the GSG's internal coordinate system. +//////////////////////////////////////////////////////////////////// +void TinyGraphicsStateGuardian:: +do_issue_transform() { + const TransformState *transform = _internal_transform; + if (tinydisplay_cat.is_spam()) { + tinydisplay_cat.spam() + << "glLoadMatrix(GL_MODELVIEW): " << transform->get_mat() << endl; + } + + _transform_state_pcollector.add_level(1); + glMatrixMode(GL_MODELVIEW); + glLoadMatrixf(transform->get_mat().get_data()); + _transform_stale = false; +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsStateGuardian::do_issue_shade_model +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +void TinyGraphicsStateGuardian:: +do_issue_shade_model() { + const ShadeModelAttrib *attrib = _target._shade_model; + switch (attrib->get_mode()) { + case ShadeModelAttrib::M_smooth: + glShadeModel(GL_SMOOTH); + break; + + case ShadeModelAttrib::M_flat: + glShadeModel(GL_FLAT); + break; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsStateGuardian::do_issue_render_mode +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +void TinyGraphicsStateGuardian:: +do_issue_render_mode() { + const RenderModeAttrib *attrib = _target._render_mode; + + switch (attrib->get_mode()) { + case RenderModeAttrib::M_unchanged: + case RenderModeAttrib::M_filled: + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + break; + + case RenderModeAttrib::M_wireframe: + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + break; + + case RenderModeAttrib::M_point: + glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); + break; + + default: + tinydisplay_cat.error() + << "Unknown render mode " << (int)attrib->get_mode() << endl; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsStateGuardian::do_issue_cull_face +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +void TinyGraphicsStateGuardian:: +do_issue_cull_face() { + const CullFaceAttrib *attrib = _target._cull_face; + CullFaceAttrib::Mode mode = attrib->get_effective_mode(); + + switch (mode) { + case CullFaceAttrib::M_cull_none: + glDisable(GL_CULL_FACE); + break; + case CullFaceAttrib::M_cull_clockwise: + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + break; + case CullFaceAttrib::M_cull_counter_clockwise: + glEnable(GL_CULL_FACE); + glCullFace(GL_FRONT); + break; + default: + tinydisplay_cat.error() + << "invalid cull face mode " << (int)mode << endl; + break; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsStateGuardian::do_issue_material +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +void TinyGraphicsStateGuardian:: +do_issue_material() { + static Material empty; + const Material *material; + if (_target._material == (MaterialAttrib *)NULL || + _target._material->is_off()) { + material = ∅ + } else { + material = _target._material->get_material(); + } + + GLenum face = material->get_twoside() ? GL_FRONT_AND_BACK : GL_FRONT; + + glMaterialfv(face, GL_SPECULAR, (GLfloat *)material->get_specular().get_data()); + glMaterialfv(face, GL_EMISSION, (GLfloat *)material->get_emission().get_data()); + glMaterialf(face, GL_SHININESS, material->get_shininess()); + + if (material->has_ambient() && material->has_diffuse()) { + // The material has both an ambient and diffuse specified. This + // means we do not need glMaterialColor(). + glDisable(GL_COLOR_MATERIAL); + glMaterialfv(face, GL_AMBIENT, (GLfloat *)material->get_ambient().get_data()); + glMaterialfv(face, GL_DIFFUSE, (GLfloat *)material->get_diffuse().get_data()); + + } else if (material->has_ambient()) { + // The material specifies an ambient, but not a diffuse component. + // The diffuse component comes from the object's color. + glMaterialfv(face, GL_AMBIENT, (GLfloat *)material->get_ambient().get_data()); + if (_has_material_force_color) { + glDisable(GL_COLOR_MATERIAL); + glMaterialfv(face, GL_DIFFUSE, (GLfloat *)_material_force_color.get_data()); + } else { + glColorMaterial(face, GL_DIFFUSE); + glEnable(GL_COLOR_MATERIAL); + } + + } else if (material->has_diffuse()) { + // The material specifies a diffuse, but not an ambient component. + // The ambient component comes from the object's color. + glMaterialfv(face, GL_DIFFUSE, (GLfloat *)material->get_diffuse().get_data()); + if (_has_material_force_color) { + glDisable(GL_COLOR_MATERIAL); + glMaterialfv(face, GL_AMBIENT, (GLfloat *)_material_force_color.get_data()); + } else { + glColorMaterial(face, GL_AMBIENT); + glEnable(GL_COLOR_MATERIAL); + } + + } else { + // The material specifies neither a diffuse nor an ambient + // component. Both components come from the object's color. + if (_has_material_force_color) { + glDisable(GL_COLOR_MATERIAL); + glMaterialfv(face, GL_AMBIENT, (GLfloat *)_material_force_color.get_data()); + glMaterialfv(face, GL_DIFFUSE, (GLfloat *)_material_force_color.get_data()); + } else { + glColorMaterial(face, GL_AMBIENT_AND_DIFFUSE); + glEnable(GL_COLOR_MATERIAL); + } + } + + glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, material->get_local()); +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsStateGuardian::do_issue_texture +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +void TinyGraphicsStateGuardian:: +do_issue_texture() { + glDisable(GL_TEXTURE_2D); + + int num_stages = _effective_texture->get_num_on_ff_stages(); + if (num_stages == 0) { + // No texturing. + return; + } + nassertv(num_stages == 1); + + TextureStage *stage = _effective_texture->get_on_ff_stage(0); + Texture *texture = _effective_texture->get_on_texture(stage); + nassertv(texture != (Texture *)NULL); + + TextureContext *tc = texture->prepare_now(_prepared_objects, this); + if (tc == (TextureContext *)NULL) { + // Something wrong with this texture; skip it. + return; + } + + // Then, turn on the current texture mode. + glEnable(GL_TEXTURE_2D); + apply_texture(tc); + + /* + GLint glmode = get_texture_apply_mode_type(stage->get_mode()); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, glmode); + */ +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsStateGuardian::do_issue_blending +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +void TinyGraphicsStateGuardian:: +do_issue_blending() { + /* + // Handle the color_write attrib. If color_write is off, then + // all the other blending-related stuff doesn't matter. If the + // device doesn't support color-write, we use blending tricks + // to effectively disable color write. + unsigned int color_channels = + _target._color_write->get_channels() & _color_write_mask; + if (color_channels == ColorWriteAttrib::C_off) { + if (_target._color_write != _state._color_write) { + enable_multisample_alpha_one(false); + enable_multisample_alpha_mask(false); + if (CLP(color_mask)) { + enable_blend(false); + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + } else { + enable_blend(true); + _glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_ZERO, GL_ONE); + } + } + return; + } else { + if (_target._color_write != _state._color_write) { + if (CLP(color_mask)) { + glColorMask((color_channels & ColorWriteAttrib::C_red) != 0, + (color_channels & ColorWriteAttrib::C_green) != 0, + (color_channels & ColorWriteAttrib::C_blue) != 0, + (color_channels & ColorWriteAttrib::C_alpha) != 0); + } + } + } + + CPT(ColorBlendAttrib) color_blend = _target._color_blend; + ColorBlendAttrib::Mode color_blend_mode = _target._color_blend->get_mode(); + TransparencyAttrib::Mode transparency_mode = _target._transparency->get_mode(); + + _color_blend_involves_color_scale = color_blend->involves_color_scale(); + + // Is there a color blend set? + if (color_blend_mode != ColorBlendAttrib::M_none) { + enable_multisample_alpha_one(false); + enable_multisample_alpha_mask(false); + enable_blend(true); + _glBlendEquation(get_blend_equation_type(color_blend_mode)); + glBlendFunc(get_blend_func(color_blend->get_operand_a()), + get_blend_func(color_blend->get_operand_b())); + + if (_color_blend_involves_color_scale) { + // Apply the current color scale to the blend mode. + _glBlendColor(_current_color_scale[0], _current_color_scale[1], + _current_color_scale[2], _current_color_scale[3]); + + } else { + Colorf c = color_blend->get_color(); + _glBlendColor(c[0], c[1], c[2], c[3]); + } + return; + } + + // No color blend; is there a transparency set? + switch (transparency_mode) { + case TransparencyAttrib::M_none: + case TransparencyAttrib::M_binary: + break; + + case TransparencyAttrib::M_alpha: + case TransparencyAttrib::M_dual: + enable_multisample_alpha_one(false); + enable_multisample_alpha_mask(false); + enable_blend(true); + _glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + return; + + case TransparencyAttrib::M_multisample: + // We need to enable *both* of these in M_multisample case. + enable_multisample_alpha_one(true); + enable_multisample_alpha_mask(true); + enable_blend(false); + return; + + case TransparencyAttrib::M_multisample_mask: + enable_multisample_alpha_one(false); + enable_multisample_alpha_mask(true); + enable_blend(false); + return; + + default: + tinydisplay_cat.error() + << "invalid transparency mode " << (int)transparency_mode << endl; + break; + } + + if (_line_smooth_enabled || _point_smooth_enabled) { + // If we have either of these turned on, we also need to have + // blend mode enabled in order to see it. + enable_multisample_alpha_one(false); + enable_multisample_alpha_mask(false); + enable_blend(true); + _glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + return; + } + + // For best polygon smoothing, we need: + // (1) a frame buffer that supports alpha + // (2) sort polygons front-to-back + // (3) glBlendFunc(GL_SRC_ALPHA_SATURATE, GL_ONE); + // + // Since these modes have other implications for the application, we + // don't attempt to do this by default. If you really want good + // polygon smoothing (and you don't have multisample support), do + // all this yourself. + + // Nothing's set, so disable blending. + enable_multisample_alpha_one(false); + enable_multisample_alpha_mask(false); + enable_blend(false); + */ +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsStateGuardian::apply_texture +// Access: Protected +// Description: Updates TinyGL with the current information for this +// texture, and makes it the current texture available +// for rendering. +//////////////////////////////////////////////////////////////////// +void TinyGraphicsStateGuardian:: +apply_texture(TextureContext *tc) { + TinyTextureContext *gtc = DCAST(TinyTextureContext, tc); + + gtc->set_active(true); + glBindTexture(GL_TEXTURE_2D, gtc->_index); + + if (gtc->was_image_modified()) { + // If the texture image was modified, reload the texture. + if (!upload_texture(gtc)) { + glDisable(GL_TEXTURE_2D); + } + gtc->mark_loaded(); + + } else if (gtc->was_properties_modified()) { + // If only the properties have been modified, we don't need to + // reload the texture. + gtc->mark_loaded(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsStateGuardian::upload_texture +// Access: Protected +// Description: Uploads the texture image to TinyGL. +// +// The return value is true if successful, or false if +// the texture has no image. +//////////////////////////////////////////////////////////////////// +bool TinyGraphicsStateGuardian:: +upload_texture(TinyTextureContext *gtc) { + Texture *tex = gtc->get_texture(); + PStatTimer timer(_load_texture_pcollector); + + if (tinydisplay_cat.is_debug()) { + tinydisplay_cat.debug() + << "loading texture " << tex->get_name() << "\n"; + } + CPTA_uchar image = tex->get_ram_image(); + nassertr(!image.is_null(), false) + + int width = tex->get_x_size(); + int height = tex->get_y_size(); + + PTA_uchar new_image = restructure_image(tex); + const unsigned char *image_ptr = new_image.p(); + +#ifdef DO_PSTATS + _data_transferred_pcollector.add_level(new_image.size()); +#endif + glTexImage2D(GL_TEXTURE_2D, 0, 3, + width, height, 0, + GL_RGB, GL_UNSIGNED_BYTE, (void *)image_ptr); + +#ifdef DO_PSTATS + gtc->update_data_size_bytes(256 * 256 * 3); +#endif + + tex->texture_uploaded(); + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsStateGuardian::draw_immediate_simple_primitives +// Access: Private +// Description: Uses the ImmediateModeSender to draw a series of +// primitives of the indicated type. +//////////////////////////////////////////////////////////////////// +void TinyGraphicsStateGuardian:: +draw_immediate_simple_primitives(const GeomPrimitivePipelineReader *reader, GLenum mode) { + int num_vertices = reader->get_num_vertices(); + _vertices_immediate_pcollector.add_level(num_vertices); + glBegin(mode); + + if (reader->is_indexed()) { + for (int v = 0; v < num_vertices; ++v) { + _sender.set_vertex(reader->get_vertex(v)); + _sender.issue_vertex(); + } + + } else { + _sender.set_vertex(reader->get_first_vertex()); + for (int v = 0; v < num_vertices; ++v) { + _sender.issue_vertex(); + } + } + + glEnd(); +} diff --git a/panda/src/tinydisplay/tinyGraphicsStateGuardian.h b/panda/src/tinydisplay/tinyGraphicsStateGuardian.h new file mode 100644 index 0000000000..1209913099 --- /dev/null +++ b/panda/src/tinydisplay/tinyGraphicsStateGuardian.h @@ -0,0 +1,132 @@ +// Filename: tinyGraphicsStateGuardian.h +// Created by: drose (24Apr08) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef TINYGRAPHICSSTATEGUARDIAN_H +#define TINYGRAPHICSSTATEGUARDIAN_H + +#include "pandabase.h" + +#include "graphicsStateGuardian.h" +#include "tinyGraphicsPipe.h" +#include "tinyImmediateModeSender.h" + +// These are actually the TinyGL headers, not the system OpenGL headers. +#include "GL/gl.h" + +class TinyTextureContext; + +//////////////////////////////////////////////////////////////////// +// Class : TinyGraphicsStateGuardian +// Description : An interface to TinySDGL (an implementation of TinyGL +// over SDL). +//////////////////////////////////////////////////////////////////// +class TinyGraphicsStateGuardian : public GraphicsStateGuardian { +public: + TinyGraphicsStateGuardian(GraphicsPipe *pipe, + TinyGraphicsStateGuardian *share_with); + + virtual ~TinyGraphicsStateGuardian(); + + virtual void reset(); + + virtual PT(GeomMunger) make_geom_munger(const RenderState *state, + Thread *current_thread); + + virtual void clear(DrawableRegion *clearable); + + virtual void prepare_display_region(DisplayRegionPipelineReader *dr, + Lens::StereoChannel stereo_channel); + virtual CPT(TransformState) calc_projection_mat(const Lens *lens); + virtual bool prepare_lens(); + + virtual bool begin_frame(Thread *current_thread); + virtual bool begin_scene(); + virtual void end_scene(); + virtual void end_frame(Thread *current_thread); + + virtual bool begin_draw_primitives(const GeomPipelineReader *geom_reader, + const GeomMunger *munger, + const GeomVertexDataPipelineReader *data_reader, + bool force); + virtual bool draw_triangles(const GeomPrimitivePipelineReader *reader, + bool force); + virtual bool draw_lines(const GeomPrimitivePipelineReader *reader, + bool force); + virtual bool draw_points(const GeomPrimitivePipelineReader *reader, + bool force); + virtual void end_draw_primitives(); + + virtual void framebuffer_copy_to_texture + (Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb); + virtual bool framebuffer_copy_to_ram + (Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb); + + virtual void set_state_and_transform(const RenderState *state, + const TransformState *transform); + + virtual TextureContext *prepare_texture(Texture *tex); + virtual void release_texture(TextureContext *tc); + + virtual void enable_lighting(bool enable); + virtual void set_ambient_light(const Colorf &color); + virtual void enable_light(int light_id, bool enable); + virtual void begin_bind_lights(); + virtual void end_bind_lights(); + +private: + void do_issue_transform(); + void do_issue_render_mode(); + void do_issue_cull_face(); + void do_issue_shade_model(); + void do_issue_material(); + void do_issue_texture(); + void do_issue_blending(); + + void apply_texture(TextureContext *tc); + bool upload_texture(TinyTextureContext *gtc); + + void draw_immediate_simple_primitives(const GeomPrimitivePipelineReader *reader, GLenum mode); + + INLINE static GLenum get_light_id(int index); + +private: + TinyImmediateModeSender _sender; + + static PStatCollector _vertices_immediate_pcollector; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + GraphicsStateGuardian::init_type(); + register_type(_type_handle, "TinyGraphicsStateGuardian", + GraphicsStateGuardian::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +private: + static TypeHandle _type_handle; +}; + +#include "tinyGraphicsStateGuardian.I" + +#endif diff --git a/panda/src/tinydisplay/tinyGraphicsWindow.I b/panda/src/tinydisplay/tinyGraphicsWindow.I new file mode 100644 index 0000000000..8ec94ffdb8 --- /dev/null +++ b/panda/src/tinydisplay/tinyGraphicsWindow.I @@ -0,0 +1,18 @@ +// Filename: tinyGraphicsWindow.I +// Created by: drose (24Apr08) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + diff --git a/panda/src/tinydisplay/tinyGraphicsWindow.cxx b/panda/src/tinydisplay/tinyGraphicsWindow.cxx new file mode 100644 index 0000000000..ee6a92c855 --- /dev/null +++ b/panda/src/tinydisplay/tinyGraphicsWindow.cxx @@ -0,0 +1,472 @@ +// Filename: tinyGraphicsWindow.cxx +// Created by: drose (24Apr08) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "tinyGraphicsWindow.h" +#include "tinyGraphicsStateGuardian.h" +#include "config_tinydisplay.h" +#include "tinyGraphicsPipe.h" +#include "mouseButton.h" +#include "keyboardButton.h" +#include "graphicsPipe.h" + +// These are actually the TinyGL headers, not the system OpenGL headers. +#include "GL/gl.h" + +TypeHandle TinyGraphicsWindow::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsWindow::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +TinyGraphicsWindow:: +TinyGraphicsWindow(GraphicsPipe *pipe, + const string &name, + const FrameBufferProperties &fb_prop, + const WindowProperties &win_prop, + int flags, + GraphicsStateGuardian *gsg, + GraphicsOutput *host) : + GraphicsWindow(pipe, name, fb_prop, win_prop, flags, gsg, host) +{ + _screen = NULL; + _frame_buffer = NULL; + _pitch = 0; + + GraphicsWindowInputDevice device = + GraphicsWindowInputDevice::pointer_and_keyboard(this, "keyboard/mouse"); + add_input_device(device); +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsWindow::Destructor +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +TinyGraphicsWindow:: +~TinyGraphicsWindow() { +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsWindow::begin_frame +// Access: Public, Virtual +// Description: This function will be called within the draw thread +// before beginning rendering for a given frame. It +// should do whatever setup is required, and return true +// if the frame should be rendered, or false if it +// should be skipped. +//////////////////////////////////////////////////////////////////// +bool TinyGraphicsWindow:: +begin_frame(FrameMode mode, Thread *current_thread) { + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsWindow::end_frame +// Access: Public, Virtual +// Description: This function will be called within the draw thread +// after rendering is completed for a given frame. It +// should do whatever finalization is required. +//////////////////////////////////////////////////////////////////// +void TinyGraphicsWindow:: +end_frame(FrameMode mode, Thread *current_thread) { + if (mode == FM_render) { + trigger_flip(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsWindow::begin_flip +// Access: Public, Virtual +// Description: This function will be called within the draw thread +// after end_frame() has been called on all windows, to +// initiate the exchange of the front and back buffers. +// +// This should instruct the window to prepare for the +// flip at the next video sync, but it should not wait. +// +// We have the two separate functions, begin_flip() and +// end_flip(), to make it easier to flip all of the +// windows at the same time. +//////////////////////////////////////////////////////////////////// +void TinyGraphicsWindow:: +begin_flip() { + if (SDL_MUSTLOCK(_screen)) { + if (SDL_LockSurface(_screen) < 0) { + tinydisplay_cat.error() + << "Can't lock screen: " << SDL_GetError() << "\n"; + } + } + ZB_copyFrameBuffer(_frame_buffer, _screen->pixels, _pitch); + + if (SDL_MUSTLOCK(_screen)) { + SDL_UnlockSurface(_screen); + } + + SDL_Flip(_screen); +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsWindow::process_events +// Access: Public, Virtual +// Description: Do whatever processing is necessary to ensure that +// the window responds to user events. Also, honor any +// requests recently made via request_properties() +// +// This function is called only within the window +// thread. +//////////////////////////////////////////////////////////////////// +void TinyGraphicsWindow:: +process_events() { + GraphicsWindow::process_events(); + + if (_screen == NULL) { + return; + } + + WindowProperties properties; + + SDL_Event evt; + ButtonHandle button; + while (SDL_PollEvent(&evt)) { + switch(evt.type) { + case SDL_KEYDOWN: + if (evt.key.keysym.unicode) { + _input_devices[0].keystroke(evt.key.keysym.unicode); + } + button = get_keyboard_button(evt.key.keysym.sym); + if (button != ButtonHandle::none()) { + _input_devices[0].button_down(button); + } + break; + + case SDL_KEYUP: + button = get_keyboard_button(evt.key.keysym.sym); + if (button != ButtonHandle::none()) { + _input_devices[0].button_up(button); + } + break; + + case SDL_MOUSEBUTTONDOWN: + button = get_mouse_button(evt.button.button); + _input_devices[0].set_pointer_in_window(evt.button.x, evt.button.y); + _input_devices[0].button_down(button); + break; + + case SDL_MOUSEBUTTONUP: + button = get_mouse_button(evt.button.button); + _input_devices[0].set_pointer_in_window(evt.button.x, evt.button.y); + _input_devices[0].button_up(button); + break; + + case SDL_MOUSEMOTION: + _input_devices[0].set_pointer_in_window(evt.motion.x, evt.motion.y); + break; + + case SDL_QUIT: + // The window was closed by the user. + close_window(); + properties.set_open(false); + system_changed_properties(properties); + break; + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsWindow::set_properties_now +// Access: Public, Virtual +// Description: Applies the requested set of properties to the +// window, if possible, for instance to request a change +// in size or minimization status. +// +// The window properties are applied immediately, rather +// than waiting until the next frame. This implies that +// this method may *only* be called from within the +// window thread. +// +// The return value is true if the properties are set, +// false if they are ignored. This is mainly useful for +// derived classes to implement extensions to this +// function. +//////////////////////////////////////////////////////////////////// +void TinyGraphicsWindow:: +set_properties_now(WindowProperties &properties) { + GraphicsWindow::set_properties_now(properties); + if (!properties.is_any_specified()) { + // The base class has already handled this case. + return; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsWindow::close_window +// Access: Protected, Virtual +// Description: Closes the window right now. Called from the window +// thread. +//////////////////////////////////////////////////////////////////// +void TinyGraphicsWindow:: +close_window() { + GraphicsWindow::close_window(); +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsWindow::open_window +// Access: Protected, Virtual +// Description: Opens the window right now. Called from the window +// thread. Returns true if the window is successfully +// opened, or false if there was a problem. +//////////////////////////////////////////////////////////////////// +bool TinyGraphicsWindow:: +open_window() { + + // GSG Creation/Initialization + TinyGraphicsStateGuardian *tinygsg; + if (_gsg == 0) { + // There is no old gsg. Create a new one. + tinygsg = new TinyGraphicsStateGuardian(_pipe, NULL); + _gsg = tinygsg; + + } else { + DCAST_INTO_R(tinygsg, _gsg, false); + } + + _screen = SDL_SetVideoMode(_properties.get_x_size(), _properties.get_y_size(), 32, SDL_SWSURFACE); + + if (_screen == NULL) { + tinydisplay_cat.error() + << "Video mode set failed.\n"; + return false; + } + + // initialize TinyGL: + int mode; + switch (_screen->format->BitsPerPixel) { + case 8: + tinydisplay_cat.error() + << "SDL Palettes are currently not supported.\n"; + return false; + + case 16: + _pitch = _screen->pitch; + mode = ZB_MODE_5R6G5B; + break; + case 24: + _pitch = (_screen->pitch * 2) / 3; + mode = ZB_MODE_RGB24; + break; + case 32: + _pitch = _screen->pitch / 2; + mode = ZB_MODE_RGBA; + break; + + default: + return false; + break; + } + + _frame_buffer = ZB_open(_properties.get_x_size(), _properties.get_y_size(), mode, 0, 0, 0, 0); + glInit(_frame_buffer); + + // Now that we have made the context current to a window, we can + // reset the GSG state if this is the first time it has been used. + // (We can't just call reset() when we construct the GSG, because + // reset() requires having a current context.) + tinygsg->reset_if_new(); + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsWindow::get_keyboard_button +// Access: Private, Static +// Description: Maps from an SDL keysym to the corresponding Panda +// ButtonHandle. +//////////////////////////////////////////////////////////////////// +ButtonHandle TinyGraphicsWindow:: +get_keyboard_button(SDLKey sym) { + switch (sym) { + case SDLK_BACKSPACE: return KeyboardButton::backspace(); + case SDLK_TAB: return KeyboardButton::tab(); + // case SDLK_CLEAR: return KeyboardButton::clear(); + case SDLK_RETURN: return KeyboardButton::enter(); + // case SDLK_PAUSE: return KeyboardButton::pause(); + case SDLK_ESCAPE: return KeyboardButton::escape(); + case SDLK_SPACE: return KeyboardButton::space(); + case SDLK_EXCLAIM: return KeyboardButton::ascii_key('!'); + case SDLK_QUOTEDBL: return KeyboardButton::ascii_key('"'); + case SDLK_HASH: return KeyboardButton::ascii_key('#'); + case SDLK_DOLLAR: return KeyboardButton::ascii_key('$'); + case SDLK_AMPERSAND: return KeyboardButton::ascii_key('&'); + case SDLK_QUOTE: return KeyboardButton::ascii_key('\''); + case SDLK_LEFTPAREN: return KeyboardButton::ascii_key('('); + case SDLK_RIGHTPAREN: return KeyboardButton::ascii_key(')'); + case SDLK_ASTERISK: return KeyboardButton::ascii_key('*'); + case SDLK_PLUS: return KeyboardButton::ascii_key('+'); + case SDLK_COMMA: return KeyboardButton::ascii_key(','); + case SDLK_MINUS: return KeyboardButton::ascii_key('-'); + case SDLK_PERIOD: return KeyboardButton::ascii_key('.'); + case SDLK_SLASH: return KeyboardButton::ascii_key('/'); + case SDLK_0: return KeyboardButton::ascii_key('0'); + case SDLK_1: return KeyboardButton::ascii_key('1'); + case SDLK_2: return KeyboardButton::ascii_key('2'); + case SDLK_3: return KeyboardButton::ascii_key('3'); + case SDLK_4: return KeyboardButton::ascii_key('4'); + case SDLK_5: return KeyboardButton::ascii_key('5'); + case SDLK_6: return KeyboardButton::ascii_key('6'); + case SDLK_7: return KeyboardButton::ascii_key('7'); + case SDLK_8: return KeyboardButton::ascii_key('8'); + case SDLK_9: return KeyboardButton::ascii_key('9'); + case SDLK_COLON: return KeyboardButton::ascii_key(':'); + case SDLK_SEMICOLON: return KeyboardButton::ascii_key(';'); + case SDLK_LESS: return KeyboardButton::ascii_key('<'); + case SDLK_EQUALS: return KeyboardButton::ascii_key('='); + case SDLK_GREATER: return KeyboardButton::ascii_key('>'); + case SDLK_QUESTION: return KeyboardButton::ascii_key('?'); + case SDLK_AT: return KeyboardButton::ascii_key('@'); + case SDLK_LEFTBRACKET: return KeyboardButton::ascii_key('['); + case SDLK_BACKSLASH: return KeyboardButton::ascii_key('\\'); + case SDLK_RIGHTBRACKET: return KeyboardButton::ascii_key(']'); + case SDLK_CARET: return KeyboardButton::ascii_key('^'); + case SDLK_UNDERSCORE: return KeyboardButton::ascii_key('_'); + case SDLK_BACKQUOTE: return KeyboardButton::ascii_key('`'); + case SDLK_a: return KeyboardButton::ascii_key('a'); + case SDLK_b: return KeyboardButton::ascii_key('b'); + case SDLK_c: return KeyboardButton::ascii_key('c'); + case SDLK_d: return KeyboardButton::ascii_key('d'); + case SDLK_e: return KeyboardButton::ascii_key('e'); + case SDLK_f: return KeyboardButton::ascii_key('f'); + case SDLK_g: return KeyboardButton::ascii_key('g'); + case SDLK_h: return KeyboardButton::ascii_key('h'); + case SDLK_i: return KeyboardButton::ascii_key('i'); + case SDLK_j: return KeyboardButton::ascii_key('j'); + case SDLK_k: return KeyboardButton::ascii_key('k'); + case SDLK_l: return KeyboardButton::ascii_key('l'); + case SDLK_m: return KeyboardButton::ascii_key('m'); + case SDLK_n: return KeyboardButton::ascii_key('n'); + case SDLK_o: return KeyboardButton::ascii_key('o'); + case SDLK_p: return KeyboardButton::ascii_key('p'); + case SDLK_q: return KeyboardButton::ascii_key('q'); + case SDLK_r: return KeyboardButton::ascii_key('r'); + case SDLK_s: return KeyboardButton::ascii_key('s'); + case SDLK_t: return KeyboardButton::ascii_key('t'); + case SDLK_u: return KeyboardButton::ascii_key('u'); + case SDLK_v: return KeyboardButton::ascii_key('v'); + case SDLK_w: return KeyboardButton::ascii_key('w'); + case SDLK_x: return KeyboardButton::ascii_key('x'); + case SDLK_y: return KeyboardButton::ascii_key('y'); + case SDLK_z: return KeyboardButton::ascii_key('z'); + case SDLK_DELETE: return KeyboardButton::del(); + case SDLK_KP0: return KeyboardButton::ascii_key('0'); + case SDLK_KP1: return KeyboardButton::ascii_key('1'); + case SDLK_KP2: return KeyboardButton::ascii_key('2'); + case SDLK_KP3: return KeyboardButton::ascii_key('3'); + case SDLK_KP4: return KeyboardButton::ascii_key('4'); + case SDLK_KP5: return KeyboardButton::ascii_key('5'); + case SDLK_KP6: return KeyboardButton::ascii_key('6'); + case SDLK_KP7: return KeyboardButton::ascii_key('7'); + case SDLK_KP8: return KeyboardButton::ascii_key('8'); + case SDLK_KP9: return KeyboardButton::ascii_key('9'); + case SDLK_KP_PERIOD: return KeyboardButton::ascii_key('.'); + case SDLK_KP_DIVIDE: return KeyboardButton::ascii_key('/'); + case SDLK_KP_MULTIPLY: return KeyboardButton::ascii_key('*'); + case SDLK_KP_MINUS: return KeyboardButton::ascii_key('-'); + case SDLK_KP_PLUS: return KeyboardButton::ascii_key('+'); + case SDLK_KP_ENTER: return KeyboardButton::enter(); + case SDLK_KP_EQUALS: return KeyboardButton::ascii_key('='); + case SDLK_UP: return KeyboardButton::up(); + case SDLK_DOWN: return KeyboardButton::down(); + case SDLK_RIGHT: return KeyboardButton::right(); + case SDLK_LEFT: return KeyboardButton::left(); + case SDLK_INSERT: return KeyboardButton::insert(); + case SDLK_HOME: return KeyboardButton::home(); + case SDLK_END: return KeyboardButton::end(); + case SDLK_PAGEUP: return KeyboardButton::page_up(); + case SDLK_PAGEDOWN: return KeyboardButton::page_down(); + case SDLK_F1: return KeyboardButton::f1(); + case SDLK_F2: return KeyboardButton::f2(); + case SDLK_F3: return KeyboardButton::f3(); + case SDLK_F4: return KeyboardButton::f4(); + case SDLK_F5: return KeyboardButton::f5(); + case SDLK_F6: return KeyboardButton::f6(); + case SDLK_F7: return KeyboardButton::f7(); + case SDLK_F8: return KeyboardButton::f8(); + case SDLK_F9: return KeyboardButton::f9(); + case SDLK_F10: return KeyboardButton::f10(); + case SDLK_F11: return KeyboardButton::f11(); + case SDLK_F12: return KeyboardButton::f12(); + case SDLK_F13: return KeyboardButton::f13(); + case SDLK_F14: return KeyboardButton::f14(); + case SDLK_F15: return KeyboardButton::f15(); + // case SDLK_NUMLOCK: return KeyboardButton::numlock(); + // case SDLK_CAPSLOCK: return KeyboardButton::capslock(); + // case SDLK_SCROLLOCK: return KeyboardButton::scrollock(); + case SDLK_RSHIFT: return KeyboardButton::rshift(); + case SDLK_LSHIFT: return KeyboardButton::lshift(); + case SDLK_RCTRL: return KeyboardButton::rcontrol(); + case SDLK_LCTRL: return KeyboardButton::lcontrol(); + case SDLK_RALT: return KeyboardButton::ralt(); + case SDLK_LALT: return KeyboardButton::lalt(); + case SDLK_RMETA: return KeyboardButton::ralt(); + case SDLK_LMETA: return KeyboardButton::lalt(); + // case SDLK_LSUPER: return KeyboardButton::left(); + // case SDLK_RSUPER: return KeyboardButton::right(); + // case SDLK_MODE: return KeyboardButton::mode(); + case SDLK_HELP: return KeyboardButton::help(); + // case SDLK_PRINT: return KeyboardButton::print-screen(); + // case SDLK_SYSREQ: return KeyboardButton::SysRq(); + // case SDLK_BREAK: return KeyboardButton::break(); + // case SDLK_MENU: return KeyboardButton::menu(); + // case SDLK_POWER: return KeyboardButton::power(); + // case SDLK_EURO: return KeyboardButton::euro(); + } + tinydisplay_cat.info() + << "unhandled keyboard button " << sym << "\n"; + + return ButtonHandle::none(); +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsWindow::get_mouse_button +// Access: Private, Static +// Description: Maps from an SDL mouse button index to the +// corresponding Panda ButtonHandle. +//////////////////////////////////////////////////////////////////// +ButtonHandle TinyGraphicsWindow:: +get_mouse_button(Uint8 button) { + switch (button) { + case SDL_BUTTON_LEFT: + return MouseButton::one(); + + case SDL_BUTTON_MIDDLE: + return MouseButton::two(); + + case SDL_BUTTON_RIGHT: + return MouseButton::three(); + + case SDL_BUTTON_WHEELUP: + return MouseButton::wheel_up(); + + case SDL_BUTTON_WHEELDOWN: + return MouseButton::wheel_down(); + } + tinydisplay_cat.info() + << "unhandled mouse button " << button << "\n"; + + return ButtonHandle::none(); +} diff --git a/panda/src/tinydisplay/tinyGraphicsWindow.h b/panda/src/tinydisplay/tinyGraphicsWindow.h new file mode 100644 index 0000000000..524a6de7a4 --- /dev/null +++ b/panda/src/tinydisplay/tinyGraphicsWindow.h @@ -0,0 +1,89 @@ +// Filename: tinyGraphicsWindow.h +// Created by: drose (24Apr08) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef TINYGRAPHICSWINDOW_H +#define TINYGRAPHICSWINDOW_H + +#include "pandabase.h" + +#include "tinyGraphicsPipe.h" +#include "graphicsWindow.h" +#include "buttonHandle.h" + +extern "C" { + #include "SDL.h" + #include "zbuffer.h" +} + +//////////////////////////////////////////////////////////////////// +// Class : TinyGraphicsWindow +// Description : An interface to TinySDGL (an implementation of TinyGL +// over SDL). +//////////////////////////////////////////////////////////////////// +class TinyGraphicsWindow : public GraphicsWindow { +public: + TinyGraphicsWindow(GraphicsPipe *pipe, + const string &name, + const FrameBufferProperties &fb_prop, + const WindowProperties &win_prop, + int flags, + GraphicsStateGuardian *gsg, + GraphicsOutput *host); + virtual ~TinyGraphicsWindow(); + + virtual bool begin_frame(FrameMode mode, Thread *current_thread); + virtual void end_frame(FrameMode mode, Thread *current_thread); + virtual void begin_flip(); + + virtual void process_events(); + virtual void set_properties_now(WindowProperties &properties); + +protected: + virtual void close_window(); + virtual bool open_window(); + +private: + static ButtonHandle get_keyboard_button(SDLKey sym); + static ButtonHandle get_mouse_button(Uint8 button); + +private: + SDL_Surface *_screen; + ZBuffer *_frame_buffer; + unsigned int _pitch; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + GraphicsWindow::init_type(); + register_type(_type_handle, "TinyGraphicsWindow", + GraphicsWindow::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +private: + static TypeHandle _type_handle; +}; + +#include "tinyGraphicsWindow.I" + +#endif diff --git a/panda/src/tinydisplay/tinyImmediateModeSender.I b/panda/src/tinydisplay/tinyImmediateModeSender.I new file mode 100644 index 0000000000..9f6a62dd58 --- /dev/null +++ b/panda/src/tinydisplay/tinyImmediateModeSender.I @@ -0,0 +1,101 @@ +// Filename: glImmediateModeSender_src.I +// Created by: drose (15Aug05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: TinyImmediateModeSender::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE TinyImmediateModeSender:: +TinyImmediateModeSender() { +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyImmediateModeSender::ComponentSender::Constructor +// Access: Public +// Description: The ComponentSender becomes the owner of the +// GeomVertexReader pointer, and will delete it when it +// is done. +//////////////////////////////////////////////////////////////////// +INLINE TinyImmediateModeSender::ComponentSender:: +ComponentSender(GeomVertexReader *reader) : + _reader(reader) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyImmediateModeSender::ComponentSender::set_vertex +// Access: Public +// Description: Specifies the vertex index of the next vertex to +// send. If this is not called, the next consecutive +// vertex will be sent. +//////////////////////////////////////////////////////////////////// +INLINE void TinyImmediateModeSender::ComponentSender:: +set_vertex(int vertex_index) { + _reader->set_row(vertex_index); +} + + +//////////////////////////////////////////////////////////////////// +// Function: TinyImmediateModeSender::ComponentSender1f::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE TinyImmediateModeSender::ComponentSender1f:: +ComponentSender1f(GeomVertexReader *reader, Func1f *func) : + ComponentSender(reader), + _func(func) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyImmediateModeSender::ComponentSender2f::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE TinyImmediateModeSender::ComponentSender2f:: +ComponentSender2f(GeomVertexReader *reader, Func2f *func) : + ComponentSender(reader), + _func(func) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyImmediateModeSender::ComponentSender3f::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE TinyImmediateModeSender::ComponentSender3f:: +ComponentSender3f(GeomVertexReader *reader, Func3f *func) : + ComponentSender(reader), + _func(func) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyImmediateModeSender::ComponentSender4f::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE TinyImmediateModeSender::ComponentSender4f:: +ComponentSender4f(GeomVertexReader *reader, Func4f *func) : + ComponentSender(reader), + _func(func) +{ +} diff --git a/panda/src/tinydisplay/tinyImmediateModeSender.cxx b/panda/src/tinydisplay/tinyImmediateModeSender.cxx new file mode 100644 index 0000000000..b78172327b --- /dev/null +++ b/panda/src/tinydisplay/tinyImmediateModeSender.cxx @@ -0,0 +1,232 @@ +// Filename: glImmediateModeSender_src.cxx +// Created by: drose (15Aug05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "tinyImmediateModeSender.h" +#include "config_tinydisplay.h" + +//////////////////////////////////////////////////////////////////// +// Function: TinyImmediateModeSender::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +TinyImmediateModeSender:: +~TinyImmediateModeSender() { + clear(); +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyImmediateModeSender::clear +// Access: Public +// Description: Removes (and deletes) all of the senders from the +// object. +//////////////////////////////////////////////////////////////////// +void TinyImmediateModeSender:: +clear() { + ComponentSenders::iterator si; + for (si = _senders.begin(); si != _senders.end(); ++si) { + delete (*si); + } + _senders.clear(); +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyImmediateModeSender::set_vertex +// Access: Public +// Description: Specifies the vertex index of the next vertex to +// send. If this is not called, the next consecutive +// vertex will be sent. +//////////////////////////////////////////////////////////////////// +void TinyImmediateModeSender:: +set_vertex(int vertex_index) { + ComponentSenders::iterator si; + for (si = _senders.begin(); si != _senders.end(); ++si) { + (*si)->set_vertex(vertex_index); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyImmediateModeSender::issue_vertex +// Access: Public +// Description: Sends the next vertex to the OpenGL API. +//////////////////////////////////////////////////////////////////// +void TinyImmediateModeSender:: +issue_vertex() { + ComponentSenders::iterator si; + for (si = _senders.begin(); si != _senders.end(); ++si) { + (*si)->issue_vertex(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyImmediateModeSender::add_column +// Access: Public +// Description: Creates a new ComponentSender for the named data +// column, if it exists in the vertex data, and adds it +// to the list of senders for this object. +// +// The four function pointers are the four variants on +// the function pointer for the possible number of +// components of the data column. The appropriate +// pointer will be used, depending on the number of +// components the data column actually uses. +// +// The return value is true if the column is added, +// false if it is not for some reason (for instance, the +// named column doesn't exist in the vertex data). +//////////////////////////////////////////////////////////////////// +bool TinyImmediateModeSender:: +add_column(const GeomVertexDataPipelineReader *data_reader, const InternalName *name, + Func1f *func1f, Func2f *func2f, Func3f *func3f, Func4f *func4f) { + if (data_reader->has_column(name)) { + GeomVertexReader *reader = new GeomVertexReader(data_reader, name); + ComponentSender *sender = NULL; + const GeomVertexColumn *column = reader->get_column(); + switch (column->get_num_components()) { + case 1: + if (func1f != (Func1f *)NULL) { + sender = new ComponentSender1f(reader, func1f); + } + break; + + case 2: + if (func2f != (Func2f *)NULL) { + sender = new ComponentSender2f(reader, func2f); + } + break; + + case 3: + if (func3f != (Func3f *)NULL) { + sender = new ComponentSender3f(reader, func3f); + } + break; + + case 4: + if (func4f != (Func4f *)NULL) { + sender = new ComponentSender4f(reader, func4f); + } + break; + } + + if (sender != (ComponentSender *)NULL) { + // Ok, we've got a valid sender; add it to the list. + _senders.push_back(sender); + return true; + + } else { + // We didn't get a valid sender; clean up and return. + delete reader; + } + } + + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyImmediateModeSender::add_sender +// Access: Public +// Description: Adds a new ComponentSender to the list of senders for +// this object. The GLImmediateModeSender object +// becomes the owner of the ComponentSender pointer and +// will delete it when it is done. +//////////////////////////////////////////////////////////////////// +void TinyImmediateModeSender:: +add_sender(ComponentSender *sender) { + _senders.push_back(sender); +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyImmediateModeSender::ComponentSender::Destructor +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +TinyImmediateModeSender::ComponentSender:: +~ComponentSender() { + delete _reader; +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyImmediateModeSender::ComponentSender1f::issue_vertex +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void TinyImmediateModeSender::ComponentSender1f:: +issue_vertex() { + float d = _reader->get_data1f(); +#ifndef NDEBUG + if (tinydisplay_cat.is_spam()) { + tinydisplay_cat.spam() + << *_reader->get_column()->get_name() << ": " << d << "\n"; + } +#endif // NDEBUG + + (*_func)(d); +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyImmediateModeSender::ComponentSender2f::issue_vertex +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void TinyImmediateModeSender::ComponentSender2f:: +issue_vertex() { + const LVecBase2f &d = _reader->get_data2f(); +#ifndef NDEBUG + if (tinydisplay_cat.is_spam()) { + tinydisplay_cat.spam() + << *_reader->get_column()->get_name() << ": " << d << "\n"; + } +#endif // NDEBUG + + (*_func)(d[0], d[1]); +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyImmediateModeSender::ComponentSender3f::issue_vertex +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void TinyImmediateModeSender::ComponentSender3f:: +issue_vertex() { + const LVecBase3f &d = _reader->get_data3f(); +#ifndef NDEBUG + if (tinydisplay_cat.is_spam()) { + tinydisplay_cat.spam() + << *_reader->get_column()->get_name() << ": " << d << "\n"; + } +#endif // NDEBUG + + (*_func)(d[0], d[1], d[2]); +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyImmediateModeSender::ComponentSender4f::issue_vertex +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void TinyImmediateModeSender::ComponentSender4f:: +issue_vertex() { + const LVecBase4f &d = _reader->get_data4f(); +#ifndef NDEBUG + if (tinydisplay_cat.is_spam()) { + tinydisplay_cat.spam() + << *_reader->get_column()->get_name() << ": " << d << "\n"; + } +#endif // NDEBUG + + (*_func)(d[0], d[1], d[2], d[3]); +} diff --git a/panda/src/tinydisplay/tinyImmediateModeSender.h b/panda/src/tinydisplay/tinyImmediateModeSender.h new file mode 100644 index 0000000000..84cd0d043c --- /dev/null +++ b/panda/src/tinydisplay/tinyImmediateModeSender.h @@ -0,0 +1,114 @@ +// Filename: tinyImmediateModeSender.h +// Created by: drose (29Apr08) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef TINYIMMEDIATEMODESENDER_H +#define TINYIMMEDIATEMODESENDER_H + +#include "pandabase.h" +#include "geomVertexReader.h" + +// These are actually the TinyGL headers, not the system OpenGL headers. +#include "GL/gl.h" + +//////////////////////////////////////////////////////////////////// +// Class : TinyImmediateModeSender +// Description : This class collects together a handful of objects +// that will issue immediate-mode commands like +// glVertex, glTexCoord, etc., for the purposes of +// sending an object's vertices using the immediate mode +// functions. +// +// Since unlike OpenGL, TinyGL prefers the +// immediate-mode interface, this is used all of the +// time. +//////////////////////////////////////////////////////////////////// +class TinyImmediateModeSender { +public: + INLINE TinyImmediateModeSender(); + ~TinyImmediateModeSender(); + + void clear(); + + void set_vertex(int vertex_index); + void issue_vertex(); + + class ComponentSender; + typedef void Func1f(GLfloat a); + typedef void Func2f(GLfloat a, GLfloat b); + typedef void Func3f(GLfloat a, GLfloat b, GLfloat c); + typedef void Func4f(GLfloat a, GLfloat b, GLfloat c, GLfloat d); + + bool add_column(const GeomVertexDataPipelineReader *data_reader, + const InternalName *name, Func1f *func1f, + Func2f *func2f, Func3f *func3f, Func4f *func4f); + + void add_sender(ComponentSender *sender); + +public: + + class ComponentSender { + public: + INLINE ComponentSender(GeomVertexReader *reader); + virtual ~ComponentSender(); + INLINE void set_vertex(int vertex_index); + virtual void issue_vertex()=0; + protected: + GeomVertexReader *_reader; + }; + + class ComponentSender1f : public ComponentSender { + public: + INLINE ComponentSender1f(GeomVertexReader *reader, Func1f *func); + virtual void issue_vertex(); + private: + Func1f *_func; + }; + + class ComponentSender2f : public ComponentSender { + public: + INLINE ComponentSender2f(GeomVertexReader *reader, Func2f *func); + virtual void issue_vertex(); + private: + Func2f *_func; + }; + + class ComponentSender3f : public ComponentSender { + public: + INLINE ComponentSender3f(GeomVertexReader *reader, Func3f *func); + virtual void issue_vertex(); + private: + Func3f *_func; + }; + + class ComponentSender4f : public ComponentSender { + public: + INLINE ComponentSender4f(GeomVertexReader *reader, Func4f *func); + virtual void issue_vertex(); + private: + Func4f *_func; + }; + +private: + typedef pvector ComponentSenders; + ComponentSenders _senders; +}; + +#include "tinyImmediateModeSender.I" + +#endif // SUPPORT_IMMEDIATE_MODE + diff --git a/panda/src/tinydisplay/tinyTextureContext.I b/panda/src/tinydisplay/tinyTextureContext.I new file mode 100644 index 0000000000..68f5390f8d --- /dev/null +++ b/panda/src/tinydisplay/tinyTextureContext.I @@ -0,0 +1,30 @@ +// Filename: tinyTextureContext.I +// Created by: drose (30Apr08) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: TinyTextureContext::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE TinyTextureContext:: +TinyTextureContext(PreparedGraphicsObjects *pgo, Texture *tex) : + TextureContext(pgo, tex) +{ + _index = 0; +} diff --git a/panda/src/tinydisplay/tinyTextureContext.cxx b/panda/src/tinydisplay/tinyTextureContext.cxx new file mode 100644 index 0000000000..44d0b1a2da --- /dev/null +++ b/panda/src/tinydisplay/tinyTextureContext.cxx @@ -0,0 +1,21 @@ +// Filename: tinyTextureContext.cxx +// Created by: drose (30Apr08) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "tinyTextureContext.h" + +TypeHandle TinyTextureContext::_type_handle; diff --git a/panda/src/tinydisplay/tinyTextureContext.h b/panda/src/tinydisplay/tinyTextureContext.h new file mode 100644 index 0000000000..e97dd84dae --- /dev/null +++ b/panda/src/tinydisplay/tinyTextureContext.h @@ -0,0 +1,61 @@ +// Filename: tinyTextureContext.h +// Created by: drose (30Apr08) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef TINYTEXTURECONTEXT_H +#define TINYTEXTURECONTEXT_H + +#include "pandabase.h" +#include "textureContext.h" +#include "deletedChain.h" + +// These are actually the TinyGL headers, not the system OpenGL headers. +#include "GL/gl.h" + +//////////////////////////////////////////////////////////////////// +// Class : TinyTextureContext +// Description : +//////////////////////////////////////////////////////////////////// +class TinyTextureContext : public TextureContext { +public: + INLINE TinyTextureContext(PreparedGraphicsObjects *pgo, Texture *tex); + ALLOC_DELETED_CHAIN(TinyTextureContext); + + // This is the GL "name" of the texture object. + GLuint _index; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + TextureContext::init_type(); + register_type(_type_handle, "TinyTextureContext", + TextureContext::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +private: + static TypeHandle _type_handle; +}; + +#include "tinyTextureContext.I" + +#endif