嘿,我正在尝试通过从 .xml 文件中读取烟花来创建烟花表演,然后该文件将遍历并启动每个烟花。
我按照关于 dinomage 的教程了解如何使用 tinyxml,我了解到我可以将属性存储到 char 指针中,但我不知道如何将它们转换为 GLfloats 以将它们存储在我的类变量中。
我确实尝试过使用 atof,但是当我运行程序时,我遇到了很多错误,我猜这是因为指针只存储了我传递给我的变量的地址。
谁能指出我哪里出错了,我该如何解决这个问题?
更新
我发现 tinyxml 与 vs2010 不兼容,但 tinyxml 2 是,所以我更改了代码,但仍然无法加载我的属性我添加了错误检查,它打印出 xml 已加载但它不会加载根
代码更新
代码:Firework.h
#ifndef FIREWORK_H
#define FIREWORK_H
#include <cstdlib>
#include <GL\GL.h>
#include <string>
const GLint particles= 50;
class Firework
{
public:
GLint x[particles];
GLint y[particles];
GLint VelX[particles];
GLint VelY[particles];
GLint Xpos;
GLint Ypos;
GLint Xspeed;
GLint Yspeed;
unsigned char red;
unsigned char blue;
unsigned char green;
GLfloat alpha;
GLfloat redStart;
GLfloat blueStart;
GLfloat greenStart;
std::string hexColour;
std::string type;
GLint timeUntilLaunch;
GLint startTime;
GLint endTime;
GLint duration;
GLfloat particleSize;
GLboolean hasExploded;
GLboolean rocket, fountain;
static const GLfloat gravity;
static const GLfloat baseYSpeed;
static const GLfloat maxYSpeed;
Firework();
void initialise();
void move();
void explode();
};
#endif
烟花.ccp
#include "Firework.h"
#include "tinyxml2.h"
#include<time.h>
#include <string>
#include<iostream>
#include <vector>
using namespace std;
const GLfloat Firework::gravity = 0.05f;
const GLfloat Firework::baseYSpeed = -4.0f;
const GLfloat Firework::maxYSpeed = -4.0f;
//int QueryAttributeStatus = elem->FirstChildElement("begin")- >QueryFloatAttribute(attr,&timeUntillLaunch);
int convertFromHex(string hex)
{
int value = 0;
int a = 0;
int b = hex.length() - 1;
for (; b >= 0; a++, b--)
{
if (hex[b] >= '0' && hex[b] <= '9')
{
value += (hex[b] - '0') * (1 << (a * 4));
}
else
{
switch (hex[b])
{
case 'A':
case 'a':
value += 10 * (1 << (a * 4));
break;
case 'B':
case 'b':
value += 11 * (1 << (a * 4));
break;
case 'C':
case 'c':
value += 12 * (1 << (a * 4));
break;
case 'D':
case 'd':
value += 13 * (1 << (a * 4));
break;
case 'E':
case 'e':
value += 14 * (1 << (a * 4));
break;
case 'F':
case 'f':
value += 15 * (1 << (a * 4));
break;
default:
cout << "Error, invalid charactare '" << hex[a] << "' in hex number" << endl;
break;
}
}
}
return value;
}
void hextodec(string hex, vector<unsigned char>& rgb)
{
/*
since there is no prefix attached to hex, use this code
string redString = hex.substr(0, 2);
string greenString = hex.substr(2, 2);
string blueString = hex.substr(4, 2);
*/
/*
if the prefix # was attached to hex, use the following code
string redString = hex.substr(1, 2);
string greenString = hex.substr(3, 2);
string blueString = hex.substr(5, 2);
*/
//if the prefix 0x was attached to hex, use the following code
string redString = hex.substr(2, 2);
string greenString = hex.substr(4, 2);
string blueString = hex.substr(6, 2);
unsigned char red = (unsigned char)(convertFromHex(redString));
unsigned char green = (unsigned char)(convertFromHex(greenString));
unsigned char blue = (unsigned char)(convertFromHex(blueString));
rgb[0] = red;
rgb[1] = green;
rgb[2] = blue;
}
Firework::Firework()
{
initialise();
}
void Firework::initialise()
{
tinyxml2::XMLDocument doc;
doc.LoadFile( "fireworks.xml");
if (!doc.LoadFile("fireworks.xml"))
{
std::cout<<"Failed to load file: no xml"<<endl;
}
else
std::cout<<"loaded xml"<<endl;
tinyxml2::XMLElement * root = doc.FirstChildElement();
if (root == NULL)
{
std::cout<<"Failed to load file: no root element."<<endl;
}
else
std::cout<<"root node loaded"<<endl;
for (tinyxml2::XMLElement* elem = root ->FirstChildElement(); elem!=NULL; elem = elem->NextSiblingElement())
{
string elemName = elem->Value();
const char* attr;
if (elemName == "Firework")
{
attr = elem->Attribute("begin");
if(attr != NULL)
{
elem->QueryIntAttribute("begin",&startTime);
}
attr = elem->Attribute("type");
if (attr != NULL)
{
type = elem->GetText();
if (type != "")
std::cout<<"have something"<<endl;
}
attr = elem ->Attribute("colour");
if (attr !=NULL)
{
hexColour= elem->GetText();
vector<unsigned char> rgbColor(3);
hextodec(hexColour,rgbColor);
red =int(rgbColor[0]);
blue = int(rgbColor[1]);
green= int(rgbColor[2]);
}
attr = elem->Attribute("duration");
if (attr !=NULL)
{
elem->QueryIntAttribute("duration", &endTime);
}
for (tinyxml2::XMLElement * e =elem ->FirstChildElement("Position"); e != NULL; e = e->NextSiblingElement("Position"))
{
attr = e->Attribute("x");
if (attr != NULL)
{
Xpos = e->QueryIntAttribute("x", &Xpos);
}
attr = e->Attribute("y");
if (attr != NULL)
{
Ypos = e->QueryIntAttribute("y", &Ypos);
}
}
for(tinyxml2::XMLElement * v =elem ->FirstChildElement("Velocity"); v !=NULL; v = v->NextSiblingElement("Velocity"))
{
attr = v -> Attribute("x");
if (attr != NULL)
{
Xspeed = v ->QueryIntAttribute("x", &Xspeed);
}
attr = v ->Attribute ("y");
if (attr !=NULL)
{
Yspeed = v ->QueryIntAttribute("y", &Yspeed);
}
}
}
}
//Setting initial x/y locations and speeds for each particle
for (int loop = 0; loop < particles; loop++)
{
x[loop] = Xpos;
y[loop] = Ypos;
VelX[loop] = Xspeed;
VelY[loop] = Yspeed;
}
//intiallising the colour and full alpha
redStart = 0.85f;//((float)rand() / (float)RAND_MAX);
greenStart = 0.55f;//((float)rand() / (float)RAND_MAX);
blueStart = 0.01f;//((float)rand() / (float)RAND_MAX);
alpha = 1.0f;
timeUntilLaunch = startTime;
duration = endTime;
particleSize = 1.0f + ((float)rand()/(float)RAND_MAX)* 3.0f;
hasExploded = false;
}
void Firework::move()
{
for (int loop = 0; loop < particles; loop++)
{
if (timeUntilLaunch <= 0)
{
x[loop] += VelX [loop];
y[loop] += VelY [loop];
VelY[loop] += Firework::gravity;
duration --;
}
}
timeUntilLaunch --;
if (duration <= 0)
{
for (int loop2 = 0; loop2 < particles; loop2++)
{
VelX[loop2] = -4 + (rand() / (int)RAND_MAX)*8;
VelY[loop2] = -4 + (rand() / (int)RAND_MAX)*8;
}
hasExploded = true;
}
}
void Firework::explode()
{
for (int loop = 0; loop < particles; loop++)
{
// Dampen the horizontal speed by 1% per frame
VelX[loop] *= 0.99f;
// Move the particle
x[loop] += VelX[loop];
y[loop] += VelY[loop];
// Apply gravity to the particle's speed
VelY[loop] += Firework::gravity;
}
// Fade out the particles (alpha is stored per firework, not per particle)
if (alpha > 0.0f)
{
alpha -= 0.01f;
}
else // Once the alpha hits zero, then reset the firework
{
initialise();
}
}
主文件
#include <iostream>
#include <ctime>
#include <time.h>
#include <windows.h> // *** IMPORTANT: Uncomment for Win32 systems - This must come -BEFORE- gl.h in the include list! ***
#include "GL\glfw.h"
#include "Firework.h"
#include <GL\GL.h>
#include <GL/glu.h>
#include "tinyxml2.h"
#pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "lib/glfw/GLFW.lib")
using namespace std;
GLint windowWidth = 1024;
GLint windowHeight = 600;
GLint frameCount =0;
GLint texture;
const int FIREWORKS = 15; // Number of fireworks
Firework fw[FIREWORKS];
void initGL()
{
glfwSwapInterval(1);
glfwSetWindowTitle("Fireworks");
glViewport(0, 0, (GLsizei)windowWidth, (GLsizei)windowHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, windowWidth, windowHeight, 0, 0, 1);
glShadeModel(GL_SMOOTH);
// Set our clear colour to opaque black
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// Disable depth testing (because we're working in 2D!)
glDisable(GL_DEPTH_TEST);
// Enable blending (we need this to be able to use an alpha component)
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Set the accumulation buffer clearing colour to opaque black
glClearAccum(0.0f, 0.0f, 0.0f, 1.0f);
glEnable(GL_POINT_SMOOTH);
}
void drawScene()
{
// Take the contents of the current accumulation buffer and copy it to the colour buffer so that it entirely overwrites it
glAccum(GL_RETURN, 1.0f);
// Clear the accumulation buffer (don't worry, we re-grab the screen into the accumulation buffer after drawing our current frame!)
glClear(GL_ACCUM_BUFFER_BIT);
// Set ModelView matrix mode and reset to the default identity matrix
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Displacement trick for exact pixelisation
glTranslatef(0.375, 0.375, 0);
// Draw our fireworks
for (int loop = 0; loop < FIREWORKS; loop++)
{
for (int particleLoop = 0; particleLoop < particles; particleLoop++)
{
// Set the point size of the firework particles (this needs to be called BEFORE opening the glBegin(GL_POINTS) section!)
glPointSize(fw[loop].particleSize);
glBegin(GL_POINTS);
// Set colour to yellow on the way up, then whatever colour firework should be when exploded
if (fw[loop].hasExploded == false)
{
glColor4f(fw[loop].redStart, fw[loop].greenStart, fw[loop].blueStart, 1.0f);
}
else
{
glColor4f(fw[loop].red, fw[loop].green, fw[loop].blue, fw[loop].alpha);
}
// Draw the point
glVertex2f(fw[loop].x[particleLoop], fw[loop].y[particleLoop]);
glEnd();
}
// Move the firework appropriately depending on its explosion state
if (fw[loop].hasExploded == false && fw[loop].type=="Rocket")
{
fw[loop].move();
}
else
{
fw[loop].explode();
}
}
glAccum(GL_ACCUM, 0.85f);
glfwSwapBuffers();
}
int main()
{
int srand((unsigned)time(NULL)); // Seed the random number generator
// Define our buffer settings
int redBits = 8, greenBits = 8, blueBits = 8;
int alphaBits = 64, depthBits = 24, stencilBits = 8;
// Flag to keep our main loop running
bool running = true;
// Initialise glfw
glfwInit();
// Create a window
if(!glfwOpenWindow(windowWidth, windowHeight, redBits, greenBits, blueBits, alphaBits, 0, 0, GLFW_WINDOW))
{
cout << "Failed to open window!" << endl;
glfwTerminate();
return 0;
}
// Call our initGL function to set up our OpenGL options
initGL();
while (running == true)
{
// Draw our scene
drawScene();
// Increase our frame counter
frameCount++;
// Exit if ESC was pressed or the window was closed
running = glfwGetWindowParam(GLFW_OPENED);
}
glfwTerminate();
return 0;
}
烟花.xml
<?xml version="1.0" ?>
<FireworkDisplay>
<Firework begin="1000" type="Fountain" colour="0x20FF40" duration="5000">
<Position x="0" y="-384"/>
</Firework>
<Firework begin="2000" type="Fountain" colour="0x4020FF" duration="4000">
<Position x="100" y="-384"/>
</Firework>
<Firework begin="3000" type="Fountain" colour="0xff5099" duration="3000">
<Position x="-100" y="-384"/>
</Firework>
<Firework begin="1000" type="Rocket" colour="0xFF2020" duration="1000">
<Position x="500" y="-384"/>
<Velocity x="-3" y="10"/>
</Firework>
<Firework begin="2000" type="Rocket" colour="0xFF2020" duration="1000">
<Position x="0" y="-384"/>
<Velocity x="0" y="10"/>
</Firework>
<Firework begin="3000" type="Rocket" colour="0xFF2020" duration="1000">
<Position x="-500" y="-384"/>
<Velocity x="3" y="10"/>
</Firework>
<Firework begin="11000" type="Rocket" colour="0xFFFF20" duration="1000">
<Position x="500" y="-384"/>
<Velocity x="-3" y="10"/>
</Firework>
<Firework begin="12000" type="Rocket" colour="0xFF2020" duration="1000">
<Position x="0" y="-384"/>
<Velocity x="0" y="10"/>
</Firework>
<Firework begin="13000" type="Rocket" colour="0xFF20FF" duration="1000">
<Position x="-500" y="-384"/>
<Velocity x="3" y="10"/>
</Firework>
<Firework begin="4000" type="Fountain" colour="0xffFF40" duration="5000">
<Position x="0" y="-384"/>
</Firework>
<Firework begin="5000" type="Fountain" colour="0x4020FF" duration="4000">
<Position x="-200" y="-384"/>
</Firework>
<Firework begin="6000" type="Fountain" colour="0xff5099" duration="3000">
<Position x="200" y="-384"/>
</Firework>
<Firework begin="7000" type="Fountain" colour="0x20FF40" duration="5000">
<Position x="0" y="-384"/>
</Firework>
<Firework begin="8000" type="Fountain" colour="0x4020FF" duration="4000">
<Position x="400" y="-384"/>
</Firework>
<Firework begin="9000" type="Fountain" colour="0xff5099" duration="3000">
<Position x="-400" y="-384"/>
</Firework>
<Firework begin="10000" type="Fountain" colour="0xff8040" duration="1000">
<Position x="-450" y="-384"/>
</Firework>
<Firework begin="10500" type="Fountain" colour="0x40ffFF" duration="1000">
<Position x="-220" y="-384"/>
</Firework>
<Firework begin="11000" type="Fountain" colour="0xffff99" duration="1000">
<Position x="0" y="-384"/>
</Firework>
<Firework begin="11500" type="Fountain" colour="0xff00ff" duration="1000">
<Position x="220" y="-384"/>
</Firework>
<Firework begin="12000" type="Fountain" colour="0x40ffFF" duration="1000">
<Position x="450" y="-384"/>
</Firework>
</FireworkDisplay>