// --------------------------------------------------------------------------- // // @file TwAdvanced1.cpp // @brief An example showing many features of AntTweakBar, // including variable accessed by callbacks and // the definition of a custom structure type. // It also uses OpenGL and GLFW windowing system // but could be easily adapted to other frameworks. // // AntTweakBar: http://anttweakbar.sourceforge.net/doc // OpenGL: http://www.opengl.org // GLFW: http://www.glfw.org // // // This example draws a simple scene that can be re-tesselated // interactively, and illuminated dynamically by an adjustable // number of moving lights. // // // @author Philippe Decaudin // @date 2006/05/20 // // --------------------------------------------------------------------------- #include #define GLFW_DLL // use GLFW as a dynamically linked library #include "glfw.h" #include #include #include #include #if !defined(_WIN32) && !defined(_WIN64) # define _snprintf snprintf #endif const float FLOAT_2PI = 6.283185307f; // 2*PI // Light structure: embeds light parameters struct Light { bool Active; // light On or Off float Pos[4]; // light position (in homogeneous coordinates, ie. Pos[4]=1) float Color[4]; // light color (no alpha, ie. Color[4]=1) float Radius; // radius of the light influence area float Dist0, Angle0, Height0, Speed0; // light initial cylindrical coordinates and speed char Name[4]; // light short name (will be named "1", "2", "3",...) enum AnimMode { ANIM_FIXED, ANIM_BOUNCE, ANIM_ROTATE, ANIM_COMBINED }; AnimMode Animation; // light animation mode }; // Class that describes the scene and its methods class Scene { public: bool Wireframe; // draw scene in wireframe or filled int Subdiv; // number of subdivisions used to tessellate the scene int NumLights; // number of dynamic lights float BgColor0[3], BgColor1[3]; // top and bottom background colors float Ambient; // scene ambient factor float Reflection; // ground plane reflection factor (0=no reflection, 1=full reflection) double RotYAngle; // rotation angle of the scene around its Y axis (in degree) enum RotMode { ROT_OFF, ROT_CW, ROT_CCW }; RotMode Rotation; // scene rotation mode (off, clockwise, counter-clockwise) Scene(); // constructor ~Scene(); // destructor void Init(bool changeLightPos); // (re)initialize the scene void Draw() const; // draw scene void Update(double time); // move lights private: void CreateBar(); // create a tweak bar for lights // Some drawing subroutines void DrawSubdivPlaneY(float xMin, float xMax, float y, float zMin, float zMax, int xSubdiv, int zSubdiv) const; void DrawSubdivCylinderY(float xCenter, float yBottom, float zCenter, float height, float radiusBottom, float radiusTop, int sideSubdiv, int ySubdiv) const; void DrawSubdivHaloZ(float x, float y, float z, float radius, int subdiv) const; void DrawHalos(bool reflected) const; GLuint objList, groundList, haloList; // OpenGL display list IDs int maxLights; // maximum number of dynamic lights allowed by the graphic card Light * lights; // array of lights TwBar * lightsBar; // pointer to the tweak bar for lights created by CreateBar() }; // Constructor Scene::Scene() { // Set scene members. // The scene will be created by Scene::Init( ) Wireframe = false; Subdiv = 20; NumLights = 0; BgColor0[0] = 0.9f; BgColor0[1] = 0.0f; BgColor0[2] = 0.0f; BgColor1[0] = 0.3f; BgColor1[1] = 0.0f; BgColor1[2] = 0.0f; Ambient = 0.2f; Reflection = 0.5f; RotYAngle = 0; Rotation = ROT_CCW; objList = 0; groundList = 0; haloList = 0; maxLights = 0; lights = NULL; lightsBar = NULL; } // Destructor Scene::~Scene() { // delete all lights if( lights ) delete[] lights; } // Create the scene, and (re)initialize lights if changeLights is true void Scene::Init(bool changeLights) { // Get the max number of lights allowed by the graphic card glGetIntegerv(GL_MAX_LIGHTS, &maxLights); if( maxLights>16 ) maxLights = 16; // Create the lights array if( lights==NULL && maxLights>0 ) { lights = new Light[maxLights]; NumLights = 3; // default number of lights if( NumLights>maxLights ) NumLights = maxLights; changeLights = true; // force lights initialization // Create a tweak bar for lights CreateBar(); } // (Re)initialize lights if needed (uses random values) if( changeLights ) for(int i=0; ilights[i].Color[1]) ? 1.0f-lights[i].Color[1] : 1.0f-lights[i].Color[0]; lights[i].Color[3] = 1; lights[i].Active = true; } // Initialize some OpenGL states glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glEnable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_LIGHTING); glEnable(GL_CULL_FACE); glEnable(GL_NORMALIZE); glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE); // Create objects display list using the current Subdiv parameter to control the tesselation if( objList>0 ) glDeleteLists(objList, 1); // delete previously created display list objList = glGenLists(1); glNewList(objList, GL_COMPILE); DrawSubdivCylinderY(-0.9f, 0, -0.9f, 1.4f, 0.15f, 0.12f, Subdiv/2+8, Subdiv); DrawSubdivCylinderY(+0.9f, 0, -0.9f, 1.4f, 0.15f, 0.12f, Subdiv/2+8, Subdiv); DrawSubdivCylinderY(+0.9f, 0, +0.9f, 1.4f, 0.15f, 0.12f, Subdiv/2+8, Subdiv); DrawSubdivCylinderY(-0.9f, 0, +0.9f, 1.4f, 0.15f, 0.12f, Subdiv/2+8, Subdiv); DrawSubdivCylinderY(0, 0, 0, 0.4f, 0.5f, 0.3f, Subdiv+16, Subdiv/8+1); DrawSubdivCylinderY(0, 0.4f, 0, 0.05f, 0.3f, 0.0f, Subdiv+16, Subdiv/16+1); glEndList(); // Create ground display list if( groundList>0 ) glDeleteLists(groundList, 1); // delete previously created display list groundList = glGenLists(1); glNewList(groundList, GL_COMPILE); DrawSubdivPlaneY(-1.2f, 1.2f, 0, -1.2f, 1.2f, (3*Subdiv)/2, (3*Subdiv)/2); glEndList(); // Create display list to draw light halos if( haloList>0 ) glDeleteLists(haloList, 1); // delete previously created display list haloList = glGenLists(1); glNewList(haloList, GL_COMPILE); DrawSubdivHaloZ(0, 0, 0, 1, 32); glEndList(); } // Callback function associated to the 'Change lights' button of the lights tweak bar. void TW_CALL ReinitCB(void *clientData) { Scene *scene = static_cast(clientData); // scene pointer is stored in clientData scene->Init(true); // re-initialize the scene } // Create a tweak bar for lights. // New enum type and struct type are defined and used by this bar. void Scene::CreateBar() { // Create a new tweak bar and change its label, position and transparency lightsBar = TwNewBar("Lights"); TwDefine(" Lights label='Lights TweakBar' position='580 16' alpha=0 help='Use this bar to edit the lights in the scene.' "); // Add a variable of type int to control the number of lights TwAddVarRW(lightsBar, "NumLights", TW_TYPE_INT32, &NumLights, " label='Number of lights' keyIncr=l keyDecr=L help='Changes the number of lights in the scene.' "); // Set the NumLights min value (=0) and max value (depends on the user graphic card) int zero = 0; TwSetParam(lightsBar, "NumLights", "min", TW_PARAM_INT32, 1, &zero); TwSetParam(lightsBar, "NumLights", "max", TW_PARAM_INT32, 1, &maxLights); // Note, TwDefine could also have been used for that pupose like this: // char def[256]; // _snprintf(def, 255, "Lights/NumLights min=0 max=%d", maxLights); // TwDefine(def); // min and max are defined using a definition string // Add a button to re-initialize the lights; this button calls the ReinitCB callback function TwAddButton(lightsBar, "Reinit", ReinitCB, this, " label='Change lights' key=c help='Random changes of lights parameters.' "); // Define a new enum type for the tweak bar TwEnumVal modeEV[] = // array used to describe the Scene::AnimMode enum values { { Light::ANIM_FIXED, "Fixed" }, { Light::ANIM_BOUNCE, "Bounce" }, { Light::ANIM_ROTATE, "Rotate" }, { Light::ANIM_COMBINED, "Combined" } }; TwType modeType = TwDefineEnum("Mode", modeEV, 4); // create a new TwType associated to the enum defined by the modeEV array // Define a new struct type: light variables are embedded in this structure TwStructMember lightMembers[] = // array used to describe tweakable variables of the Light structure { { "Active", TW_TYPE_BOOLCPP, offsetof(Light, Active), " help='Enable/disable the light.' " }, // Light::Active is a C++ boolean value { "Color", TW_TYPE_COLOR4F, offsetof(Light, Color), " noalpha help='Light color.' " }, // Light::Color is represented by 4 floats, but alpha channel should be ignored { "Radius", TW_TYPE_FLOAT, offsetof(Light, Radius), " min=0 max=4 step=0.02 help='Light radius.' " }, { "Animation", modeType, offsetof(Light, Animation), " help='Change the animation mode.' " }, // use the enum 'modeType' created before to tweak the Light::Animation variable { "Speed", TW_TYPE_FLOAT, offsetof(Light, Speed0), " readonly=true help='Light moving speed.' " } // Light::Speed is made read-only }; TwType lightType = TwDefineStruct("Light", lightMembers, 5, sizeof(Light), NULL, NULL); // create a new TwType associated to the struct defined by the lightMembers array // Use the newly created 'lightType' to add variables associated with lights for(int i=0; i