I have a 2D node scene graph that I'm trying to 'nest' stencil clipping in.
I was thinking what I could do is when drawing the stencil, increment any pixel it writes to by 1, and keep track of what the current 'layer' is that I'm on.
Then when drawing, only write pixel data to the color buffer if the value of the stencil at that pixel is >= the current layer #.
This is the code I have now. It doesn't quite work. Where am I messing up?
First I call SetupStencilForMask().
Then draw stencil primitives.
Next, call SetupStencilForDraw().
Now draw actual imagery
When done with a layer, call DisableStencil().
Edit: Updated with solution. It doesn't work for individual items on the same layer, but otherwise is fine.
Found a great article on how to actually pull this off, although it's fairly limited.
http://cranialburnout.blogspot.com/2014/03/nesting-and-overlapping-translucent.html
// glClear(GL_STENICL_BIT) at start of each draw frame
static int stencilLayer = 0;
void SetupStencilForMask(void)
{
if (stencilLayer == 0)
glEnable(GL_STENCIL_TEST);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glStencilFunc(GL_LESS, stencilLayer, 0xff);
glStencilOp(GL_INCR, GL_KEEP, GL_KEEP);
glStencilMask(0xff);
if (stencilLayer == 0)
glClear(GL_STENCIL_BUFFER_BIT);
stencilLayer++;
}
void SetupStencilForDraw()
{
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glStencilFunc(GL_EQUAL, stencilLayer, 0xff);
glStencilMask(0x00);
}
void DisableStencil(void)
{
if (--stencilLayer == 0)
glDisable(GL_STENCIL_TEST);
}
I have figured out the way to do this in libgdx. I'm not sure you still need this, but for future reference here is the code:
/**
* Start cropping
*
* #param cropMask
* Mask plane
*/
public void startCropping(Plane cropMask) {
// Check if there is active masking group
if (activeCropMaskGroup == null) {
// Create new one
activeCropMaskGroup = new CropMaskingGroupDescriptor(cropMask);
} else {
// Increase hierarchy level
activeCropMaskGroup.increaseHierachy(cropMask);
}
}
/** End cropping */
public void endCropping() throws IllegalStateException {
// Check if there is active group mask
if (activeCropMaskGroup == null) {
throw new IllegalStateException("Call start cropping before this!");
}
if (activeCropMaskGroup.getHierachy() > 0) {
activeCropMaskGroup.decreaseHierachy();
} else {
// Finish setup of crop data
cropMaskGroups.add(activeCropMaskGroup);
activeCropMaskGroup = null;
}
}
/** Crop registered planes for cropping */
private void cropRender(CropMaskingGroupDescriptor cropMaskGroupDescriptor) {
// Draw mask to stencil buffer
Gdx.gl.glClear(GL20.GL_STENCIL_BUFFER_BIT);
// setup drawing to stencil buffer
Gdx.gl20.glEnable(GL20.GL_STENCIL_TEST);
// Number of registered hierarchy levels
int hierarchyLevels = cropMaskGroupDescriptor.getRegisteredBatch().size();
// Loop trough hierarchy
for (int hierarchyLevel = 0; hierarchyLevel < hierarchyLevels; hierarchyLevel++) {
Gdx.gl20.glStencilFunc(GL20.GL_ALWAYS, 0x1, 0xffffffff);
Gdx.gl20.glStencilOp(GL20.GL_INCR, GL20.GL_INCR, GL20.GL_INCR);
Gdx.gl20.glColorMask(false, false, false, false);
Gdx.gl20.glDepthMask(false);
// Draw mask with decal batch
cropMaskBatch.add(((NativePlane) cropMaskGroupDescriptor.getCroppingMasks().get(hierarchyLevel)).getPlane());
cropMaskBatch.flush();
// fix stencil buffer, enable color buffer
Gdx.gl20.glColorMask(true, true, true, true);
Gdx.gl20.glDepthMask(true);
Gdx.gl20.glStencilOp(GL20.GL_KEEP, GL20.GL_KEEP, GL20.GL_KEEP);
// draw where pattern has been drawn
Gdx.gl20.glStencilFunc(GL20.GL_LEQUAL, hierarchyLevel + 1, 0xffffffff);
// Loop trough registered masked layers and found which one belongs
// to
// current hierarchy level
for (int i = 0; i < cropMaskGroupDescriptor.getMaskedLayers().size(); i++) {
if (cropMaskGroupDescriptor.getMaskedLayers().get(i).getHierarchyId() == hierarchyLevel) {
Plane plane = cropMaskGroupDescriptor.getMaskedLayers().get(i).getMaskedPlane();
cropMaskGroupDescriptor.getRegisteredBatch().get(hierarchyLevel).add(((NativePlane) plane).getPlane());
}
}
cropMaskGroupDescriptor.getRegisteredBatch().get(hierarchyLevel).flush();
}
Gdx.gl20.glDisable(GL20.GL_STENCIL_TEST);
}
And inner class inside renderer module.
/**
* Cropped layer descriptor
*
* #author Veljko Ilkic
*
*/
private class CropMaskLayerDescriptor {
/** Layer that needs to be masked */
private Plane maskedPlane;
/** Hierarchy level in which belongs */
private int hierarchyId = 0;
/** Constructor 1 */
public CropMaskLayerDescriptor(Plane maskedPlane, int hierarchyId) {
this.maskedPlane = maskedPlane;
this.hierarchyId = hierarchyId;
}
public Plane getMaskedPlane() {
return maskedPlane;
}
public int getHierarchyId() {
return hierarchyId;
}
}
/**
* Crop masking group descriptor class
*
* #author Veljko Ilkic
*
*/
private class CropMaskingGroupDescriptor {
/** Crop mask */
private ArrayList<Plane> croppingMasks = new ArrayList<Plane>();
/** Planes that will be masked by crop mask */
private ArrayList<CropMaskLayerDescriptor> maskedLayers = new ArrayList<Renderer.CropMaskLayerDescriptor>();
/** Batch for drawing masked planes */
private ArrayList<DecalBatch> hierarchyBatches = new ArrayList<DecalBatch>();
private int activeHierarchyLayerId = 0;
/** Constructor 1 */
public CropMaskingGroupDescriptor(Plane topLevelCropMask) {
// Create batch for top level hierarchy
hierarchyBatches.add(new DecalBatch(new CameraGroupStrategy(perspectiveCamera)));
// Register top level crop mask
croppingMasks.add(topLevelCropMask);
}
/** Increase hierarchy level of the group */
public void increaseHierachy(Plane hierarchyCropMask) {
activeHierarchyLayerId++;
// Create individual batch for hierarchy level
hierarchyBatches.add(new DecalBatch(new CameraGroupStrategy(perspectiveCamera)));
// Register crop mask for current hierarchy level
croppingMasks.add(hierarchyCropMask);
}
/** Decrease hierarchy group */
public void decreaseHierachy() {
activeHierarchyLayerId--;
}
/** Get current hierarchy level */
public int getHierachy() {
return activeHierarchyLayerId;
}
/** Register plane for masking */
public void registerLayer(Plane maskedPlane) {
hierarchyBatches.get(activeHierarchyLayerId).add(((NativePlane) maskedPlane).getPlane());
maskedLayers.add(new CropMaskLayerDescriptor(maskedPlane, activeHierarchyLayerId));
}
/** Get all registered batched */
public ArrayList<DecalBatch> getRegisteredBatch() {
return hierarchyBatches;
}
/** Get registered cropping masks */
public ArrayList<Plane> getCroppingMasks() {
return croppingMasks;
}
/** Get layer that should be masked */
public ArrayList<CropMaskLayerDescriptor> getMaskedLayers() {
return maskedLayers;
}
/** Dispose */
public void dispose() {
for (int i = 0; i < hierarchyBatches.size(); i++) {
hierarchyBatches.get(i).dispose();
hierarchyBatches.set(i, null);
}
hierarchyBatches.clear();
}
}
Hope this helps.
Related
I am working with a PIC32MX795F512L. With below code I can transmit but cannot receive. How can it be possible I can transmit but I cannot receive? Any suggestions will be appreciated.
Here is the init code:
void CAN1Init(void) {
CAN_BIT_CONFIG canBitConfig;
UINT baudPrescalar;
PORTSetPinsDigitalIn(IOPORT_F, BIT_0);
PORTSetPinsDigitalOut(IOPORT_F, BIT_1);
// ODCFSET = BIT_1;
// change the CAN1 RX register from anlog to digital
// PORTSetPinsDigitalIn(IOPORT_F, BIT_0);
// PORTSetPinsDigitalOut(IOPORT_F, BIT_1);
CANEnableModule(CAN1, TRUE);
// Set the CAN_en pin to low, which is at RC3
mPORTCClearBits(BIT_3);
PORTSetPinsDigitalOut(IOPORT_C, BIT_3);
CANSetOperatingMode(CAN1, CAN_CONFIGURATION);
while (CANGetOperatingMode(CAN1) != CAN_CONFIGURATION);
canBitConfig.phaseSeg2Tq = CAN_BIT_3TQ;
canBitConfig.phaseSeg1Tq = CAN_BIT_3TQ;
canBitConfig.propagationSegTq = CAN_BIT_3TQ;
canBitConfig.phaseSeg2TimeSelect = TRUE;
canBitConfig.sample3Time = TRUE;
canBitConfig.syncJumpWidth = CAN_BIT_2TQ;
// baudPrescalar = CANCalcBitClockPrescalar(&canBitConfig,80000000,250000);
CANSetSpeed(CAN1, & canBitConfig, SYS_FREQ, CAN_BUS_SPEED);
/* Step 3: Assign the buffer area to the
* CAN module.
*/
CANAssignMemoryBuffer(CAN1, CAN1MessageFifoArea, (2 * 8 * 16));
CANConfigureChannelForTx(CAN1, CAN_CHANNEL0, 8, CAN_TX_RTR_DISABLED, CAN_LOW_MEDIUM_PRIORITY);
CANConfigureChannelForRx(CAN1, CAN_CHANNEL1, 8, CAN_RX_FULL_RECEIVE);
//CANConfigureFilter (CAN1, CAN_FILTER0, 0x000, CAN_SID);
//CANConfigureFilterMask (CAN1, CAN_FILTER_MASK0, 0x7FF, CAN_SID, CAN_FILTER_MASK_IDE_TYPE);
// CANLinkFilterToChannel (CAN1, CAN_FILTER0, CAN_FILTER_MASK0, CAN_CHANNEL1);
// CANEnableFilter (CAN1, CAN_FILTER0, TRUE);
CANEnableChannelEvent(CAN1, CAN_CHANNEL1, CAN_RX_CHANNEL_NOT_EMPTY, TRUE);
CANEnableModuleEvent(CAN1, CAN_RX_EVENT, TRUE);
INTSetVectorPriority(INT_CAN_1_VECTOR, INT_PRIORITY_LEVEL_4);
INTSetVectorSubPriority(INT_CAN_1_VECTOR, INT_SUB_PRIORITY_LEVEL_0);
INTEnable(INT_CAN1, INT_ENABLED);
/* Step 7: Switch the CAN mode
* to normal mode. */
CANSetOperatingMode(CAN1, CAN_NORMAL_OPERATION);
mPORTEToggleBits(BIT_6 | BIT_7);
while (CANGetOperatingMode(CAN1) != CAN_NORMAL_OPERATION);
CANSetTimeStampValue(CAN1, 0x00);
printf("CAN BUS is working\n");
}
Edit: main part of the code:
void RxMsgProcess(void)
{
if(isCAN1MsgReceived == FALSE) // This flag to make sure there is an interrupt from receiving a new message, if it's true then there are new packet
{
return;
}
isCAN1MsgReceived = FALSE;
CANRxMessageBuffer * message2;
message2 = CANGetRxMessage(CAN1,CAN_CHANNEL1);
printf(" received\n");
CANUpdateChannel(CAN1, CAN_CHANNEL1);
CANEnableChannelEvent(CAN1, CAN_CHANNEL1, CAN_RX_CHANNEL_NOT_EMPTY, TRUE);
}
void __attribute__((vector(46), interrupt(ipl4), nomips16)) CAN1InterruptHandler(void)
{
/* Check if the source of the interrupt is
* RX_EVENT. This is redundant since only this
* event is enabled in this example but
* this shows one scheme for handling events. */
if((CANGetModuleEvent(CAN1) & CAN_RX_EVENT) != 0)
{
/* Within this, you can check which channel caused the
* event by using the CANGetModuleEvent() function
* which returns a code representing the highest priority
* pending event. */
if(CANGetPendingEventCode(CAN1) == CAN_CHANNEL1_EVENT)
{
CANEnableChannelEvent(CAN1, CAN_CHANNEL1, CAN_RX_CHANNEL_NOT_EMPTY, FALSE);
isCAN1MsgReceived = TRUE;
}
}
INTClearFlag(INT_CAN1);
}
hi so im making a hierarchy sort of structure for a robotic walker to make the number of servos manageable and im trying to create a Limb class that contains a number of servo classes (yes im using the built in servo Library but i want to also tweak the offset,scale ect. of the value for calibration purposes) anyway hear is my code.
the problem is the Limb Class initiator (bottom 4 lines) i usually dont like just straight up asking for the correct line of code and prefer to figure it out but iv tried everything i can think of
PS i apolagise for any crap spelling and thanks
class ServoConfig{
public :
float Offset;
float Scale;
bool Inversed;
Servo ServoV;
ServoConfig (float InOffset, float InScale, bool InInversed,int Pin){
float Offset = InOffset;
float Scale = InScale;
bool Inversed = InInversed;
ServoV.attach(Pin);
}
void WriteToServo(float Angle){
if (Inversed){
ServoV.write((180-Angle)/Scale + Offset);
}
else{
ServoV.write(Angle/Scale + Offset);
}
}
};
class Limb{
ServoConfig Servos[];
Limb (ServoConfig InServos[]){
ServoConfig Servos[] = InServos;
}
};
It's not so easy in C++ and on Arduino it's even harder.
But first you have loads of mistakes in code. For example shadowing class attibutes by local variables:
ServoConfig (float InOffset, float InScale, bool InInversed,int Pin) {
float Offset = InOffset; // this will create new local variable and hides that one in class with the same name
float Scale = InScale; // this too
bool Inversed = InInversed; // and this too
The same is in Limb constructor, but it doesn't work anyways.
And how it can be working? You can use something like this:
#include <Servo.h>
class ServoConfig {
public :
float Offset;
float Scale;
bool Inversed;
Servo ServoV;
ServoConfig (float InOffset, float InScale, bool InInversed,int Pin)
: Offset { InOffset }
, Scale { InScale }
, Inversed { InInversed }
{
ServoV.attach(Pin); // it might have to be attached in setup() as constructors are called before main()
}
void WriteToServo(float Angle){
if (Inversed) {
ServoV.write((180-Angle)/Scale + Offset);
} else {
ServoV.write(Angle/Scale + Offset);
}
}
};
ServoConfig servos[] = {{10,10,0,9},{0,1,0,10}}; // this makes servos of size two and calls constructors
class Limb {
public:
ServoConfig * servos_begin;
ServoConfig * servos_end;
Limb(ServoConfig * beg, ServoConfig * end)
: servos_begin { beg }
, servos_end { end }
{;}
ServoConfig * begin() { return servos_begin; }
ServoConfig * end() { return servos_end; }
size_t size() { return servos_end - servos_begin; }
};
// much better than using sizeof(array)/sizeof(array[0]):
template <class T, size_t size> size_t arraySize(T(&)[size]) { return size; }
// create and construct Limb instance:
Limb limb { servos, servos + arraySize(servos)};
void setup(){
Serial.begin(9600);
}
void loop(){
Serial.println("starting...");
for (ServoConfig & servo : limb) { // this uses begin() and end() methods
servo.WriteToServo(90);
}
// or directly with array[]
for (ServoConfig & servo : servos) {
servo.WriteToServo(40);
}
}
I know that it is possible to write Level-2 MATLAB S-Functionswith variable-sized signals.
Is it also somehow possible to do that in C MEX S-Functions?
My data has a different size at each time step. This requirement originates from a compressing block which gets a fixed size signal (2D) as its input. However the output signal (1D / Vector) changes its size at every mdlOutput().
The comments of the question already answered it:
Yes it is possible!
Here my example:
// Required S-Function header
#define S_FUNCTION_LEVEL 2
#define S_FUNCTION_NAME sfunc_varsignal
#include "simstruc.h"
enum {INPUT_PORT = 0, NUM_INPUT_PORTS};
enum {OUTPUT_PORT = 0, NUM_OUPUT_PORTS};
/**
* "Specify the number of inputs, outputs, states, parameters, and other
* characteristics of the C MEX S-function"
*/
static void mdlInitializeSizes(SimStruct* S)
{
boolean_T boolret;
int_T intret;
// Parameter
ssSetNumSFcnParams(S, 0);
if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S))
{
return; // Parameter mismatch will be reported by Simulink
}
// Input port
boolret = ssSetNumInputPorts(S, NUM_INPUT_PORTS);
if (boolret == 0)
{
return;
}
ssSetInputPortDirectFeedThrough(S, INPUT_PORT, 1);
intret = ssSetInputPortDimensionInfo(S, INPUT_PORT, DYNAMIC_DIMENSION);
if (intret == 0)
{
ssWarning(S, "Input dimensions could not be set.");
}
_ssSetInputPortNumDimensions(S, INPUT_PORT, 1);
// Output port
boolret = ssSetNumOutputPorts(S, NUM_OUPUT_PORTS);
if (boolret == 0)
{
return;
}
intret = ssSetOutputPortDimensionInfo(S, OUTPUT_PORT, DYNAMIC_DIMENSION);
if (intret == 0)
{
ssWarning(S, "Output dimensions could not be set.");
}
_ssSetOutputPortNumDimensions(S, OUTPUT_PORT, 1);
// Sample Times
ssSetNumSampleTimes(S, 1);
// Dimension Modes of the Ports
ssSetInputPortDimensionsMode(S, INPUT_PORT, INHERIT_DIMS_MODE);
ssSetOutputPortDimensionsMode(S, OUTPUT_PORT, INHERIT_DIMS_MODE);
// This is required for any kind of variable size signal:
ssSetInputPortRequiredContiguous(S, INPUT_PORT, true);
ssSetOptions(S, 0);
// Note: In the doc of ssSetOutputPortWidth it is wriiten:
// "If the width is dynamically sized, the S-function must provide
// mdlSetOutputPortDimensionInfo and mdlSetDefaultPortDimensionInfo
// methods to enable the signal dimensions to be set correctly
// during signal propagation."
// However in the example sfun_varsize_concat1D this methods are
// not present. The function _ssSetOutputPortNumDimensions() may be sufficient
// This usgae of this function is copied from the example sfcndemo_varsize
}
#if defined(MATLAB_MEX_FILE)
/**
* "Set the width of an input port that accepts 1-D (vector) signals"
*/
#define MDL_SET_INPUT_PORT_WIDTH
static void mdlSetInputPortWidth(SimStruct* S, int_T port, int_T width)
{
// Set to the sugessted width (e.g. the output width
// from the connected block)
ssSetInputPortWidth(S, port, width);
// Check if the setting was sucessful
if (ssGetInputPortWidth(S, INPUT_PORT) != DYNAMICALLY_SIZED)
{
ssSetOutputPortWidth(S, OUTPUT_PORT, width);
}
return;
}
/**
* "Set the width of an output port that outputs 1-D (vector) signals"
*/
#define MDL_SET_OUTPUT_PORT_WIDTH
static void mdlSetOutputPortWidth(SimStruct* S, int_T port, int_T width)
{
// Nothing here, but its required since the output port is set as
// dynamically sized. But its size is set in mdlSetInputPortWidth()
UNUSED_ARG(S);
UNUSED_ARG(port);
UNUSED_ARG(width);
return;
}
#endif //defined(MATLAB_MEX_FILE)
/**
* "Specify the sample rates at which this C MEX S-function operates"
*/
static void mdlInitializeSampleTimes(SimStruct* S)
{
ssSetSampleTime(S, 0, INHERITED_SAMPLE_TIME);
ssSetOffsetTime(S, 0, 0.0);
ssSetModelReferenceSampleTimeDefaultInheritance(S);
}
/**
* "Compute the signals that this block emits."
*/
static void mdlOutputs(SimStruct* S, int_T tid)
{
UNUSED_ARG(tid);
const real_T* insignal = ssGetInputPortRealSignal(S, INPUT_PORT);
auto width = static_cast<const int>(insignal[0]);
// This function does the trick:
ssSetCurrentOutputPortDimensions(S, OUTPUT_PORT, 0, width);
// newWidth should be width
int_T newWidth = ssGetCurrentOutputPortDimensions(S, OUTPUT_PORT, 0 /* dimension ID */);
real_T* outsignal = ssGetOutputPortRealSignal(S, OUTPUT_PORT);
for (int i = 0; i < newWidth; i++)
{
*outsignal++ = i+1;
}
}
/**
* "Perform any actions required at termination of the simulation"
*/
static void mdlTerminate(SimStruct* S)
{
UNUSED_ARG(S);
}
// Required S-function trailer
#ifdef MATLAB_MEX_FILE /* Is this file being compiled as a MEX-file? */
#include "simulink.c" /* MEX-file interface mechanism */
#else
#include "cg_sfun.h" /* Code generation registration function */
#endif
I wrote a program in c++ using Windows forms. I use two Forms. The first form only contains a button. When it is pressed, a second form opens. This form contains a panel where a simple OpenGL simulation is played (rotated with the help of a timer provided by windows forms). The second form can be closed and opend again by pressing the botton in the first Form. The more often this is done, the slower the 3D-OpenGL-object rotates. After doing this for about 6 times the 3D-OpenGL-object starts to flicker totally crazy. I think it has to do with the fact, that the OpenGL-Object I construct is not destroyed properly and at a certain point the memory is full (in a more complicated version of the project it was flickering between the current 3D-object and a 3D object that should have been destroyed after the window was closed).
Here is a video of the Problem.
here is the code of OpenGL:
namespace OpenGLForm
{
public ref class COpenGL: public System::Windows::Forms::NativeWindow
{
public:
// Position/Orientation of 3D Mesh in Mesh-Viewer Window
float meshPos_x;
float meshPos_y;
float meshPos_z;
float meshOri_x;
float meshOri_y;
float meshOri_z;
COpenGL(System::Windows::Forms::Panel ^ parentForm, GLsizei iWidth, GLsizei iHeight)
{
// initialize all parameter / set pointers (for pointers of type MAT)
meshPos_x = 0.0;
meshPos_y = 0.0;
meshPos_z = -2.0;
meshOri_x = -63.0;
meshOri_y = 0.0;
meshOri_z = 0.0;
CreateParams^ cp = gcnew CreateParams;
m_hDC = GetDC((HWND)parentForm->Handle.ToPointer());
System::String^ filename = "C:/Advantech/Desktop/Const.txt";
System::IO::StreamWriter^ csvWriter = gcnew System::IO::StreamWriter(filename, false, System::Text::Encoding::UTF8);
csvWriter->Write("Const");
csvWriter->Close();
if(m_hDC)
{
MySetPixelFormat(m_hDC);
ReSizeGLScene(iWidth, iHeight);
InitGL();
}
}
//custom function for transformations
System::Void Transform(float xTrans, float yTrans, float zTrans, float xRot, float yRot, float zRot)
{
//translate object
glTranslatef(xTrans, yTrans, zTrans);
//rotate along x-axis
glRotatef(xRot,1.0f,0.0f,0.0f);
//rotate along y-axis
glRotatef(yRot,0.0f,1.0f,0.0f);
//rotate along z-axis
glRotatef(zRot,0.0f,0.0f,1.0f);
}
System::Void Render(System::Void)
{
// Initial Settings
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear screen and depth buffer
glLoadIdentity();
meshOri_z = meshOri_z + 1;
// Set position and orientation of 3D mesh
Transform( meshPos_x,
meshPos_y,
meshPos_z,
meshOri_x,
meshOri_y,
meshOri_z );
glScalef( 0.05, 0.05, 0.05 );
int meshSize = 200;
// create 3D mesh Toplayer
for (int x = 1; x < meshSize; x++) {
for (int z = 1; z < meshSize; z++) {
glBegin(GL_QUADS);
int dm = 1;
glColor3f(dm,dm,dm);
glVertex3f( x, z, dm );
glVertex3f( (x+1), z, dm );
glVertex3f( (x+1), (z+1), dm );
glVertex3f( x, (z+1), dm );
glEnd();
}
}
}
System::Void SwapOpenGLBuffers(System::Void)
{
SwapBuffers(m_hDC) ;
}
private:
HDC m_hDC;
HGLRC m_hglrc;
protected:
~COpenGL(System::Void)
{
System::String^ filename = "C:/Advantech/Desktop/Dest.txt";
System::IO::StreamWriter^ csvWriter = gcnew System::IO::StreamWriter(filename, false, System::Text::Encoding::UTF8);
csvWriter->Write("Dest");
csvWriter->Close();
wglDeleteContext(m_hglrc);
DeleteDC(m_hDC);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
this->DestroyHandle();
}
GLint MySetPixelFormat(HDC hdc)
{
static PIXELFORMATDESCRIPTOR pfd= // pfd Tells Windows How We Want Things To Be
{
sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
1, // Version Number
PFD_DRAW_TO_WINDOW | // Format Must Support Window
PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
PFD_DOUBLEBUFFER, // Must Support Double Buffering
PFD_TYPE_RGBA, // Request An RGBA Format
16, // Select Our Color Depth
0, 0, 0, 0, 0, 0, // Color Bits Ignored
0, // No Alpha Buffer
0, // Shift Bit Ignored
0, // No Accumulation Buffer
0, 0, 0, 0, // Accumulation Bits Ignored
16, // 16Bit Z-Buffer (Depth Buffer)
0, // No Stencil Buffer
0, // No Auxiliary Buffer
PFD_MAIN_PLANE, // Main Drawing Layer
0, // Reserved
0, 0, 0 // Layer Masks Ignored
};
GLint iPixelFormat;
// get the device context's best, available pixel format match
if((iPixelFormat = ChoosePixelFormat(hdc, &pfd)) == 0)
{
MessageBox::Show("ChoosePixelFormat Failed");
return 0;
}
// make that match the device context's current pixel format
if(SetPixelFormat(hdc, iPixelFormat, &pfd) == FALSE)
{
MessageBox::Show("SetPixelFormat Failed");
return 0;
}
if((m_hglrc = wglCreateContext(m_hDC)) == NULL)
{
MessageBox::Show("wglCreateContext Failed");
return 0;
}
if((wglMakeCurrent(m_hDC, m_hglrc)) == NULL)
{
MessageBox::Show("wglMakeCurrent Failed");
return 0;
}
return 1;
}
bool InitGL(GLvoid) // All setup for opengl goes here
{
glShadeModel(GL_SMOOTH); // Enable smooth shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black background
glClearDepth(1.0f); // Depth buffer setup
glEnable(GL_DEPTH_TEST); // Enables depth testing
glDepthFunc(GL_LEQUAL); // The type of depth testing to do
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really nice perspective calculations
return TRUE; // Initialisation went ok
}
GLvoid ReSizeGLScene(GLsizei width, GLsizei height) // Resize and initialise the gl window
{
if (height==0) // Prevent A Divide By Zero By
{
height=1; // Making Height Equal One
}
glViewport(0,0,width,height); // Reset The Current Viewport
glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix
// Calculate The Aspect Ratio Of The Window
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity(); // Reset The Modelview Matrix
}
System::Void detectBlack(){
}
};
}
the first form only contains a button to open the second form
private: System::Void button2_Click(System::Object^ sender, System::EventArgs^ e) {
Form1^ freaker = gcnew Form1();
freaker->ShowDialog();
}
and here is the code of the second form:
private: System::Void Form1_Load(System::Object^ sender, System::EventArgs^ e) {
}
void Form1_Closing( Object^ /*sender*/, System::ComponentModel::CancelEventArgs^ e )
{
this->OpenGL->~COpenGL();
}
//Time tick for play button option
private: System::Void timer1_Tick(System::Object^ sender, System::EventArgs^ e){
UNREFERENCED_PARAMETER(sender);
UNREFERENCED_PARAMETER(e);
OpenGL->Render();
OpenGL->SwapOpenGLBuffers();
}
After one week of searching and trying around here the answer:
I found a class to destroy openGL objects in Windows (wgl). This class alone did not solve the problem. I had to call all the commands, then switch buffers by calling SwapBuffers(m_hDC); and call all the commands again. Later on I recognized that it is enough only to call the commands g_hDC=NULL; and g_hWnd=NULL;. So this is how my destructor looks like now:
~COpenGL(System::Void){
if (g_bFullscreen) // Are We In Fullscreen Mode?
{
ChangeDisplaySettings(NULL,0); // If So Switch Back To The Desktop
ShowCursor(TRUE); // Show Mouse Pointer
}
if (g_hRC) // Do We Have A Rendering Context?
{
if (!wglMakeCurrent(NULL,NULL)) // Are We Able To Release The DC And RC Contexts?
{
MessageBox(NULL,TEXT("Release Of DC And RC Failed."),TEXT("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
}
if (!wglDeleteContext(g_hRC)) // Are We Able To Delete The RC?
{
MessageBox(NULL,TEXT("Release Rendering Context Failed."),TEXT("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
}
g_hRC=NULL; // Set RC To NULL
}
if (g_hDC && !ReleaseDC(g_hWnd,g_hDC)) // Are We Able To Release The DC
{
MessageBox(NULL,TEXT("Release Device Context Failed."),TEXT("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
g_hDC=NULL; // Set DC To NULL
}
if (g_hWnd && !DestroyWindow(g_hWnd)) // Are We Able To Destroy The Window?
{
MessageBox(NULL,TEXT("Could Not Release hWnd."),TEXT("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
g_hWnd=NULL; // Set hWnd To NULL
}
if (!UnregisterClass(TEXT("OpenGL"),g_hInstance)) // Are We Able To Unregister Class
{
MessageBox(NULL,TEXT("Could Not Unregister Class."),TEXT("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
g_hInstance=NULL; // Set hInstance To NULL
}
SwapBuffers(g_hDC);
g_hDC=NULL;
g_hWnd=NULL;
}
I have made a simple program that displays video from a webcam and can detect motion from the feed, but I am having a problem understanding how I go about recording from the webcam when motion is detected. I have searched on the Aforge.Net site but I am finding it hard to understand what I need to do. When motion is detected, I want to start recording to a pre determined destination and when no motion is detected, I want to continue recording for a set period of time and then stop. This is part of my program that I have so far...
Please can you help to explain it to me and let me know if I need to supply more info or code. Thanks
$// Open video source
private void OpenVideoSource(IVideoSource source)
{
// set busy cursor
//this.Cursor = Cursors.WaitCursor;
// close previous video source
CloseVideoSource();
//motionDetectionType = 1;
//SetMotionDetectionAlgorithm(new TwoFramesDifferenceDetector());
//motionProcessingType = 1;
//SetMotionProcessingAlgorithm(new MotionAreaHighlighting());
// start new video source
videoSourcePlayer.VideoSource = new AsyncVideoSource(source);
videoSourcePlayer.NewFrame +=new VideoSourcePlayer.NewFrameHandler(videoSourcePlayer_NewFrame);
//videoSourcePlayer.DesiredFrameRate = 30;
//webcam's default frame rate will be used instead of above code that has an error
// create new video file
writer.Open("test.avi", width, height, 25, VideoCodec.MPEG4);
// create a bitmap to save into the video file
Bitmap image = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
// write 1000 video frames
for (int i = 0; i < 1000; i++)
{
image.SetPixel(i % width, i % height, System.Drawing.Color.Red);
writer.WriteVideoFrame(image);
}
writer.Close();
try
{
videoSourcePlayer.Start();
//motionAlarmLevel = sldMotionSensitivity.Value / 100;
}
catch (Exception x)
{
System.Windows.MessageBox.Show(x.ToString());
}
//videoSource.DesiredFrameSize = new System.Drawing.Size(800,600);
videoSourcePlayer.BorderColor = System.Drawing.Color.Blue;
// reset statistics
statIndex = statReady = 0;
// start timers
clock.Start();
//alarm.Start();
videoSource = source;
//this.Cursor = Cursors.Default;
}
// Close current video source
private void CloseVideoSource()
{
// set busy cursor
//this.Cursor = Cursors.WaitCursor;
// stop current video source
videoSourcePlayer.SignalToStop();
// wait 2 seconds until camera stops
for (int i = 0; (i < 50) && (videoSourcePlayer.IsRunning); i++)
{
Thread.Sleep(100);
}
if (videoSourcePlayer.IsRunning)
videoSourcePlayer.Stop();
// stop timers
clock.Stop();
//alarm.Stop();
motionHistory.Clear();
// reset motion detector
if (detector != null)
detector.Reset();
//videoSourcePlayer.BorderColor = System.Drawing.Color.Red;
//this.Cursor = Cursors.Default;
}
// New frame received by the player
void videoSourcePlayer_NewFrame(object sender, ref Bitmap image)
{
lock (this)
{
if (detector != null)
{
//motion detected
if (detector.ProcessFrame(image) > motionAlarmLevel)
{
//float motionLevel = detector.ProcessFrame(image);
videoSourcePlayer.BorderColor = System.Drawing.Color.Red;
Dispatcher.BeginInvoke(new ThreadStart(delegate { lblMotionDetected.Content = "Motion Detected"; }));
//lblMotionDetected.Content = "Motion Detected";
//flash = (int)(2 * (1000 / alarm.Interval));
}
// no motion detected
if (detector.ProcessFrame(image) < motionAlarmLevel)
{
videoSourcePlayer.BorderColor = System.Drawing.Color.Black;
Dispatcher.BeginInvoke(new ThreadStart(delegate { lblMotionDetected.Content = "No Motion Detected"; }));
}
// if (motionLevel > motionAlarmLevel)
// {
// // flash for 2 seconds
// timer.Start();
// }
}
}
}
There's an open source project called ispy - http://www.ispyconnect.com that does exactly that. Source is available for download.