Im total beginner. I have a C++ GUI project in Visual Studio. It's working fine.
I would like to launch a function (when pressing a button in GUI) from existing cpp file opencvtesti.cpp, which I'm trying to include into this GUI project.
I added a existing file by pressing right mouse button over "source files" and added "opencvtesti.cpp". This .cpp was also workign fine before combining it to this GUI project. Also created opencvtesti.h and removed #includes from .cpp.
My code looks like this. But something goes wrong. Is there some dublicates in variables? I can't find them... I think I have done something wrong.
Errors:
Error LNK1169 one or more multiply defined symbols found Project5 C:\Users\....Project5.exe 1
Error LNK2005 "class Pylon::CPylonImage __cdecl SampleImageCreator::CreateMandelbrotFractal(enum Pylon::EPixelType,unsigned int,unsigned int)" (?CreateMandelbrotFractal#SampleImageCreator##$$FYA?AVCPylonImage#Pylon##W4EPixelType#3#II#Z) already defined in MyForm.obj Project5 C:\Users\....\source\repos\Project5\Project5\opencvtesti.obj 1
Error LNK2005 "class Pylon::CPylonImage __cdecl SampleImageCreator::CreateJuliaFractal(enum Pylon::EPixelType,unsigned int,unsigned int)" (?CreateJuliaFractal#SampleImageCreator##$$FYA?AVCPylonImage#Pylon##W4EPixelType#3#II#Z) already defined in MyForm.obj Project5 C:\Users\....\source\repos\Project5\Project5\opencvtesti.obj 1
Error LNK2005 "class Pylon::CPylonImage __cdecl SampleImageCreator::CreateMandelbrotFractal(enum Pylon::EPixelType,unsigned int,unsigned int)" (?CreateMandelbrotFractal#SampleImageCreator##YA?AVCPylonImage#Pylon##W4EPixelType#3#II#Z) already defined in MyForm.obj Project5 C:\Users\...\source\repos\Project5\Project5\opencvtesti.obj 1
Error LNK2005 "class Pylon::CPylonImage __cdecl SampleImageCreator::CreateJuliaFractal(enum Pylon::EPixelType,unsigned int,unsigned int)" (?CreateJuliaFractal#SampleImageCreator##YA?AVCPylonImage#Pylon##W4EPixelType#3#II#Z) already defined in MyForm.obj Project5 C:\Users\...\source\repos\Project5\Project5\opencvtesti.obj 1
MyForm.cpp:
#include "MyForm.h"
#include <iostream>
using namespace System;
using namespace System::Windows::Forms;
[STAThreadAttribute]
void main(array<String^>^ args) {
Application::EnableVisualStyles();
Application::SetCompatibleTextRenderingDefault(false);
Project5::MyForm form;
Application::Run(% form);
}
MyForm.h:
#pragma once
#include <fstream>
#include <iostream>
#include "Python.h"
#include "opencvtesti.h"
namespace Project5 {
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
/// <summary>
/// Summary for MyForm
/// </summary>
public ref class MyForm : public System::Windows::Forms::Form
{
public:
MyForm(void)
{
InitializeComponent();
//
//TODO: Add the constructor code here
//
}
protected:
/// <summary>
/// Clean up any resources being used.
/// </summary>
~MyForm()
{
if (components)
{
delete components;
}
}
protected:
private: System::Windows::Forms::Button^ button1;
private:
/// <summary>
/// Required designer variable.
/// </summary>
System::ComponentModel::Container ^components;
#pragma region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
void InitializeComponent(void)
{
this->button1 = (gcnew System::Windows::Forms::Button());
this->SuspendLayout();
//
// button1
//
this->button1->Location = System::Drawing::Point(13, 67);
this->button1->Name = L"button1";
this->button1->Size = System::Drawing::Size(75, 23);
this->button1->TabIndex = 2;
this->button1->Text = L"Press this";
this->button1->UseVisualStyleBackColor = true;
this->button1->Click += gcnew System::EventHandler(this, &MyForm::button1_Click);
//
// MyForm
//
this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
this->ClientSize = System::Drawing::Size(187, 180);
this->Controls->Add(this->button1);
this->Name = L"MyForm";
this->Text = L"GUI test";
this->ResumeLayout(false);
}
#pragma endregion
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
std::ofstream outfile("aukeaako.txt");
outfile << "No aukeniko? :)" << std::endl;
outfile.close();
Py_Initialize();
FILE* fd = fopen("aukesko.py", "r");
PyRun_SimpleFileEx(fd, "aukesko.py", 0);
}
};
}
opencvtesti.h:
#ifndef OPENCVTESTI_H
#define OPENCVTESTI_H
#pragma once
#include <pylon/PylonIncludes.h>
#include <pylon/PylonGUI.h>
#include <SampleImageCreator.h>
#include <conio.h>
int opencvtesti();
#endif
opencvtesti.cpp:
#include "opencvtesti.h"
// Namespace for using pylon objects.
using namespace Pylon;
// Namespace for using cout.
using namespace std;
// Number of images to be grabbed.
static const uint32_t c_countOfImagesToGrab = 1000;
int opencvtesti(int /*argc*/, char* /*argv*/[])
{
// The exit code of the sample application.
int exitCode = 0;
// Before using any pylon methods, the pylon runtime must be initialized.
PylonInitialize();
try
{
// Define constants.
static const uint32_t cNumTilesX = 3;
static const uint32_t cNumTilesY = 2;
static const uint32_t cWindowBorderSizeX = 25;
static const uint32_t cWindowBorderSizeY = 125;
static const uint32_t cScreenStartX = 40;
static const uint32_t cScreenStartY = 40;
static const uint32_t cMaxIndex = 31;
static const size_t cNumWindows = cNumTilesY * cNumTilesX;
static const uint32_t cMaxWidth = 640;
static const uint32_t cMaxHeight = 480;
// Create an array of image windows.
CPylonImageWindow imageWindows[cNumWindows];
// Create an Instant Camera object.
CInstantCamera camera(CTlFactory::GetInstance().CreateFirstDevice());
// Print the model name of the camera.
cout << "Using device " << camera.GetDeviceInfo().GetModelName() << endl;
// Start the grab. Only display the latest image.
camera.StartGrabbing(c_countOfImagesToGrab, GrabStrategy_LatestImageOnly);
// This smart pointer will receive the grab result data.
CGrabResultPtr ptrGrabResult;
// Grab images and show the tiles of each image in separate image windows.
while (camera.IsGrabbing())
{
// Wait for an image and then retrieve it. A timeout of 5000 ms is used.
camera.RetrieveResult(5000, ptrGrabResult, TimeoutHandling_ThrowException);
// If the image was grabbed successfully.
if (ptrGrabResult->GrabSucceeded())
{
// This image object is used for splitting the grabbed image into tiles.
CPylonImage image;
// Attach the grab result to a pylon image.
image.AttachGrabResultBuffer(ptrGrabResult);
// Compute tile sizes.
uint32_t imageTileWidth = min(image.GetWidth(), cMaxWidth) / cNumTilesX;
uint32_t imageTileHeight = min(image.GetHeight(), cMaxHeight) / cNumTilesY;
imageTileWidth -= imageTileWidth % GetPixelIncrementX(image.GetPixelType());
imageTileHeight -= imageTileWidth % GetPixelIncrementY(image.GetPixelType());
uint32_t windowTileWidth = imageTileWidth + cWindowBorderSizeX;
uint32_t windowTileHeight = imageTileHeight + cWindowBorderSizeY;
// Create and display the tiles of the grabbed image.
for (uint32_t indexTileX = 0; indexTileX < cNumTilesX; ++indexTileX)
{
for (uint32_t indexTileY = 0; indexTileY < cNumTilesY; ++indexTileY)
{
size_t arrayIndex = indexTileY * cNumTilesX + indexTileX;
bool windowCreated = false;
if (!imageWindows[arrayIndex].IsValid())
{
// Create the image window and position the image window as a tile on the screen.
// The Image Window stores the last size and position.
// The last Image Window indices are used here to avoid changing
// the settings of the windows used for other samples.
size_t windowIndex = cMaxIndex - arrayIndex;
imageWindows[arrayIndex].Create(windowIndex,
cScreenStartX + indexTileX * windowTileWidth,
cScreenStartY + indexTileY * windowTileHeight,
windowTileWidth,
windowTileHeight
);
windowCreated = true;
}
// Get the image area of interest (Image AOI) that includes the tile. This is a zero copy operation.
CPylonImage tile = image.GetAoi(indexTileX * imageTileWidth, indexTileY * imageTileHeight, imageTileWidth, imageTileHeight);
// Set the tile image.
imageWindows[arrayIndex].SetImage(tile);
// Show the image.
imageWindows[arrayIndex].Show();
if (windowCreated)
{
// Wait a little to show how the windows appear on the screen.
::Sleep(200);
}
}
}
}
else
{
throw RUNTIME_EXCEPTION("Error image grab failed: %hs", ptrGrabResult->GetErrorDescription().c_str());
}
}
// Destroy the windows.
for (size_t arrayIndex = 0; arrayIndex < cNumWindows; ++arrayIndex)
{
// Close() closes and destroys the window.
imageWindows[arrayIndex].Close();
// Wait a little to show how the windows are removed from the screen.
::Sleep(200);
}
}
catch (const GenericException& e)
{
// Error handling.
cerr << "An exception occurred." << endl
<< e.GetDescription() << endl;
exitCode = 1;
cerr << endl << "Press enter to exit." << endl;
while (cin.get() != '\n');
}
// Releases all pylon resources.
PylonTerminate();
return exitCode;
}
Edit:
SampelImageCreator.h looks like this:
// Contains functions for creating sample images.
#ifndef INCLUDED_SAMPLEIMAGECREATOR_H_2792867
#define INCLUDED_SAMPLEIMAGECREATOR_H_2792867
#include <pylon/PylonImage.h>
#include <pylon/Pixel.h>
#include <pylon/ImageFormatConverter.h>
namespace SampleImageCreator
{
Pylon::CPylonImage CreateJuliaFractal( Pylon::EPixelType pixelType, uint32_t width, uint32_t height )
{
// Allow all the names in the namespace Pylon to be used without qualification.
using namespace Pylon;
// Define Constants.
static const SRGB8Pixel palette[] =
{
{0, 28, 50}, {0, 42, 75}, {0, 56, 100}, {0, 70, 125}, {0, 84, 150},
{0, 50, 0}, {0, 100, 0}, {0, 150, 0}, {0, 200, 0}, {0, 250, 0},
{50, 0, 0}, {100, 0, 0}, {150, 0, 0}, {200, 0, 0}, {250, 0, 0}
};
uint32_t numColors = sizeof( palette ) / sizeof( palette[0] );
const double cX = -0.735;
const double cY = 0.11;
const double cMaxX = 1.6;
const double cMinX = -1.6;
const double cMaxY = 1;
const double cMinY = -1;
const uint32_t cMaxIterations = 50;
// Create image.
CPylonImage juliaFractal( CPylonImage::Create( PixelType_RGB8packed, width, height ) );
// Get the pointer to the first pixel.
SRGB8Pixel* pCurrentPixel = (SRGB8Pixel*) juliaFractal.GetBuffer();
// Compute the fractal.
for (uint32_t pixelY = 0; pixelY < height; ++pixelY)
{
for (uint32_t pixelX = 0; pixelX < width; ++pixelX, ++pCurrentPixel)
{
long double x = ((cMaxX - cMinX) / width) * pixelX + cMinX;
long double y = cMaxY - pixelY * ((cMaxY - cMinY) / height);
long double xd = 0;
long double yd = 0;
uint32_t i = 0;
for (; i < cMaxIterations; ++i)
{
xd = x * x - y * y + cX;
yd = 2 * x * y + cY;
x = xd;
y = yd;
if ((x * x + y * y) > 4)
{
break;
}
}
if (i >= cMaxIterations)
{
*pCurrentPixel = palette[0];
}
else
{
*pCurrentPixel = palette[i % numColors];
}
}
}
// Convert the image to the target format if needed.
if (juliaFractal.GetPixelType() != pixelType)
{
CImageFormatConverter converter;
converter.OutputPixelFormat = pixelType;
converter.OutputBitAlignment = OutputBitAlignment_MsbAligned;
converter.Convert( juliaFractal, CPylonImage( juliaFractal ) );
}
// Return the image.
return juliaFractal;
}
Pylon::CPylonImage CreateMandelbrotFractal( Pylon::EPixelType pixelType, uint32_t width, uint32_t height )
{
// Allow all the names in the namespace Pylon to be used without qualification.
using namespace Pylon;
// Define constants.
static const SRGB8Pixel palette[] =
{
{0, 28, 50}, {0, 42, 75}, {0, 56, 100}, {0, 70, 125}, {0, 84, 150},
{0, 50, 0}, {0, 100, 0}, {0, 150, 0}, {0, 200, 0}, {0, 250, 0},
{50, 0, 0}, {100, 0, 0}, {150, 0, 0}, {200, 0, 0}, {250, 0, 0}
};
uint32_t numColors = sizeof( palette ) / sizeof( palette[0] );
const double cMaxX = 1.0;
const double cMinX = -2.0;
const double cMaxY = 1.2;
const double cMinY = -1.2;
const uint32_t cMaxIterations = 50;
// Create image.
CPylonImage mandelbrotFractal( CPylonImage::Create( PixelType_RGB8packed, width, height ) );
// Get the pointer to the first pixel.
SRGB8Pixel* pCurrentPixel = (SRGB8Pixel*) mandelbrotFractal.GetBuffer();
// Compute the fractal.
for (uint32_t pixelY = 0; pixelY < height; ++pixelY)
{
for (uint32_t pixelX = 0; pixelX < width; ++pixelX, ++pCurrentPixel)
{
long double xStart = ((cMaxX - cMinX) / width) * pixelX + cMinX;
long double yStart = cMaxY - pixelY * ((cMaxY - cMinY) / height);
long double x = xStart;
long double y = yStart;
long double xd = 0;
long double yd = 0;
uint32_t i = 0;
for (; i < cMaxIterations; ++i)
{
xd = x * x - y * y + xStart;
yd = 2 * x * y + yStart;
x = xd;
y = yd;
if ((x * x + y * y) > 4)
{
break;
}
}
if (i >= cMaxIterations)
{
*pCurrentPixel = palette[0];
}
else
{
*pCurrentPixel = palette[i % numColors];
}
}
}
// Convert the image to the target format if needed.
if (mandelbrotFractal.GetPixelType() != pixelType)
{
CImageFormatConverter converter;
converter.OutputPixelFormat = pixelType;
converter.OutputBitAlignment = OutputBitAlignment_MsbAligned;
converter.Convert( mandelbrotFractal, CPylonImage( mandelbrotFractal ) );
}
// Return the image.
return mandelbrotFractal;
}
}
#endif /* INCLUDED_SAMPLEIMAGECREATOR_H_2792867 */
If you provide a definition of your function within a header file, you must declare it with inline keyword:
namespace SampleImageCreator
{
inline Pylon::CPylonImage CreateJuliaFractal( Pylon::EPixelType pixelType, uint32_t width, uint32_t height )
{
Also, Template functions are inline by default.
In your case you have an ODR (One Definition Rule) violation, that is your in-header defined functions are added to every translation unit that includes your header. Multiple Definitions are not allowed, otherwise the linker would not know which definition to use.
But if you use inline, you allow the linker to have multiple definitions.
Try to wrap code in opencvtesti files in personal namespace to avoid problems with linking
Check all your headers, especially SampleImageCreator.h and make sure that there is no redefinition of the variables specified in the errors
It could be problem with call conventions, like cdecl. Chance is
0.01%, but you can "play" with settings in Properties -> C/C++ -> Other -> Call conventions
Related
I'm new to c++, and I need to use list container for my 3D marker-based watershed function. But I get strange bugs when I use list container. May I know what's wrong with my code?
Thank you so much!
I used a vector of list to save the wait-to-search pixel index.
I declare the variable in this way (GVInt32 is int32_t):
vector<list<GVInt32>> toSearchList;
And I used these two kinds of operations of list:
Add a new wait-to-search index at the end of a list
toSearchList[cnt].push_back(newidx);
Remove a searched element at the middle of a list(it is list<GVInt32>::iterator):
it = toSearchList[cnt].erase(it);
But I get two kinds of errors:
malloc(): memory corruption when I do
toSearchList[cnt].push_back(newidx);
I get not accessible elements in the end of the list when I inspect the variable in debugger:
[Not accessible elements][1]
https://i.stack.imgur.com/flJg3.png
The IDE is QT creator 4.15.2
The system is Ubuntu 18.04
The full code
watershed_wz.cpp:
#include "watershed_wz.h"
WaterShed_WZ::WaterShed_WZ()
{
}
array<GVInt32, 6> WaterShed_WZ::getNeighbor_WZ(const GVInt32 idx, const GVInt32 width, const GVInt32 height, const GVInt32 thick) {
GVInt32 SLICE = width * height;
GVInt32 z = idx / SLICE;
GVInt32 y = (idx%SLICE) / width;
GVInt32 x = idx % width;
array<GVInt32, 6> nIndex;
nIndex[0] = (x == 0) ? -1 : (idx - 1);
nIndex[1] = ((x + 1) == width) ? -1 : (idx + 1);
nIndex[2] = (y == 0) ? -1 : (idx - width);
nIndex[3] = ((y + 1) == height) ? -1 : (idx + width);
nIndex[4] = (z == 0) ? -1 : (idx - SLICE);
nIndex[5] = ((z + 1) == thick) ? -1 : (idx + SLICE);
return nIndex;
}
void WaterShed_WZ::Watershed3D_WZ(
const Mat im,
const GVInt32 width,
const GVInt32 height,
const GVInt32 thick,
GVInt32* label,
const vector<vector<GVInt32>> marker)
{
//<Parameter>
//<image> the image for watershed
//<width> the width of the image
//<height> the height of the image
//<thick> the thick of the image
//<label> the map to save result. need to allocate memory before use watershed
//<marker> the marker's index
// const GVByte* image=im.data;
auto t0 = chrono::high_resolution_clock::now();
QTextStream out(stdout);
// const GVInt32 SZ_slice = width * height;
// const GVInt32 SZ = SZ_slice * thick;
const GVInt32 markerNum = marker.size();
// create toSearchList. Saved pixel connected to labeled pixels and wait to search
vector<list<GVInt32>> toSearchList;
toSearchList.resize(markerNum);
// set label to INIT (unsearched)
// ::memset(label, -1, sizeof(GVInt32) * SZ);
// initialize
array<GVInt32, 6> nIdx;
for (size_t i = 0; i < markerNum; i++)
{
for (GVInt32 idx : marker[i])
{
// initialize label (which can be considered as a map of pointer to labelBar)
label[idx] = i + 1;
nIdx = getNeighbor_WZ(idx, width, height, thick);
for (GVInt32 newidx : nIdx)
{
if (newidx != -1)
{
if (label[newidx] == -1) {
toSearchList[i].push_back(newidx);
label[newidx] = -2;
}
}
}
}
}
//watershed
GVByte h;
GVInt32 idx;
for (int h_cnt = 0; h_cnt < (1+(int)GV_BYTE_MAX); h_cnt++) // water height
{
h = (GVByte)h_cnt;
for (GVInt32 cnt = 0; cnt < markerNum; cnt++) { // for each marker
list<GVInt32>::iterator it = toSearchList[cnt].begin();
while (!toSearchList[cnt].empty())
{
// for each pixel connected to the cnt-th labeled region
idx = *it;
// if this pixel is higher than water, ignore it
if (im.at<unsigned char>(idx) > h)
{
++it;
if(it == toSearchList[cnt].end())
{
break;
}
else
{
continue;
}
}
// this pixel is lower than water, assign it
label[idx] = cnt + 1;
// L.at<int>(idx)=cnt + 1;
// add new neighbor
nIdx = getNeighbor_WZ(idx, width, height, thick);
for (GVInt32 newidx : nIdx)
{
if (newidx != -1)
{
if (label[newidx]== -1) {
toSearchList[cnt].push_back(newidx);
label[newidx] = -2;
// L.at<int>(newidx)=-2;
}
}
}
// erase searched pixel
it = toSearchList[cnt].erase(it);
if(it == toSearchList[cnt].end())
{
break;
}
else
{
continue;
}
}
}
}
auto t1 = chrono::high_resolution_clock::now();
auto dt = 1.e-9 * chrono::duration_cast<std::chrono::nanoseconds>(t1 - t0).count();
out << "Watershed used " << dt << " seconds.\n\n" << Qt::endl;
}
watershed_wz.h:
#ifndef WATERSHED_WZ_H
#define WATERSHED_WZ_H
#define _USE_MATH_DEFINES
#include <vector>
#include <array>
#include <list>
#include <opencv2/core.hpp> //basic building blocks of opencv
#include <opencv2/imgcodecs.hpp> // image io
#include <opencv2/highgui.hpp> //image display
#include <QDebug>
#include <QTextStream>
#include <chrono>
using namespace std;
using namespace cv;
typedef unsigned char GVByte;
typedef int32_t GVInt32;
//typedef uint32_t GVInt32U;
const GVByte GV_BYTE_MAX = UCHAR_MAX;
class WaterShed_WZ
{
public:
WaterShed_WZ();
static array<GVInt32, 6> getNeighbor_WZ(const GVInt32 idx, const GVInt32 width, const GVInt32 height, const GVInt32 thick);
static void Watershed3D_WZ(
const Mat im,
const GVInt32 width,
const GVInt32 height,
const GVInt32 thick,
GVInt32* label,
const vector<vector<GVInt32>> marker);
};
#endif // WATERSHED_WZ_H
try delete [cnt] index everywhere like this
toSearchList[cnt].end() --> toSearchList.end()
I have code that are to paint a BMP image on a TPaintBox on a VCL form in a C++ application.
Everything works fine as long as I only have one image to paint, on one form. When I create a second form, I get sporadic access violations.
The code is called from a thread and I'm using the Synchronize function in order to synchronize with the main VCL thread as this
void TCameraForm::loadImage(FramePtr frame)
{
syncing s;
s.aFrame = frame;
s.theForm = this;
//Synchronize with UI thread
TThread::Synchronize(0, &s.fn);
}
In the code, a FramePtr is a shared pointer to one individual 'frame', holding a device dependent bitmap.
The syncing variable is a structure, holding the code for the actual painting:
//This is a trick to use VCL's TThread::Synchronize function "with parameters"
//Thanks to Mr. R. Lebeau for sharing this trick.
struct syncing
{
FramePtr aFrame;
TCameraForm* theForm;
int tag;
void __fastcall fn()
{
try
{
//Create a device dependent bitmap
BitMap aBitMap(aFrame);
//Get the bitmap memory into a TMemoryStream
TMemoryStream* ms = new TMemoryStream();
int bytes = ms->Write(aBitmap.getBuffer()->mMemoryBuffer, aBitmap.getBuffer()->mBufferSize);
ms->Position = 0;
//Create a TPicture object that will be used for drawing on the paintbox
TBitmap* tbm = new TBitmap();
tbm->LoadFromStream(ms);
TRect stretchedRect(getStretchedDimensions(tbm->Width, tbm->Height, theForm->PaintBox1->Width, theForm->PaintBox1->Height));
theForm->PaintBox1->Canvas->StretchDraw(stretchedRect, tbm);
delete ms;
delete tbm;
}
catch(...)
{
Log(lError) << "Exception occured in the CameraFrame sync function";
}
}
};
The debugger mainly stops on creation of the bitmap.
I'm using BCC builder 10.3.2 and the classic compiler.
The bitmap class looks like this:
Header
class BitMap
{
public:
BitMap(FramePtr aFrame);
BitMap(unsigned long width, unsigned long height, ColorCode c, ImageMemoryBuffer& buf);
ImageMemoryBuffer* getBuffer();
~BitMap();
bool write(const string& file);
protected:
unsigned int mWidth;
unsigned int mHeight;
ColorCode mColorCode;
ImageMemoryBuffer mImageMemoryBuffer;
bool create();
bool release();
};
And CPP:
enum { THREE_CHANNEL = 0xC,};
enum { BMP_HEADER_SIZE = 54, };
enum { ALIGNMENT_SIZE = 4, };
namespace ai
{
BitMap::BitMap(FramePtr aFrame)
:
mWidth(0),
mHeight(0),
mColorCode(ColorCodeMono8),
mImageMemoryBuffer()
{
aFrame->GetImageSize(mImageMemoryBuffer.mBufferSize);
aFrame->GetWidth(mWidth);
aFrame->GetHeight(mHeight);
VmbPixelFormatType ePixelFormat = VmbPixelFormatMono8;
aFrame->GetPixelFormat(ePixelFormat);
if((ePixelFormat != VmbPixelFormatMono8) && (ePixelFormat != VmbPixelFormatRgb8))
{
throw(MVRException("Invalid pixel format: " + toString(ePixelFormat)));
}
mColorCode = (ePixelFormat == VmbPixelFormatRgb8) ? ColorCodeRGB24 : ColorCodeMono8;
VmbUchar_t *pImage = NULL;
if (aFrame->GetImage(pImage) != VmbErrorSuccess)
{
throw(MVRException("Failed \"getting\" image"));
}
mImageMemoryBuffer.mMemoryBuffer = (unsigned char*) pImage;
if(!create())
{
Log(lError) << "There was an error creating the bitmap";
throw(MVRException("Failed creating Bitmap"));
}
}
BitMap::BitMap(unsigned long width, unsigned long height, ColorCode c, ImageMemoryBuffer& buf)
:
mWidth(width),
mHeight(height),
mColorCode(c),
mImageMemoryBuffer(buf)
{
if(!create())
{
Log(lError) << "There was an error creating the bitmap";
throw(MVRException("Failed creating bitmap"));
}
}
BitMap::~BitMap()
{
if(!release())
{
Log(lError) << "There was an error releasing the bitmap";
}
}
ImageMemoryBuffer* BitMap::getBuffer()
{
return &mImageMemoryBuffer;
}
bool BitMap::create()
{
try
{
unsigned char nNumColors; // Number of colors of our image
unsigned char nPadLength; // The padding we need to align the bitmap ALIGNMENT_SIZE
unsigned long nPaletteSize = 0; // The size of the bitmap's palette
unsigned long nHeaderSize; // The size of the bitmap's header
unsigned long nFileSize; // The size of the bitmap file
unsigned char* pBitmapBuffer; // A buffer we use for creating the bitmap
unsigned char* pCurBitmapBuf; // A cursor to move over "pBitmapBuffer"
unsigned char* pCurSrc; // A cursor to move over the given buffer "pBuffer"
unsigned long px; // A single pixel for storing transformed color information
unsigned long x; // The horizontal position within our image
unsigned long y; // The vertical position within our image
unsigned long i; // Counter for some iteration
// The bitmap header
char fileHeader[14] = { 'B','M', // Default
0,0,0,0, // File size
0,0,0,0, // Reserved
0,0,0,0 }; // Offset to image content
char infoHeader[40] = { 40,0,0,0, // Size of info header
0,0,0,0, // Width
0,0,0,0, // Height
1,0, // Default
0, 0 }; // bpp
if ( 0 == mImageMemoryBuffer.mBufferSize || 0 == mWidth || 0 == mHeight )
{
Log(lError) << "Zero bitmap buffer, width ot height in Bitmap constructor";
return false;
}
if ( mColorCode == (mColorCode & THREE_CHANNEL) )
{
nNumColors = 3;
}
else
{
nNumColors = 1;
}
// Bitmap padding always is a multiple of four Bytes. If data is not we need to pad with zeros.
nPadLength = (mWidth * nNumColors) % ALIGNMENT_SIZE;
if ( 0 != nPadLength )
{
nPadLength = ALIGNMENT_SIZE - nPadLength;
}
if ( ColorCodeRGB24 != mColorCode )
{
nPaletteSize = 256;
}
nHeaderSize = BMP_HEADER_SIZE + nPaletteSize * 4;
pBitmapBuffer = (unsigned char*)malloc( nHeaderSize + mImageMemoryBuffer.mBufferSize + (nPadLength * mHeight) );
nFileSize = nHeaderSize + mImageMemoryBuffer.mBufferSize + (nPadLength * mHeight);
// File size
fileHeader[ 2] = (char)(nFileSize);
fileHeader[ 3] = (char)(nFileSize >> 8);
fileHeader[ 4] = (char)(nFileSize >> 16);
fileHeader[ 5] = (char)(nFileSize >> 24);
// Offset to image content
fileHeader[10] = (char)(nHeaderSize);
fileHeader[11] = (char)(nHeaderSize >> 8);
fileHeader[12] = (char)(nHeaderSize >> 16);
fileHeader[13] = (char)(nHeaderSize >> 24);
// Width
infoHeader[ 4] = (char)(mWidth);
infoHeader[ 5] = (char)(mWidth >> 8);
infoHeader[ 6] = (char)(mWidth >> 16);
infoHeader[ 7] = (char)(mWidth >> 24);
// Height (has to be negative for a top down image)
infoHeader[ 8] = (char)(-(long)mHeight);
infoHeader[ 9] = (char)(-(long)mHeight >> 8);
infoHeader[10] = (char)(-(long)mHeight >> 16);
infoHeader[11] = (char)(-(long)mHeight >> 24);
// bpp
infoHeader[14] = 8 * nNumColors;
// Image size
infoHeader[20] = (char)(mImageMemoryBuffer.mBufferSize);
infoHeader[21] = (char)(mImageMemoryBuffer.mBufferSize >> 8);
infoHeader[22] = (char)(mImageMemoryBuffer.mBufferSize >> 16);
infoHeader[23] = (char)(mImageMemoryBuffer.mBufferSize >> 24);
// Palette size
infoHeader[32] = (char)(nPaletteSize);
infoHeader[33] = (char)(nPaletteSize >> 8);
infoHeader[34] = (char)(nPaletteSize >> 16);
infoHeader[35] = (char)(nPaletteSize >> 24);
// Used colors
infoHeader[36] = (char)(nPaletteSize);
infoHeader[37] = (char)(nPaletteSize >> 8);
infoHeader[38] = (char)(nPaletteSize >> 16);
infoHeader[39] = (char)(nPaletteSize >> 24);
// Write header
pCurBitmapBuf = pBitmapBuffer;
memcpy(pCurBitmapBuf, fileHeader, 14);
pCurBitmapBuf += 14;
memcpy(pCurBitmapBuf, infoHeader, 40);
pCurBitmapBuf += 40;
for(i = 0; i < nPaletteSize; ++i)
{
pCurBitmapBuf[0] = (char)(i);
pCurBitmapBuf[1] = (char)(i);
pCurBitmapBuf[2] = (char)(i);
pCurBitmapBuf[3] = 0;
pCurBitmapBuf += 4;
}
// RGB -> BGR (a Windows bitmap is BGR)
if(mColorCode == ColorCodeRGB24)
{
pCurSrc = (unsigned char*) mImageMemoryBuffer.mMemoryBuffer;
for(y=0; y < mHeight; ++y, pCurBitmapBuf += nPadLength )
{
for (x = 0; x < mWidth; ++x, pCurSrc += 3, pCurBitmapBuf += 3)
{
px = 0;
// Create a 4 Byte structure to store ARGB (we don't use A)
px = px | (pCurSrc[0] << 16) | (pCurSrc[1] << 8) | pCurSrc[2];
// Due to endianess ARGB is stored as BGRA
// and we only have to write the first three Bytes
memcpy( pCurBitmapBuf, &px, 3 );
}
// Add padding at the end of each row
memset( pCurBitmapBuf, 0, nPadLength );
}
mColorCode = ColorCodeBGR24;
}
// Mono8
else
{
if(nPadLength == 0)
{
memcpy( pCurBitmapBuf, mImageMemoryBuffer.mMemoryBuffer, mImageMemoryBuffer.mBufferSize );
}
else
{
pCurSrc = (unsigned char*)mImageMemoryBuffer.mMemoryBuffer;
for (y=0; y < mHeight; ++y, pCurSrc += mWidth * nNumColors)
{
// Write a single row of colored pixels
memcpy( pCurBitmapBuf, pCurSrc, mWidth * nNumColors );
pCurBitmapBuf += mWidth * nNumColors;
// Write padding pixels
memset(pCurBitmapBuf, 0, nPadLength);
pCurBitmapBuf += nPadLength;
}
}
}
mImageMemoryBuffer.mMemoryBuffer = pBitmapBuffer;
mImageMemoryBuffer.mBufferSize = nFileSize;
return true;
}
catch(...)
{
Log(lError) << "Exception in creation of bitmap create function";
return false;
}
}
bool BitMap::release()
{
try
{
if (mImageMemoryBuffer.mMemoryBuffer != NULL && mImageMemoryBuffer.mBufferSize > 0)
{
free(mImageMemoryBuffer.mMemoryBuffer);
mImageMemoryBuffer.mMemoryBuffer = NULL;
}
return true;
}
catch(...)
{
return false;
}
}
bool BitMap::write(const string& fName)
{
if (mImageMemoryBuffer.mMemoryBuffer == NULL)
{
return false;
}
FILE *file = fopen(fName.c_str(), "wb");
if(!file)
{
Log(lError) << "Failed opening file: " << fName;
return false;
}
fwrite(mImageMemoryBuffer.mMemoryBuffer, 1, mImageMemoryBuffer.mBufferSize, file );
fclose(file);
return true;
}
}
UPDATE: The above code works fine when executed by one thread. The problem occurs when several threads are involved. I have located the problem happening when the memcpy function is called in the creation of the bitmap (not the TBitmap), supporting this. So main problem is that the same memory is being manipulated by two or more threads at the same time.
For the above code, where would it be appropriate to incorporate a Mutex, in order to prevent the memory corruption? Or could one use another technique?
I am trying to play a sin wave sound with SDL2 by using the audio queue on C++. In order to do that, I have created a class "Speaker", which has a pushBeep function that is called every time a beep needs to be generated. I have created an AudioDevice successfully, and it is also successful when I do the QueueAudio to the device (I have checked on the debugger) but I can't seem to get any sound out of it.
I have tried changing the way I generate the samples in numerous ways, also, as I said previously, I have checked that the device is properly opened and the QueueAudio returns 0 for success.
This is the class
Speaker::Speaker()
{
SDL_AudioSpec ds;
ds.freq = Speaker::SPEAKER_FREQUENCY;
ds.format = AUDIO_F32;
ds.channels = 1;
ds.samples = 4096;
ds.callback = NULL;
ds.userdata = this;
SDL_AudioSpec os;
this->dev = SDL_OpenAudioDevice(NULL, 0, &ds, &os, NULL);
std::cout << "DEVICE: " << this->dev << std::endl;
SDL_PauseAudioDevice(this->dev, 0);
}
Speaker::~Speaker()
{
SDL_CloseAudioDevice(this->dev);
}
void Speaker::pushBeep(double freq, int duration) {
int nSamples = duration * Speaker::SPEAKER_FREQUENCY / 1000;
float* samples = new float[nSamples];
double v = 0.0;
for (int idx = 0; idx < nSamples; idx++) {
//float value = (float)Speaker::SPEAKER_AMPLITUDE * std::sin(v * 2 * M_PI / Speaker::SPEAKER_FREQUENCY);
float value = 440.0;
samples[idx] = value;
v += freq;
}
int a = SDL_QueueAudio(this->dev, (void*)samples, nSamples * sizeof(float));
std::cout << a << std::endl;
delete[] samples;
samples = NULL;
}
And this is how I call it
Speaker s;
s.pushBeep(440.0, 1000);
When I try with the sin wave generation code (commented) it gives me a "double to float loss of precision" error. When I use the fixed value (not commented) it does not give the error, but it still does not work.
I expect the program to output the sound.
Couple of things you are missing, or maybe you didn't add to your code snippet. You didn't specify an audio callback so when you call SDL_QueueAudio(); it didn't know what to do with the data I'm pretty sure. And you weren't calling SDL_PauseAudioDevice() in your example with the delay.
#include <math.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_audio.h>
#include <iostream>
namespace AudioGen
{
const int AMPLITUDE = 1;
const int SAMPLE_RATE = 44000;
// Globals
float *in_buffer;
SDL_atomic_t callback_sample_pos;
SDL_Event event;
SDL_bool running = SDL_TRUE;
/**
* Structure for holding audio metadata such as frequency
*/
struct AudioData
{
int sampleNum;
float frequency;
};
void audio_callback(void *user_data, Uint8 *raw_buffer, int bytes)
{
float *buffer = (float*)raw_buffer;
AudioData &audio_data(*static_cast<AudioData*>(user_data));
int nSamples = bytes / 4; // For F32
std::cout << nSamples << std::endl;
for(int i = 0; i < nSamples; i++, audio_data.sampleNum++)
{
double time = (double)audio_data.sampleNum / (double)SAMPLE_RATE;
buffer[i] = (float)(AMPLITUDE * sin(2.0f * M_PI * audio_data.frequency * time));
}
}
int buffer_length;
void callback(void *user_data, Uint8 *raw_buffer, int bytes)
{
float *buffer = (float*)raw_buffer;
int nSamples = bytes/4;
auto local_sample_pos = SDL_AtomicGet(&callback_sample_pos);
for(int i = 0; i < nSamples; ++i)
{
// Stop running audio if all samples are finished playing
if(buffer_length == local_sample_pos)
{
running = SDL_FALSE;
break;
}
buffer[i] = in_buffer[local_sample_pos];
++local_sample_pos;
}
SDL_AtomicSet(&callback_sample_pos, local_sample_pos);
}
class Speaker
{
public:
Speaker()
{
SDL_Init(SDL_INIT_AUDIO);
SDL_AudioSpec ds;
ds.freq = SAMPLE_RATE;
ds.format = AUDIO_F32;
ds.channels = 1;
ds.samples = 4096;
ds.callback = callback;
ds.userdata = &ad; // metadata for frequency
SDL_AudioSpec os;
dev = SDL_OpenAudioDevice(NULL, 0, &ds, &os, SDL_AUDIO_ALLOW_FORMAT_CHANGE);
}
~Speaker()
{
SDL_CloseAudioDevice(dev);
SDL_Quit();
}
void pushBeep(float frequency, int duration)
{
ad.frequency = frequency; // set the frequency for the beep
SDL_PauseAudioDevice(dev, 0);
SDL_Delay(duration); // wait while sound is playing
SDL_PauseAudioDevice(dev, 1);
}
void pushBeep2(float frequency, int duration )
{
int nSamples = duration * SAMPLE_RATE / 1000;
in_buffer = new float[nSamples];
buffer_length = nSamples;
for (int idx = 0; idx < nSamples; idx++) {
double time = (double)idx / (double)SAMPLE_RATE;
in_buffer[idx] = (float)(AMPLITUDE * std::sin(2.0f * M_PI * frequency * time));
}
SDL_QueueAudio(dev, in_buffer, nSamples * sizeof(float));
SDL_PauseAudioDevice(dev, 0);
while(running){
while(SDL_PollEvent(&event)!=0);
}
delete[] in_buffer;
}
private:
SDL_AudioDeviceID dev;
AudioData ad;
int sampleNum = 0;
};
} // End of namespace AudioGen
int main(int argc, char *argv[])
{
AudioGen::Speaker speaker;
//speaker.pushBeep(440, 1000);
speaker.pushBeep2(440.0f, 1000);
return 0;
}
I'm attempting to create a minimal usage example for https://github.com/ginsweater/gif-h
But, starting with a vector<uint8_t> of size imageWidth*imageHeight, the second GifWriteFrame call throws an access violation reading location exception
My attempt:
#include <gif.h>
#include "BOBImageConversion.h"
int main(void)
{
// USAGE:
// Create a GifWriter struct. Pass it to GifBegin() to initialize and write the header.
// Pass subsequent frames to GifWriteFrame().
// Finally, call GifEnd() to close the file handle and free memory.
int delay = 100;
auto i1 = BOBImageIO::BOBLoadImage("Camera7.png");
auto i2 = BOBImageIO::BOBLoadImage("Camera18.png");
vector<uint8_t> vi1 = BOBImageConversion::ARGB2RGBAuint8(i1);
vector<uint8_t> vi2 = BOBImageConversion::ARGB2RGBAuint8(i2);
cout << (vi1.size() == i1.Width()*i1.Height()) << endl; // true
cout << (vi2.size() == i2.Width()*i2.Height()) << endl; // true
auto fileName = "gif.gif";
GifWriter g;
GifBegin(&g, fileName, i1.Width(), i1.Height(), delay);
GifWriteFrame(&g, vi1.data(), i1.Width(), i1.Height(), delay);
GifWriteFrame(&g, vi2.data(), i2.Width(), i2.Height(), delay); // Exception thrown: Access violation reading location
GifEnd(&g);
return 0;
}
For the above point the code posted is a minimal example. What's wrong?
This works
#include <vector>
#include <cstdint>
#include <gif.h>
int main()
{
int width = 100;
int height = 200;
std::vector<uint8_t> vi1(width * height * 4, 0);
std::vector<uint8_t> vi2(width * height * 4, 255);
auto fileName = "bwgif.gif";
int delay = 100;
GifWriter g;
GifBegin(&g, fileName, width, height, delay);
GifWriteFrame(&g, vi1.data(), width, height, delay);
GifWriteFrame(&g, vi2.data(), width, height, delay);
GifEnd(&g);
return 0;
}
Segmentation fault when retrieving OGRE 3D 1.81 submesh data.
I tried to make use of the code from http://alumni.cs.ucr.edu/~sorianom/cs134_09win/
to get ogre mesh data for Bullet physics engine to use, but encountered an error message that said Segment Fault.
After reducing the code to find the reason I found it's "submesh->indexData->indexStart" that caused segment fault.
I am running on Ubuntu Linux 12.10 ( 32bit x86)(Due the budget limit, we can not afford to buy Windows), and use g++ as compiler.
Please help me, I am an elementary school teacher who are trying to make some CAI programs for students to learn Math, English...
I know cs134 sample code listed on the site is a little bit too old, I've upgrade all the meshes, dotsceneloader... but still cannot figure out what have to change.
Thank you!
The following is the reduced code that still makes the segment fault error message.
#include <Ogre.h>
#include <ExampleApplication.h>
#include <btBulletCollisionCommon.h>
class SampleApp : public ExampleApplication
{
public:
// Basic constructor
SampleApp()
{}
protected:
// Just override the mandatory create scene method
void createScene(void) {
mSceneMgr->setSkyBox(true, "Examples/CloudyNoonSkyBox");
Ogre::Light* myLight = mSceneMgr->createLight("Light0");
myLight->setType(Light::LT_POINT);
myLight->setPosition(0, 40, 0);
myLight->setDiffuseColour(1, 1, 1);
myLight->setSpecularColour(1, 1, 1);
Ogre::Entity* entity = mSceneMgr->createEntity("ogre", "ogrehead.mesh");
mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(entity);
Ogre::MeshPtr mesh = entity->getMesh();
Ogre::Mesh::SubMeshIterator j = mesh->getSubMeshIterator();
while (j.hasMoreElements()) {
Ogre::SubMesh* submesh = j.getNext();
std::cout << " submesh:" << submesh << "\n";
std::cout << " submesh->indexData:" << submesh->indexData << "\n";
//std::cout << " submesh->indexData->indexStart:" << submesh->indexData->indexStart << "\n";
int idxStart = submesh->indexData->indexStart;
int nIdx = submesh->indexData->indexCount;
}
}
};
// ----------------------------------------------------------------------------
// Main function, just boots the application object
// ----------------------------------------------------------------------------
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
int main(int argc, char **argv)
#endif
{
// Create application object
SampleApp app;
try
{
app.go();
}
catch( Exception& e )
{
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
std::cerr << "An exception has occured: " << e.getFullDescription();
#endif
}
return 0;
}
And the error message:
....
submesh:0xb752c080
submesh->indexData:0x8d042444
Segmentation fault (core dumped)
------------------
(program exited with code: 139)
The following is the gdb output:
(gdb) print submesh->indexData
$5 = (Ogre::IndexData *) 0x8d042444
(gdb) print submesh->indexData->indexStart
Cannot access memory at address 0x8d042458
(gdb)
ps: compiler setting: (You can compile the above code which is modified from CODE:BLOCK OGRE3D template , and bullet part isn't necessary in this reduced version)
g++ -o "%e" "%f" pkg-config --cflags --libs OGRE OIS bullet -I/usr/local/include/OGRE -I/usr/include/bullet
The original file is as following ( from http://tutorialsdl.googlecode.com/svn/trunk/Lab3/Lab3/OgreToBtMeshConverter.cpp) :
#include <Ogre.h>
#include <ExampleApplication.h>
#include <btBulletCollisionCommon.h>
class SampleApp : public ExampleApplication
{
public:
// Basic constructor
SampleApp()
{}
protected:
// Just override the mandatory create scene method
void createScene(void) {
mSceneMgr->setSkyBox(true, "Examples/CloudyNoonSkyBox");
Ogre::Light* myLight = mSceneMgr->createLight("Light0");
myLight->setType(Light::LT_POINT);
myLight->setPosition(0, 40, 0);
myLight->setDiffuseColour(1, 1, 1);
myLight->setSpecularColour(1, 1, 1);
Ogre::Entity* entity = mSceneMgr->createEntity("ogre", "ninja.mesh");
mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(entity);
//
// initialize bullets collision detection system
//
btVector3 worldAabbMin(-1000,-1000,-1000);
btVector3 worldAabbMax(1000,1000,1000);
btDefaultCollisionConfiguration* mColConfig;
btCollisionWorld* mColWorld;
btCollisionDispatcher* mDispatcher;
btAxisSweep3* mBroadphase;
mBroadphase = new btAxisSweep3(worldAabbMin, worldAabbMax); // broadphase
mColConfig = new btDefaultCollisionConfiguration();
mDispatcher = new btCollisionDispatcher(mColConfig); // narrowphase pair-wise checking
mColWorld = new btCollisionWorld(mDispatcher, mBroadphase, mColConfig);
//
// Registers every mesh in OGREs scene manager with the
// collision world. You should be adding your environment
// to the scene manager before this call. Your moveable
// character should be created after this call as to avoid
// having his mesh become part of the static level geometry.
//
// All meshes here are placed into group 2 and set to
// collide with group 1. You character should be in group
// 1, and set to collide with group 2. More about contact groups
// in the manual.
btCollisionWorld* colWorld=0;
registerEntityAsCollider(entity,colWorld);
}
void registerEntityAsCollider(Entity* entity, btCollisionWorld* colWorld)
{
// if you wish to do instancing you will have to share one
// btTriangleMesh amongst multiple btBvhTriangleMeshShape
// instances
btTriangleMesh* btMesh = new btTriangleMesh();
MeshPtr mesh = entity->getMesh();
Mesh::SubMeshIterator j = mesh->getSubMeshIterator();
while (j.hasMoreElements()) {
SubMesh* submesh = j.getNext();
int idxStart = submesh->indexData->indexStart;
int nIdx = submesh->indexData->indexCount;
HardwareIndexBuffer* idxBuffer
= submesh->indexData->indexBuffer.get();
HardwareVertexBufferSharedPtr virtBuffer;
VertexDeclaration* virtDecl;
if (submesh->useSharedVertices) {
virtDecl = mesh->sharedVertexData->vertexDeclaration;
assert(mesh->sharedVertexData->vertexBufferBinding->getBufferCount() > 0);
virtBuffer = mesh->sharedVertexData->vertexBufferBinding->getBuffer(0);
} else {
virtDecl = submesh->vertexData->vertexDeclaration;
assert(submesh->vertexData->vertexBufferBinding->getBufferCount() > 0);
virtBuffer = submesh->vertexData->vertexBufferBinding->getBuffer(0);
}
unsigned char* pVert = static_cast<unsigned char*>(virtBuffer->lock(HardwareBuffer::HBL_READ_ONLY));
// need to lock the buffer since vertex data resides on GPU
// and we need synchronization
unsigned short* sindices = NULL;
unsigned long* lindices = NULL;
if (idxBuffer->getType() == HardwareIndexBuffer::IT_16BIT) {
sindices = static_cast<unsigned short*>(idxBuffer->lock(HardwareBuffer::HBL_READ_ONLY));
} else if (idxBuffer->getType() == HardwareIndexBuffer::IT_32BIT) {
lindices = static_cast<unsigned long*>(idxBuffer->lock(HardwareBuffer::HBL_READ_ONLY));
} else {
assert(true == false);
}
const VertexElement* elm = virtDecl->findElementBySemantic(VES_POSITION, 0);
int offset = elm->getOffset();
assert(elm->getType() == VET_FLOAT3);
for (int k = idxStart; k < idxStart + nIdx; k += 3) {
unsigned int indices[3];
btVector3 vertices[3];
if (idxBuffer->getType() == HardwareIndexBuffer::IT_16BIT) {
for (int l = 0; l < 3; ++l) {
indices[l] = sindices[k + l];
}
} else {
for (int l = 0; l < 3; ++l) {
indices[l] = lindices[k + l];
}
}
for (int l = 0; l < 3; ++l) { // for each vertex
Real* posVert = (Real*)(pVert + indices[l] * virtBuffer->getVertexSize() + offset);
for (int m = 0; m < 3; ++m) { // for each vertex component
vertices[l][m] = posVert[m];
}
}
btMesh->addTriangle(vertices[0], vertices[1], vertices[2]);
}
idxBuffer->unlock();
virtBuffer->unlock();
}
btBvhTriangleMeshShape* btMeshShape = new btBvhTriangleMeshShape(btMesh, true, true);
btCollisionObject* btObj = new btCollisionObject();
btObj->setCollisionShape(btMeshShape);
Vector3 pos = entity->getParentSceneNode()->getPosition();
Quaternion orient = entity->getParentSceneNode()->getOrientation();
Vector3 scale = entity->getParentSceneNode()->getScale();
btMeshShape->setLocalScaling(btVector3(scale[0], scale[1], scale[2]));
btMeshShape->setMargin(0.0);
btTransform btTrans;
btTrans.setIdentity();
btTrans.setOrigin(btVector3(pos[0], pos[1], pos[2]));
btTrans.setRotation(btQuaternion(orient[1], orient[2], orient[3], orient[0]));
btObj->setWorldTransform(btTrans);
// the last 2 parameters are bit strings representing group membership
// and the groups which it is allowed to collide with
colWorld->addCollisionObject(btObj, 2, 1);
}
//
// This method will take every entity in your scene and register it as
// a mesh in the btCollisionWorld. NOTE: Be sure to call this function after
// you've added your static entities (environment) to the scene manager but
// before you add your characters.
//
void registerAllEntitiesAsColliders(SceneManager* sceneMgr, btCollisionWorld* colWorld)
{
SceneManager::MovableObjectIterator
i = sceneMgr->getMovableObjectIterator("Entity");
while (i.hasMoreElements()) {
Entity* entity = static_cast<Entity*>(i.getNext());
registerEntityAsCollider(entity, colWorld);
}
}
};
// ----------------------------------------------------------------------------
// Main function, just boots the application object
// ----------------------------------------------------------------------------
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
int main(int argc, char **argv)
#endif
{
// Create application object
SampleApp app;
try
{
app.go();
}
catch( Exception& e )
{
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
std::cerr << "An exception has occured: " << e.getFullDescription();
#endif
}
return 0;
}