ASSIMP & paintGL() ,slow rendering (and crash) - c++

I am using Assimp to load a .3ds file, and a QGLWidget derived class to draw it using PaintGL(). It works with small .3ds files (some KBytes) but if i try to render bigger files (like 1MBytes) the application crashes. Is my way too bad and twisted? Am I doing something wrong?
With qDebug i understand that paintGL() works correctly.The problem is in ourRender method,because if i obscure the
for (int t = 0; t < p->getFaces().count(); ++t)
and in detail
glVertex3f(f.getVerticesArray()[s].getX(),f.getVerticesArray();
cycle it all works fast (but obviously nothing is painted) except grid and axis.With it,and loading some complicated 3ds,it crashes
my hardware is
Phenom II X3 2.10ghz,4GB and 6650M (last drivers)
On a Celeron 2.1 Ghz it crash
BUT on a i7 the program starts but render #2FPS (if I dont use "ourRender" method,it renders at 120fps on my pc)
void GLWidget::paintGL()
{
qDebug << "Start PaintGL() #" << times;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
gluLookAt(objCamera->mPos.x, objCamera->mPos.y, objCamera->mPos.z,
0, objCamera->mView.y, 0,
objCamera->mUp.x, objCamera->mUp.y, objCamera->mUp.z);
if (drawLines) glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
else glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
draw_grid();
drawAxis();
ourRender(this->scenaa);
qDebug << "Close PaintGL() #" << times;
}
And this is the "ourRender" method:
void GLWidget::ourRender(const Scene* sc){
QHash<QString, SceneObject*>& hash=sc->getObj();
double molt =1/20;
int counter =0;
for (QHash<QString,SceneObject*>::ConstIterator i = hash.begin();i!=hash.end();++i) {
aiMatrix4x4 minchia(1,0,0,molt*20,0,1,0,molt*20,0,0,1,molt*20,0,0,0,1);
aiTransposeMatrix4(&minchia);
glPushMatrix();
const Mesh* p = dynamic_cast<Mesh*>(i.value());
glMultMatrixf((float*) &minchia);
if(p){
for (int t = 0; t < p->getFaces().count(); ++t) {
Face f = p->getFaces()[t];
GLenum face_mode;
switch(f.getVerticesArray().count()) {
case 1: face_mode = GL_POINTS; break;
case 2: face_mode = GL_LINES; break;
case 3: face_mode = GL_TRIANGLES; break;
default: face_mode = GL_POLYGON; break;
}
glBegin(face_mode);
QList<Vector3D> lista = f.getVerticesArray();
for(int s = 0; s < lista.count(); s++) {
if (p->getNormals().count()>0)
--------->glVertex3f(f.getVerticesArray()[s].getX(),f.getVerticesArray()[s].getY(),f.getVerticesArray()[s].getZ());
}
glEnd();
}
}
glPopMatrix();
molt+=13;
counter++;
}
glPopMatrix();
}
...in the derived QGLWidget class costructor...
SceneImporter* aa = new AssimpAdapter();
Scene * nuovo=aa->importFile("C:/Users/nicola/Desktop/Source/aces.3ds");
scenaa=nuovo;

We solved the problem modifying "ourender" method (using references instead of copyes)
void GLWidget::ourRender(Scene *&sc){
QHash<QString, SceneObject*>& hash=sc->getObj();
int counter =0;
for (QHash<QString,SceneObject*>::ConstIterator i = hash.begin();i!=hash.end();++i) {
aiMatrix4x4 m;
aiTransposeMatrix4(&m);
glPushMatrix();
const Mesh* p = dynamic_cast<Mesh*>(i.value());
glMultMatrixf((float*) &m);
if(p){
//apply_material(aaFuori.GetScene()->mMaterials[counter]);
QList<Face>& faccie=p->getFaces();
for (int t = 0; t < faccie.count(); ++t) {
Face f = faccie[t];
GLenum face_mode;
switch(f.getVerticesArray().count()) {
case 1: face_mode = GL_POINTS; break;
case 2: face_mode = GL_LINES; break;
case 3: face_mode = GL_TRIANGLES; break;
default: face_mode = GL_POLYGON; break;
}
glBegin(face_mode);
QList<Vector3D>& lista = f.getVerticesArray();
int conta=lista.count();
glVertex3f(lista[0].x,lista[0].y,lista[0].z);
glVertex3f(lista[1].x,lista[1].y,lista[1].z);
glVertex3f(lista[2].x,lista[2].y,lista[2].z);
glEnd();
}
}
glPopMatrix();
counter++;
}
Now we can render 8MBytes .3Ds #4fps during camera rotations (instead of application crash).Could someone of you give us an opinion about this result?is it good or bad?

Optimizazion.The fact is that for every vertex we were accessing to a QList 3 times.Now we've modified it,and instead of Qlist we use a Vector3D* array that saves the position of the vertices and so we can use the GL method glVertex3fv((GLfloat*)array[numface].posvertex); So,given the pointer to the face,its much faster than before (4 to 10 fps on the same scene).
void GLWidget::ourRender(Scene *sc){
QHash<QString, SceneObject*>& hash=sc->getObj();
aiMatrix4x4 m;
for (QHash<QString,SceneObject*>::ConstIterator i = hash.begin();i!=hash.end();++i) {
aiTransposeMatrix4(&m);
glPushMatrix();
Mesh* p = dynamic_cast<Mesh*>(i.value());
glMultMatrixf((float*) &m);
if(p){
QList<Face>& faccie=p->getFaces();
int numerofacce=faccie.count();
for (int t = 0; t < numerofacce; ++t) {
Face& f = faccie[t];
GLenum face_mode;
Vector3D* lista=f.arrayVertici;
switch(f.getVerticesArray().count()) {
case 1:
face_mode = GL_POINTS;
glBegin(face_mode);
glVertex3fv((GLfloat*)lista[0].pos);
break;
case 2:
face_mode = GL_LINES;
glBegin(face_mode);
glVertex3fv((GLfloat*)lista[0].pos);
glVertex3fv((GLfloat*)lista[1].pos);
break;
case 3:
face_mode = GL_TRIANGLES;
glBegin(face_mode);
glVertex3fv(&lista[0].pos[0]);
glVertex3fv(&lista[1].pos[0]);
glVertex3fv(&lista[2].pos[0]);
break;
default: face_mode = GL_POLYGON; break;
}
glEnd();
}
}
glPopMatrix();
counter++;
}
glPopMatrix();
}
Where Vector3D is initialized like this:
Vector3D::Vector3D(double x, double y, double z) {
setX(x);
setY(y);
setZ(z);
pos[0]=x; //vertex1
pos[1]=y; //vertex2
pos[2]=z; //vertex3
}
PS:Grimmy suggests me to use DisplayLists (discovered right now).Tomorrow I will try them.

Related

Infrared selected switch statement using Arduino and Neopixels

I'm having some problems putting the finishing touches on the latest project. The Idea is to have an Infrared receiver mounted on a single Arduino Uno, taking ques from a remote to select preprogramed patterns on a Neopixel strip (selection from the Neopixel Strand test)
Here is my code
//Always comment your code like a violent psychopath will be maintaining it and they know where you live
#include <Adafruit_NeoPixel.h> //Neopixel Library
#include <IRLibAll.h> //IR reciever Library
IRrecvLoop myReceiver(2); //IR receiver on IO pin 2
IRdecode myDecoder; //Decoder object
unsigned long oldCode = 00000000; //Comparison variable to evaluate the execution of the 'Check' function later
Adafruit_NeoPixel strip (3,3,NEO_RGBW + NEO_KHZ800); //Creates the Pixel strip as an object in the code
void setup() {
strip.begin(); //Initialise the Neopixel strip
strip.show(); //Initialise all pixels to 'off'
myReceiver.enableIRIn(); // Start the IR receiver
}
void loop() {
check(); //Run the check function
delay(20); //Delay before running the loop again by 20 milliseconds giving time to recieve signals
}
void check() { //check Function: Checks for an IR signal before nominating which of the test displays to run
if (oldCode = myDecoder.value){ //Evaluates if the IR code recieved from the remote matches 'oldCode' and if it does....
return; //Terminates the check Function returning its values
}
if (myReceiver.getResults()) {
myDecoder.decode();
if (myDecoder.protocolNum == NEC) {
switch(myDecoder.value) { //Activate this switch statement based on the value 'myDecoder' holds
case 0xFFA25D: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFFE21D: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFF629D: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFF22DD: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFF02FD: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFFC23D: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFFE01F: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFFA857: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFF906F: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFF9867: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFFB04F: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFF6897:
colorWipe(strip.Color( 0, 0, 0), 50); // Black/off "0"
Serial.println("0 - Black/off");
break;
case 0xFF30CF:
colorWipe(strip.Color(255, 0, 0), 50); // Red "1"
Serial.println("1 - All red");
break;
case 0xFF18E7:
colorWipe(strip.Color( 0, 255, 0), 50); // Green "2"
Serial.println("2 - All green");
break;
case 0xFF7A85:
colorWipe(strip.Color( 0, 0, 255), 50); // Blue "3"
Serial.println("3 - All blue");
break;
case 0xFF10EF:
theaterChase(strip.Color(127, 127, 127), 50); // White "4"
Serial.println("4 - All white");
break;
case 0xFF38C7:
theaterChase(strip.Color(127, 0, 0), 50); // Red "5"
Serial.println("5");
break;
case 0xFF5AA5:
theaterChase(strip.Color( 0, 0, 127), 50); // Blue "6"
Serial.println("6");
break;
case 0xFF42BD:
rainbow(10); // "7"
Serial.println("7");
break;
case 0xFF4AB5:
theaterChaseRainbow(50); // "8"
Serial.println("8");
break;
case 0xFF52AD: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFFFFFFFF: Serial.println("Please release button and reselect"); break;
}
}
oldCode = myDecoder.value; //make the new button state equal the old buttonstate preventing the button from activating if statement
}
}
void colorWipe(uint32_t color, int wait) { //Colour wipe test
while(true) {
for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
strip.setPixelColor(i, color); // Set pixel's color (in RAM)
strip.show(); // Update strip to match
check();
delay(wait); // Pause for a moment
}
}
}
void theaterChase(uint32_t color, int wait) { //Theatre Chase test
while(true) {
for(int a=0; a<10; a++) { // Repeat 10 times...
for(int b=0; b<3; b++) { // 'b' counts from 0 to 2...
strip.clear(); // Set all pixels in RAM to 0 (off)
for(int c=b; c<strip.numPixels(); c += 3) { // 'c' counts up from 'b' to end of strip in steps of 3...
strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'
check(); //Run the check function
}
strip.show(); // Update strip with new contents
delay(wait); // Pause for a moment
}
}
}
}
void rainbow(int wait) { //Rainbow test function
while(true) { //while this function is active
for(long firstPixelHue = 0; firstPixelHue < 3*65536; firstPixelHue += 256) { //Sets differing colours for the rainbow
for(int i=0; i<strip.numPixels(); i++) { //For each pixel in strip...
int pixelHue = firstPixelHue + (i * 65536L / strip.numPixels()); //balances the colour pattern along the length of the strip
strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue))); //run the colour pattern along the strip
check(); //run the check function
}
strip.show(); //Update strip with new contents
delay(wait); //Pause for a moment
}
}
}
void theaterChaseRainbow(int wait) {
while(true) {
int firstPixelHue = 0; //First pixel starts at red
for(int a=0; a<30; a++) { //Repeat 30 times...
for(int b=0; b<3; b++) { //'b' counts from 0 to 2...
strip.clear(); //Set all pixels to off
for(int c=b; c<strip.numPixels(); c += 3) { //'c' counts up from 'b' to end of strip in increments of 3, hue of pixel 'c' is offset by an amount to make one full revolution of the color wheel (range 65536) along the length of the strip (strip.numPixels() steps):
int hue = firstPixelHue + c * 65536L / strip.numPixels(); //create the hue variable and balance the rainbow colouring across the strip
uint32_t color = strip.gamma32(strip.ColorHSV(hue)); // hue -> RGB
strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'
check(); //Run the check function
}
strip.show(); // Update strip with new contents
delay(wait); // Pause for a moment
firstPixelHue += 65536 / 90; // One cycle of color wheel over 90 frames
}
}
}
}
The Problems
I have tried to write a loop that uses a class call to decide what is going on ("check"), I have also written another version where the switch statement is place in the loop instead. The problem from what I understand is that the IR input cannot receive whilst the loop is running (as it cannot interrupt) yet the test patterns will not play unless the loop is running. I have looked at solutions that involve using two Arduino's with either one running IR and the Neopixel respectively but unfortunately this will not match up with my brief - I need to have it running on one Arduino.
Any ideas?
For those who are interested - the final code to this project was...
//Always comment your code like it will be maintained by a violent psychopath who knows where you live.
#include <IRLibAll.h> //Infra Red Library
#include <Adafruit_NeoPixel.h> //Adafruit NeoPixel Library
//======== Constants =============
const int LEDpin = 3; //IO pin for the LED strip
const int LEDcount = 3; //Number of LED's in the strip
const int IRreceiver = 2; //IO pin for the IRreceiver
IRrecvPCI myReceiver(IRreceiver); //Instantiate the Infra Red receiver
IRdecode myDecoder; //Instatiate a Decoder object (Veriable to hold the recieved data from the button press)
enum pattern { NONE, RAINBOW_CYCLE, THEATER_CHASE, color_WIPE, SCANNER, FADE }; //Limit the results 'pattern' will accept with an enumeration
//======== Variables =============
//=====Classes and Functions =====
class neoPatterns : public Adafruit_NeoPixel //A class to govern the operation of the Neopixel patterns outside of the Main loop
{
private:
int steps;
uint32_t color;
public:
pattern activePattern; //Tracks the pattern that is currently active on the strip
unsigned long interval; //Milliseconds between updates
unsigned long lastUpdate; //Records the millisecond of the last update
uint32_t color1, color2; //Variables for recording active colors
uint16_t totalSteps; //How many steps of the pattern have been called
uint16_t index; //What step within the pattern we are on
void (*onComplete)(); //onComplete callback function - still wondering how much i need this?
neoPatterns(uint16_t pixels, uint8_t pin, uint8_t type, void (*callback)()) //Class constructor to...
:Adafruit_NeoPixel(pixels, pin, type) //initialise the Neopixel strip
{
onComplete = callback;
}
void update() //Function that manages updating the pattern
{
if((millis() - lastUpdate) > interval) //Is it time to update?
{
lastUpdate = millis(); //Updates 'lastUpdate' to the current milli's value
switch(activePattern) //Switch statement to track which pattern needs its update function
{
case RAINBOW_CYCLE: //If rainbowCycle...
rainbowCycleUpdate(); //update rainbowCycle
break;
case THEATER_CHASE: //If theatreChase...
theaterChaseUpdate(); //update theatreChase
break;
case color_WIPE: //if colorWipe
colorWipeUpdate(); //update colorWipe
break;
case SCANNER: //if scanner
scannerUpdate(); //update scanner
break;
case FADE: //if fade
fadeUpdate(); //update fade
break;
default:
break;
}
}
}
void increment() //Function for incrementing values to drive strand tests
{
index++; //increment index variable
if (index >= totalSteps) //if index is greater than or equal to totalsteps...
{
index = 0; //..reset index to 0 and...
if (onComplete != NULL) //... if onComplete has no value...
{
onComplete(); //...call the onComplete callback
}
}
}
void rainbowCycle(uint8_t interval) //Rainbow Cycle strand test pattern
{
activePattern = RAINBOW_CYCLE; //Set current active pattern to Rainbow Cycle...
interval = interval; //reset interval to interval
totalSteps = 255; //set total step variable to 255
index = 0; //set index variable to 0
}
void rainbowCycleUpdate() //update for Rainbow Cycle
{
for(int i=0; i< numPixels(); i++) //create a variable called 'i' which is equal to 0 and do loops, whilst the number of pixels in the strip is greater than i, incremeting i every loop.
{
setPixelColor(i, wheel(((i * 256 / numPixels()) + index) & 255)); //set the pixel color to ...
}
show(); //update the orders to the Neopixel strand
increment(); //Run the increment function
}
void colorWipe (uint32_t color, uint8_t interval) //color wipe funtion
{
activePattern = color_WIPE; //update the current active pattern to color Wipe
interval = interval; //reset the interval variable
totalSteps = 255; //set the total steps variable to 255
color1 = color; //set color to color 1
index = 0; //reset the index variable to 0
}
void colorWipeUpdate() //Color wipe update function
{
setPixelColor(index, color1); //change the pixel color to color1
show(); //update the strand
increment(); //run the increment function
}
void theaterChase(uint32_t color1, uint32_t color2, uint8_t interval) //Theatre Chase funtion
{
activePattern = THEATER_CHASE; //change the current active pattern to Theatre Chase
interval = interval; //reset the interval variable
totalSteps = numPixels(); //update the total steps variable to be equivilent to the number of pixels
color1 = color1; //Reset color1
color2 = color2; //Reset color2
index = 0; //Set index variable to 0
}
void theaterChaseUpdate() //Theatre Chase update function
{
for(int i=0; i< numPixels(); i++) //take the i variable and reset it to 0 and do loops, whilst the number of pixels in the strip is greater than i, incremeting i every loop.
{
if ((i + index) % 3 == 0) //if the total of I and index divide equally by 3...
{
setPixelColor(i, color1); //...set the pixelcolor to color 1...
}
else //...otherwise...
{
setPixelColor(i, color2); //set the pixel color to color 2
}
}
show(); //update the neopixel strand
increment(); //run the increment function
}
void scanner(uint32_t color1, uint8_t interval) //Scanner function
{
activePattern = SCANNER; //update the active pattern to Scanner
interval = interval; //reset the interval variable
totalSteps = (numPixels() - 1) * 2; //set the total steps variable to by equal to twice that of the number of pixels on the strand less one
color1 = color1; //reset the color1 variable
index = 0; //set the index variable to 0
}
void scannerUpdate() //Scanner update function
{
for (int i = 0; i < numPixels(); i++) //take the i variable and reset it to 0 and do loops, whilst the number of pixels in the strip is greater than i, incremeting i every loop.
{
if (i == index) //if the i variable is equivilant to the index variable...
{
setPixelColor(i, color1); //set the pixel color to color1
}
else if (i == totalSteps - index) //if the i variable is equivilant to totalsteps less the value of index...
{
setPixelColor(i, color1); //set the pixel color to color1...
}
else //otherwise...
{
setPixelColor(i, DimColor(getPixelColor(i))); //dim the current pixel value
}
}
show(); //update the strand
increment(); //run the increment function
}
void fade(uint32_t color1, uint32_t color2, uint16_t steps, uint8_t interval) //Fade function
{
activePattern = FADE; //set the current active pattern to fade
interval = interval; //reset the interval variable
totalSteps = steps; //create a new steps variable and set it to be eqivilant to totalSteps
color1 = color1; //reset color1
color2 = color2; //reset color2
index = 0; //set index to 0
}
void fadeUpdate() //Fade update function
{
uint8_t red = ((Red(color1) * (totalSteps - index)) + (Red(color2) * index)) / totalSteps;
uint8_t green = ((Green(color1) * (totalSteps - index)) + (Green(color2) * index)) / totalSteps;
uint8_t blue = ((Blue(color1) * (totalSteps - index)) + (Blue(color2) * index)) / totalSteps;
colorSet(Color(red, green, blue));
show(); //update the strand
increment(); //run the increment function
}
uint8_t Red(uint32_t color) //Red color function
{
return (color >> 16) & 0xFF;
}
uint8_t Green(uint32_t color) //Green color function
{
return (color >> 8) & 0xFF;
}
uint8_t Blue(uint32_t color) //Blue color function
{
return color & 0xFF;
}
uint32_t DimColor(uint32_t color) //color dimming function
{
uint32_t dimColor = Color(Red(color) >> 1, Green(color) >> 1, Blue(color) >> 1);
return dimColor;
}
uint32_t wheel(byte wheelPos) //color wheeling function for the rainbow color functions
{
wheelPos = 255 - wheelPos;
if(wheelPos < 85)
{
return Color(255 - wheelPos * 3, 0, wheelPos * 3);
}
else if(wheelPos < 170)
{
wheelPos -= 85;
return Color(0, wheelPos * 3, 255 - wheelPos * 3);
}
else
{
wheelPos -= 170;
return Color(wheelPos * 3, 255 - wheelPos * 3, 0);
}
}
void colorSet(uint32_t color) //color set function sets all colors to the same synchronus color
{
for (int i = 0; i < numPixels(); i++)
{
setPixelColor(i, color);
}
show();
}
void IRSelector() //Infra Red selection function - takes action based on IR code received
{
if (myDecoder.protocolNum == NEC) { //ignore any code that is not recieved from a NEC remote control
switch(myDecoder.value) //Switch statement that makes a decision based upon the value recieved from the Infra Red decoder
{
case 0xFFA25D: Serial.println("Untethered button, please select from 0-8"); break; //=====================================================================
case 0xFFE21D: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFF629D: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFF22DD: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFF02FD: Serial.println("Untethered button, please select from 0-8"); break; // ------------- UNASSIGNED BUTTON SELECTIONS -------------------------
case 0xFFC23D: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFFE01F: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFFA857: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFF906F: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFF9867: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFFB04F: Serial.println("Untethered button, please select from 0-8"); break; //=====================================================================
case 0xFF6897: //"0 - All black (off)"
colorWipe(color, interval);
Serial.println("0 - Black/off");
break;
case 0xFF30CF: //"1 - All red"
colorWipe(color, interval);
Serial.println("1 - All red");
break;
case 0xFF18E7: //"2 - All green"
colorWipe(color, interval);
Serial.println("2 - All green");
break;
case 0xFF7A85: //"3 - All blue"
colorWipe(color, interval);
Serial.println("3 - All blue");
break;
case 0xFF10EF: //"4 - All white"
colorWipe(color, interval);
Serial.println("4 - All white");
break;
case 0xFF38C7: //"5 - Rainbow Cycle"
rainbowCycle(interval);
Serial.println("5");
break;
case 0xFF5AA5: //"6 - Theater Chase"
theaterChase(color1, color2, interval);
Serial.println("6");
break;
case 0xFF42BD: //"7 - Scanner"
scanner(color1, interval);
Serial.println("7");
break;
case 0xFF4AB5: //"8 - Fader"
fade(color1, color2, steps, interval);
Serial.println("8");
break;
case 0xFF52AD: Serial.println("Untethered button, please select from 0-8"); break; //button 9 - unassigned
case 0xFFFFFFFF: Serial.println("Please release button and reselect"); break; //consistant repeat code
default:
Serial.print(" other button ");
Serial.println(myDecoder.value);
}//End of Switch
}
}//End of IRSelector method
}; // End of neoPatterns class
void strandComplete();
neoPatterns strand(LEDcount, LEDpin, NEO_RGBW + NEO_KHZ800, &strandComplete); //Neopattern object to define the strand
void setup(){ /*----( SETUP: RUNS ONCE )----*/
Serial.begin(9600); //engage the serial monitor
Serial.println("IR Receiver Button Decode"); //print out to the monitor
myReceiver.enableIRIn(); //Start the receiver
strand.begin(); //start the Neopixel strip
}/*--(end setup )---*/
void loop(){ /*----( LOOP: RUNS CONSTANTLY )----*/
if (myReceiver.getResults()) //check to see if we have received an IR signal?
{
myDecoder.decode(); //Decode the recieved signal
strand.IRSelector(); //Run the IR selection function
myReceiver.enableIRIn(); //reset the receiver for a new code
}
strand.update(); //Run the update function on the Neopixel strand
}/* --(end main loop )-- */
void strandComplete()
{
// Random color change for next scan
strand.color1 = strand.wheel(random(255));
}`

Exception thrown by IJawsRenderer()

I’m using the Mako SDK and IJawsRenderer::render() to render all IDOMPathNodes with an IDOMImageBrush fill. When I do, the renderer throws an error 2000 exception for some nodes, but not all. What could be the cause?
IDOMBrushPtr pBrush;
pPath->getFill(pBrush);
if (pBrush)
{
IDOMBrush::eBrushType fillStyle = pBrush->getBrushType();
switch (fillStyle)
{
case IDOMBrush::eImage:
{
IJawsRendererPtr renderer = IJawsRenderer::create(jawsMako);
IDOMImagePtr renderedImage;
renderedImage = renderer->render(pNode, 800); // This is where the exception will eventually happen.
break;
}
default:
break;
}
}
It could be that the exception is thrown because the path passed to the renderer is too small. There is a lower limit of 1pt x 1pt (or 1.33 x 1.33 Mako units) for the renderer. Modify your code to check that the bounding box of the node is big enough, for example:
const double minimumRenderSize = 96.0 / 72.0;
...
IDOMBrushPtr pBrush;
pPath->getFill(pBrush);
FRect box;
pPath->getBounds(box);
box.dX = box.dX < minimumRenderSize ? minimumRenderSize : box.dX;
box.dY = box.dY < minimumRenderSize ? minimumRenderSize : box.dY;
if (pBrush)
{
IDOMBrush::eBrushType fillStyle = pBrush->getBrushType();
switch (fillStyle)
{
case IDOMBrush::eImage:
{
IJawsRendererPtr renderer = IJawsRenderer::create(jawsMako);
IDOMImagePtr renderedImage;
renderedImage = renderer->render(pNode, 800, IDOMColorSpacesRGB::create(jawsMako), box);
break;
}
default:
break;
}
}

How do I scale Box2D objects with PPM?

I recently ran into a problem with Box2D where my player was moving at a slow speed. I use LinearImpulse's to move the body but (100, 100) was the fastest it could go.
After researching it a bit, I know that the Box2D body is too large because Box2D uses meters and I'm typing it in pixels. I know I have to scale the bodies using a PPM constant, but it's not quite making sense to me.
I've created a PPM constant and set it to 32.0f.
const float PPM = 32.0f;
Here's how I create the dynamic player body:
void Physics::playerDynamic(float x, float y, float width, float height)
{
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position.Set(x / PPM, y / PPM);
body = world.CreateBody(&bodyDef);
b2PolygonShape dynamicBox;
dynamicBox.SetAsBox((64.0f) / PPM, (64.0f) / PPM);
b2FixtureDef fixtureDef;
fixtureDef.shape = &dynamicBox;
fixtureDef.filter.categoryBits = CATEGORY_PLAYER;
fixtureDef.filter.maskBits = CATEGORY_PLAYER;
fixtureDef.filter.groupIndex = -1;
body->CreateFixture(&fixtureDef);
world.Step(timeStep, velocityIterations, positionIterations);
posX = x;
posY = y;
bodyType = "player";
}
I understand that I need to scale down the body, which I did by dividing it by the PPM. But now the body is really small and won't collide how I'd like it to.
Here is the function where I apply the impulse to the player body:
void Physics::moveBodies()
{
myCollisionDetection myListener;
world.SetContactListener(&myListener);
if (bodyType != "player")
{
}
else if (bodyType == "player")
{
body->SetAwake(true);
float forceX = 0;
float forceY = 0;
switch (moveState)
{
case MS_UP:
forceY = -50;
break;
case MS_DOWN:
forceY = 50;
break;
case MS_LEFT:
forceX = -50;
break;
case MS_RIGHT:
forceX = 50;
break;
case MS_UPRIGHT:
forceY = -50;
forceX = 50;
break;
case MS_UPLEFT:
forceY = -50;
forceX = -50;
break;
case MS_DOWNRIGHT:
forceY = 50;
forceX = 50;
break;
case MS_DOWNLEFT:
forceY = 50;
forceX = -50;
break;
case MS_STOP:
body->SetLinearVelocity(b2Vec2(0, 0));
}
body->ApplyLinearImpulse(b2Vec2(forceX, forceY ), body->GetWorldCenter(), true);
pos = body->GetPosition();
posX = body->GetPosition().x;
posY = body->GetPosition().y;
}
world.Step(timeStep, velocityIterations, positionIterations);
}
I've been researching this for quite a while and it seems simple but I'm having a hard time applying it to my code.
So what do I do from here? Do I scale the body back up?
I'm also using SDL2 for the graphics. Do I need to change anything with the rendering?

OpenGL Model Loader Issue

Finally got my model loader working (based off a previous question). Stores all the values fine, runs glDrawElemts fine - yet it doesn't run glDrawArrays.
Yeah, first thing you'd say is 'glDrawArrays clearly isn't written out right'. That's the problem - I'm 99% sure it is.
Code is as follows:
bool modelLoader(string fileName,vector<GLfloat>& vertices, vector<GLushort>& indices)
{
fstream objFile;
vector<GLfloat> localVertices;
string dataLine;
stringstream mystream;
GLfloat x, y, z;
GLushort ind1, ind2, ind3;
char c, d;
vertices.clear();
indices.clear();
for (int i = 0; i < 3; i++)
{
vertices.push_back(0);
}
for (int i = 0; i < 3; i++)
{
localVertices.push_back(0);
}
objFile.open(fileName);
if (!objFile.good())
{
printf("Error with loader");
return false;
}
while (!objFile.eof())
{
getline(objFile, dataLine);
if (dataLine == "")
{
mystream.clear();
continue;
}
mystream.clear();
mystream.str(dataLine);
c = dataLine[0];
d = dataLine[1];
mystream.ignore(2);
switch (c)
{
case 'v':
{
switch (d)
{
case 'n':
{ /* for normals */ break;}
case ' ':
mystream >> x >> y >> z;
localVertices.push_back(x);
localVertices.push_back(y);
localVertices.push_back(z);
printf("\nVertices: %f, %f, %f", x, y, z);
break;
default:
{break;}
}
break;
}
case 'f':
{
//printf("F entered");
mystream >> ind1 >> ind2 >> ind3;
vertices.push_back(localVertices[ind1* 3 + 0]);
vertices.push_back(localVertices[ind1* 3 + 1]);
vertices.push_back(localVertices[ind1* 3 + 2]);
vertices.push_back(localVertices[ind2* 3 + 0]);
vertices.push_back(localVertices[ind2* 3 + 1]);
vertices.push_back(localVertices[ind2* 3 + 2]);
vertices.push_back(localVertices[ind3* 3 + 0]);
vertices.push_back(localVertices[ind3* 3 + 1]);
vertices.push_back(localVertices[ind3* 3 + 2]);
indices.push_back(ind1);
indices.push_back(ind2);
indices.push_back(ind3);
printf("\nIndices: %d, %d, %d", ind1, ind2, ind3);
break;
}
case !'v' || !'f':
{
break;
}
default:
{break;}
}
mystream.clear();
}
objFile.close();
return true;
}
From here I go on to call the following in the main function:
vector<GLfloat> vertices;
vector<GLushort> indices;
if (!modelLoader("triangles.obj", vertices, indices))
{
cout << "FAILED TO RUN: MODEL LOADER";
return 1;
}
Insert a bunch of other malarky about setting the model view matrix, running a loop to update every iteration...
int size = vertices.size()-3;
glDrawArrays(GL_TRIANGLES, 3, (GLsizei)size);
Oh, and the triangles.obj file is:
v -10.0 10.0 10.0
v -10.0 -10.0 10.0
v 10.0 -10.0 10.0
v 10.0 10.0 10.0
v 20.0 10.0 10.0
v 20.0 -10.0 10.0
f 1 2 3
f 4 5 6
Having no joy at all. As I said, using DrawElements does this fine, yet causes an exception error when I try to draw any other .obj file.
Any clues as to where I'm going wrong?
Are you intending not to draw the first triangle? The proper call to draw all triangles should be glDrawArrays(GL_TRIANGLES, 0, (GLsizei)vertices.size()); Before that you also need to enable calls and set the arrays up by glEnableClientState(GL_VERTEX_ARRAY) and glVertexPointer(). The same for other attributes like color and normals if you want them. BTW, all of this is deprecated since OpenGL 3.0 onward, so you may want to learn the core 3.0 API instead if you are just starting.

How to move relatively to the angle?

I keep looking up on the internet how to move from point A to point B on an angle with a specified distance. When I tried to code it, however, the camera just gets messed up and I'm moving in random directions. I am using SDL/OpenGL with c++ and this is my player function. Right now, I'm trying to get the player to move forwards along the angle.
void player_action()
{
if (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_MOUSEMOTION:
{
player.rotxl = (screen->w)/2;
player.rotxd = event.motion.x - player.rotxl;
player.rotx = player.rotx + (player.rotxd/4);
if (player.rotx < 0)
{
player.rotx = player.rotx + 360;
};
if (player.rotx > 360)
{
player.rotx = player.rotx - 360;
}
};
break;
case SDL_KEYDOWN:
switch (event.key.keysym.sym)
{
case SDLK_w:
{player.zvel = 8.0f;}; break;
case SDLK_a:
{player.xvel = 8.0f;}; break;
case SDLK_s:
{player.zvel = -8.0f;}; break;
case SDLK_d:
{player.xvel = -8.0f;}; break;
case SDLK_ESCAPE:
{running = false;}; break;
default: break;
}; break;
case SDL_KEYUP:
switch(event.key.keysym.sym)
{
case SDLK_w:
{player.zvel = 0.0f;}; break;
case SDLK_a:
{player.xvel = 0.0f;}; break;
case SDLK_s:
{player.zvel = 0.0f;}; break;
case SDLK_d:
{player.xvel = 0.0f;}; break;
default: break;
};
break;
};
};
player.x = player.x + float(player.zvel*cos((double)player.rotx));
player.z = player.z + float(player.zvel*sin((double)player.rotx));
glRotatef(player.rotx, 0.0f, 1.0f, 0.0f);
glTranslatef(player.x, player.y, player.z);
SDL_WarpMouse((screen->w/2), (screen->h/2));
};
If I'm correct the math functions sin and cos both take angles in radians, not degrees as player.rotx seems to be. Try the following:
player.x = player.x + float(player.zvel*cos((double)player.rotx*0.0174532925));
player.z = player.z + float(player.zvel*sin((double)player.rotx*0.0174532925));
We're multiplying player.rotx by pi/180, which is how we convert degrees to radians.
Not sure if this is your only problem, but it certainly appears to be one of them.
Two possible sources of the issue I see:
The standard C++ cos/sin function take a function in radians instead of degrees (one radian = 180/pi degrees).
While I'm not familiar with SDL a quick look at the docs makes me think you should be using event.motion.xrel instead of .x. You'll have to change your rotx calculation which should not need the screen width.