Performance issue while using PictureBox - winforms

I'm working on an application in Visual Studio 2010 and I'm coding in C++/CLI.
In my previous questions I had issue with data series from a serial port. Now it seems ok and now I'm trying to plot them.
I don't want to use Chart, so I would like to use handmade functions that use the class Graphics. In order to test my code, I created two arrays: the first one is filled with values coming from a Gaussian. The second one is filled with random numbers.
When I plot the values, I would like to see my plot growing and updating just like an oscilloscope. The second Do_Plot manages to "remove point" plotting them by the BackColor.
All the code works as intended but I'm experiencing problem with performances. If I run the code on my Pc, my series is plotted every 500/700 ms.
Sometimes it slows down to 1500ms and then it comes back faster.
I tried to run the code on my coworkers' Pc and I noticed the series is plotted every 170ms on the first one, whereas the series is plotted every 950ms on the second one.
This is the code:
System::Void Form1::button1_Click(System::Object^ sender, System::EventArgs^ e) {
button1->Enabled = false;
array<float,1>^ Gauss = gcnew array<float,1>(1001);
array<float,1>^ Rumore = gcnew array<float,1>(1001);
/*Some useful variables*/
Random^ generatore = gcnew Random;
float a = safe_cast<float>(Math::Round(5/(SIGMA*Math::Sqrt(2*PI)), 2));
float b = safe_cast<float>(2*(SIGMA*SIGMA));
/*Start */
float portante;
float r;
float s;
int convX =1000/1000;
int convY =500/2;
/*time variables */
int bias = 50;
int dif =600;
/*Gap between drawing and removing*/
int k = 3;
int e1 = 0;
for ( ; ; ) {
/*Start*/
clock_t Start = clock();
if(textBox1->Text==""){
portn = 5;
}
else
portn = float::Parse(textBox1->Text);
/*temp variables to go out the for cycle */
portante = portn;
r = rand;
s = sig;
/ckeck state is OK */
check = 0;
for(int i = 1; i<=1000; i++) {
Gauss[i] = safe_cast<float>(Math::Round( a*s*Math::Exp(-Math::Pow(((0.01*1*(i))-portante), 2)/b), 2));
Rumore[i] = safe_cast<float>(Math::Round(r*generatore->NextDouble(), 2));
bool clipSup = ClipSup(2, Gauss[i]+Rumore[i]);
if(clipSup==true) {
Gauss[i] = 1.99f;
Rumore[i] = 0;
}
Do_Plot(g, disegna, i-1, Gauss[i-1]+Rumore[i-1], i, Gauss[i]+Rumore[i], convX, convY);
e1 =(k+i)%1000;
Do_Plot(g, rimuovi, e1, Gauss[e1]+Rumore[e1], e1+1, Gauss[e1+1]+Rumore[e1+1], convX, convY);
/*Ckeck if go out for cycle*/
if(check == CODE_1 ) {
portante = portn;
break;
}
if(check == CODE_2 ) {
r = rand;
break;
}
if(check == CODE_3 ) {
s = sig;
break;
}
}
clock_t Stop = clock();
int Diff = Stop-Start;
label8->Text = Convert::ToString(Diff);
int tempDiff = (Stop-Start)+bias;
if(tempDiff>dif)
{
//Do_Axes(g); /*Do Axes*/
//Do_Grid(g); /*Do Grid */
Application::DoEvents();
dif = 600;
bias = 0;
}
else
bias +=50; //Else bias grows
}
}
Where Do_Plot is:
void Do_Plot(Graphics^ g, Pen^ penna, int Xi, float Yi, int Xf, float Yf, int convX, int convY) {
g->DrawLine(penna, (convX*Xi+50), safe_cast<int>(500-(Yi*convY)+50),
(convX*Xf+50), safe_cast<int>(500-(Yf*convY)+50));
}
I have declared Graphics^ g here:
public ref class Form1 : public System::Windows::Forms::Form
{
Graphics^ g;
public:
Form1(void)
{
InitializeComponent();
//
//TODO: aggiungere qui il codice del costruttore.
//
g = pictureBox1->CreateGraphics();
}
Onestly I don't know why my code works so differently when it runs on another Pc. I think the problem is g = pictureBox1->CreateGraphics(); but I'm just doing some hypothesis. Any kind of help would be really appreciated cause I'm stuck on this one since the previous week!!
Thanks a lot!
Emiliano

I am going to give you the code in c/c++. Will then find how to do it in c++/cli
First initialize the objects we will use (begining of button_click):
RECT rt = {0, 0, 1200, 600};
HBITMAP hBitmap = NULL;
HPEN hLinePen = NULL;
HDC hdcPctrBox = NULL, hdc = NULL, hdcMemTempImage = NULL;
HBRUSH hBrush = NULL;
POINT arrayPnt[1000]; //array of points
hdc = CreateIC(TEXT("DISPLAY"), NULL, NULL, NULL);
hdcPctrBox = GetWindowDC(hwndPctrBox); //hwndPctrBox is the handle of picturebox
hdcMemTempImage = CreateCompatibleDC(hdc);
hBitmap = CreateCompatibleBitmap(hdc, 1200, 600);
SelectObject(hdcMemTempImage, hBitmap);
hLinePen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0)); //width of pen = 1,and color (255, 0, 0)
SelectObject(hdcMemTempImage, hLinePen);
hBrush = CreateSolidBrush(RGB(100, 100, 255)); //color of picturebox
Then:
for ( ; ; ) {
/*Start*/
clock_t Start = clock();
FillRect(hdcMemTempImage, &rt, hBrush); //clear the hdcMemTempImage with the picturebox color
//your code continues...
In the for(int i = 1; i<=1000; i++) add one point at a time:
arrayPnt[i - 1].x = X; //calculate X
arrayPnt[i - 1].x = Y; ////calculate Y
And finaly we draw it, after the for loop and before the clock_t Stop (we dont need the Do_Plot()):
Polyline(hdcMemTempImage, &arrayPnt, 1000);
BitBlt(hdcPctrBox, 0, 0, 1200, 600, hdcMemTempImage, 0, 0, SRCCOPY);
clock_t Stop = clock();
//your code continues...
EDIT: use your original code(you dont need rt, hBitmap, hBrush, hdcMemTempImage, arrayPnt and hdc) and instead of calling Do_Plot() add this code:
//create two pens, one with the color you want hLinePen, and another with the color of picturebox hLinePenErase
//inside for(int i = 1; i<=1000; i++)
(some code...)
if(clipSup==true) {
Gauss[i] = 1.99f;
Rumore[i] = 0;
}
SelectObject(hdcPctrBox, hLinePen); //the pen to draw the line
MoveToEx(hdcPctrBox, xStart, yStart, NULL); //start point of line
LineTo(hdcPctrBox, xEnd, yEnd); //end point of line
SelectObject(hdcPctrBox, hLinePenErase); //the pen to erase the line
MoveToEx(hdcPctrBox, xStartErase, yStartErase, NULL); //start point of line to erase
LineTo(hdcPctrBox, xEndErase, yEndErase); //end point of line to erase
(code continues...)
To delete your resources:
HPEN hLinePen = NULL, hLinePenErase = NULL, originalPen = NULL;
HDC hdcPctrBox = NULL;
hdcPctrBox = GetWindowDC(hwndPctrBox); //hwndPctrBox is the handle of picturebox
originalPen = SelectObject(hdcPctrBox, GetStockObject(DC_PEN));
//create the two pens
//in the end release resources
SelectObject(hdcPctrBox, originalPen);
DeleteObject(hLinePen);
DeleteObject(hLinePenErase);
ReleaseDC(hwndPctrBox, hdcPctrBox);
valter

I suggest to implement your own painting class. Derive your own class from "Panel" or "UserControl" and do the following in the constructor, which activates double buffering and optimized drawing:
public ref class MyPaintControl : public System::Windows::Forms::UserControl
{
public:
MyPaintControl()
{
this->SetStyle(System::Windows::Forms::ControlStyles::AllPaintingInWmPaint, true);
this->SetStyle(System::Windows::Forms::ControlStyles::DoubleBuffer, true);
this->SetStyle(System::Windows::Forms::ControlStyles::ResizeRedraw, true);
this->SetStyle(System::Windows::Forms::ControlStyles::UserPaint, true);
}
// And then implement your painting in OnPaint:
protected:
virtual void OnPaint(PaintEventArgs^ e)
{
// Do painting...
System::Drawing::Brush^ br = gcnew System::Drawing::SolidBrush(this->BackColor);
e->Graphics->FillRectangle(br, this->ClientRectangle);
delete br;
// Do other paintings...
}
// This function might be called if new data arrived...
public:
void UpdateArea(int daten) // pass data here, if you want...
{
// Store the data in a member variable...
// force a redraw:
this->InvalidateRect(); // this will force a "OnPaint"
}
}
Then embedd this control in your UI. This should improve your painting very much!
Also this works, even if you move or resize your window. Be aware, that painting should always be done in "OnPaint"!

I would like to update the state of my coding.
I used the method posted by Jochen. It is very fast but it does not suit my application or maybe I'm not able to adapt it. What I need to do, is to update constantly my plot. At time t0, I should draw a line. At time t1, when I store a new line, I should draw the new line and add this to the previous one. The plot must be "alive". I tried to derive a panel class and override the OnPaintevent but my plot refreshing only if all lines are stored and displayed.

Related

Drawing a figure from an array of coordinates with C and SDL

I am trying to draw a figure in C, and I have succeded in doing that, but I'm wondering if the way I'm doing it is making it hard for me to what I want to do next (making the figure move/bounce).
I have made a for loop in main that iterates through an array of coordinates which then again call a function that draws lines between them and fills it with color. What I'm wondering about is if this for loop is the best way to do this?
I have made this for loop in main:
for(i = 0; i < SPHERE_NUMTRIANGLES; i++){
object = CreateObject(screen,&sphere_model[i],SPHERE_NUMTRIANGLES);
object->model->scale = 0.1f;
DrawObject(object);
}
The sphere_model im trying to draw contains of many coordinates on the form:
#define SPHERE_NUMTRIANGLES 478
triangle_t sphere_model[] = {
{
.x1=-1,
.y1=-500,
.x2=-1,
.y2=-489,
.x3=-1,
.y3=-500,
.fillcolor=0xeeeeee,
.scale=1.0
},
The CreateObject gets the model from the for loop
// Create new object
object_t *CreateObject(SDL_Surface *screen, triangle_t *model, int numtriangles)
{
object_t *object;
object = NULL;
object = malloc(sizeof(object_t));
object->model = malloc(sizeof(triangle_t) * numtriangles);
object->screen = screen;
object->ttl;
object->speedx = 0;
object->speedy = 1;
object->model = model;
object->model->scale;
object->model->tx = 100;
object->model->ty = 100;
return object;
}
and finally the DrawObject just calls a function that draws the triangles
void DrawObject(object_t *object)
{
DrawTriangle(object->screen,object->model);
}
The sphere_model is in sphere_data.h and the CreateObject function is in triangle.c
I'm supposed to create multiple figures and add the created figures to a list after this, but I'm currently trying to just make one. (This is homework, but I'm hoping I can get some help here, I'm struggling a bit)
...hard for me to what I want to do next (making the figure move/bounce).
What i see is that you allocate objects, draw them and then forget them (I do not see you deallocate the memory). Then, if you want to draw the model again at a different place, you will have to go through the loop again, creating objects, drawing them (and forgetting them).
Maybe it would be better to remember the objects created so you can later just change their coordinates before redrawing them. As an example:
typedef struct LIST {
struct LIST *next;
object_t *object;
};
struct LIST *pObjectList, *pList;
// create objects, draw them and save in list
pObjectList= pList= calloc(1,sizeof(struct LIST));
for(i = 0; i < SPHERE_NUMTRIANGLES; i++){
object = CreateObject(screen,&sphere_model[i],SPHERE_NUMTRIANGLES);
object->model->scale = 0.1f;
DrawObject(object);
pList->object= object;
pList= pList->next= calloc(1,sizeof(struct LIST));
}
// offset the model with 50 pixels
pList= pObjectList;
while (pList->object) {
pList->object.x1 += 50; pList->object.y1 += 50;
pList->object.x2 += 50; pList->object.y2 += 50;
pList->object.x3 += 50; pList->object.y3 += 50;
pList= pList->next;
}
// redraw
pList= pObjectList;
for(i = 0; i < SPHERE_NUMTRIANGLES; i++, pList= pList->next)
{
DrawObject(pList->object);
}

Unity array of colors prevent same value

I'm trying to generate two random colors from a single array which are supposed not to be same. One of the colors is the bg color of the label, the other one is the text color of the text on top of it. But curiously i fail. Here is the code:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class ColorText : MonoBehaviour {
public GUISkin mySkin;
public GameObject obj;
private Color clr;
private Color txtClr;
private string clrName;
Color[] colorList = new Color[13]{
new Color(0,0,255,255), // mavi
new Color(165,42,42,255), // kahverengi
new Color(192,192,192,255), // gri (192,192,192 gümüş)
new Color(0,128,0,255), // yeşil
new Color(128,0,0,255), // bordo
new Color(255,165,0,255), // turuncu
new Color(255,192,203,255), // pembe
new Color(128,0,128,255), // mor
new Color(255,0,0,255), // kırmızı
new Color(64,224,208,255), // turkuaz
new Color(255,255,0,255), // sarı
new Color(255,255,255,255), // beyaz
new Color(0,0,0,255), // siyah
};
string[] colorNames = new string[13]{
"Mavi",
"Kahverengi",
"Gri", // gri (192,192,192 gümüş)
"Yeşil", // yeşil
"Bordo", // bordo
"Turuncu", // turuncu
"Pembe", // pembe
"Mor", // mor
"Kırmızı", // kırmızı
"Turkuaz", // turkuaz
"Sarı", // sarı
"Beyaz", // beyaz
"Siyah", // siyah
};
// Use this for initialization
void Start () {
InvokeRepeating ("changeColors", 0, 1f);
}
void changeColors(){
int a, b;
a = (int)Random.Range (0, colorList.Length);
b = (int)Random.Range (0, colorList.Length);
if (a == b) {
do{
a = (int)Random.Range (0, colorList.Length);
b = (int)Random.Range (0, colorList.Length);
}while(a == b);
clr = colorList [a];
txtClr = colorList [b];
clrName = colorNames [Random.Range (0, colorNames.Length)];
} else {
clr = colorList [a];
txtClr = colorList [b];
clrName = colorNames [Random.Range (0, colorNames.Length)];
}
}
// Update is called once per frame
void Update () {
}
void OnGUI() {
GUI.skin = mySkin;
mySkin.box.fontStyle = FontStyle.Bold;
mySkin.box.normal.textColor = txtClr;
//GUI.backgroundColor = Color.blue;
Texture2D texture = new Texture2D(1, 1);
//Set new texture as background
mySkin.box.normal.background = texture;
//Set the texture color
texture.SetPixel(1,1,clr);
// Apply all SetPixel calls
texture.Apply();
/*float scalex = (float)(Screen.width) / 480.0f;
float scaley = (float)(Screen.height) / 800.0f;
GUI.matrix = Matrix4x4.TRS(new Vector3(0, 0, 0), Quaternion.identity, new Vector3(scalex, scaley, 1));*/
GUI.Box(new Rect(Screen.width/2 - 400,10,800,200), clrName, "box");
//GUI.Label(new Rect(Screen.width/2, 15, 100, 20), "Hello World!");
}
}
Any spotted point of i've been missing? Thanks for your help in advance.
Edit: I checked the indices to compare. They aren't same.
I have a slightly less efficient way for you to do this. First clone your array of colors to a temporary list that you can change however you want. Then remove the index of the first random color. Here is an example:
void changeColors()
{
List<Color> tempColors = new List<Color>(colorList);
// Get the first random index.
int a = (int)Random.Range (0, tempColors.Length);
// Assign the colour.
clr = tempColors[a];
// Remove the colour from the list so that it is impossible to select the same again.
tempColors.RemoveAt(a);
// Get second index.
int b = (int)Random.Range (0, tempColors.Length);
// Assign second colour.
txtClr = tempColors[b];
}
I hope this can help you.
EDIT:
If the problem turns out to be something else I think a code cleanup is appropriate here. Just to show you a different way of writing:
void changeColors(){
int a,b;
a = b = 0;
while (a == b)
{
a = (int)Random.Range (0, colorList.Length);
b = (int)Random.Range (0, colorList.Length);
}
clr = colorList [a];
txtClr = colorList [b];
clrName = colorNames [Random.Range (0, colorNames.Length)];
}
This should do exactly the same as your current code if I'm not mistaken.
Why did you putted it in invokerepeating if you only need two colors only one time and as a side note for invokerepeating start time don't put zero if you want it to start right away put a small value in start time
void Start () {
Changecolors();
}
"Color uses float values between 0 and 1, Color32 uses byte values between 0 and 255.
http://docs.unity3d.com/ScriptReference/Color-ctor.html
http://docs.unity3d.com/ScriptReference/Color32.html
Answer
alucardj solved it.

OpenGL in Windows Forms (c++) - Buffer overflows?

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;
}

problems with old c code with new ncurses version (ldat struct)

I have a problem with some code using curses after upgrading to a new server and thus also new software like libs, headers and such.
The problem is the use of the ldat struct fields "firstchar", "lastchar" and "text" which in the the newer versions of curses.h is hidden in the curses.priv.h and therefore they are not resolved.
I could really use some pointers as to how I might be able to resolve these issues.
The code below indicates the use of the struct fields, but it just a part of the complete code as it several thousand lines...
If there is need for additional code I can add this.
I might also add that I have not made this program myself, I'm just responsible for making it work with our new server...
int
update_window(changed, dw, sw, win_shared)
bool *changed;
WINDOW *dw; /* Destination window */
window_t *sw; /* Source window */
bool win_shared;
{
int y, x;
int yind, nx, first, last;
chtype *pd, *ps; /* pd = pointer destination, ps = pointer source */
int nscrolls; /* Number of scrolls to make */
if(! sw->changed) {
*changed = FALSE;
return(0);
}
/****************************************
* Determine number of times window is
* scrolled since last update
****************************************/
nscrolls = sw->scrollcount; if(nscrolls >= sw->ny)
nscrolls = 0;
sw->scrollcount = 0L;
dw->_flags = _HASMOVED;
dw->_cury = sw->cury;
dw->_curx = sw->curx;
if(nscrolls > 0) {
/* Don't copy lines that is scolled away */
for(y = nscrolls; y < sw->ny; y++) {
yind = GETYIND(y - nscrolls, sw->toprow, sw->ny);
if(sw->lastch[yind] != _NOCHANGE) {
first = dw->_line[y].firstchar = sw->firstch[yind];
last = dw->_line[y].lastchar = sw->lastch[yind];
ps = &sw->screen[yind][first];
pd = (chtype *)&dw->_line[y].text[first];
nx = last - first + 1;
LOOPDN(x, nx)
d++ = *ps++;
if(! win_shared) {
sw->firstch[yind] = sw->nx;
sw->lastch[yind] = _NOCHANGE;
}
}
}
} else {
LOOPUP(y, sw->ny) {
yind = GETYIND(y, sw->toprow, sw->ny);
if(sw->lastch[yind] != _NOCHANGE) {
first = dw->_line[y].firstchar = sw->firstch[yind];
last = dw->_line[y].lastchar = sw->lastch[yind];
ps = &sw->screen[yind][first];
pd = (chtype *)&dw->_line[y].text[first];
nx = last - first + 1;
LOOPDN(x, nx)
*pd++ = *ps++;
if(! win_shared) {
sw->firstch[yind] = sw->nx;
sw->lastch[yind] = _NOCHANGE;
}
}
}
if(! win_shared)
sw->changed = FALSE;
}
*changed = TRUE;
return(nscrolls);
}
I appreciate all the help I can get!
The members of struct ldat were made private in June 2001. Reading the function and its mention of scrolls hints that it is writing a portion of some window used to imitate scrolling (by writing a set of lines to the real window), and attempting to bypass the ncurses logic which checks for changed lines.
For a function like that, the only solution is to determine what the developer was trying to do, and write a new function which does this — using the library functions provided.

Checkers game in SDL

i'm trying to make a checkers game and atm i'm doing the interface with SDL, but i'm just learning C and SDL, how can I move a surface I added to the screen ? I want it the simplest as possible, just remove from X and show on Y, how do I remove a surface to make it appear on another place on the screen ? here is my code:
#include "SDL.h"
#define BRANCA 2
#define PRETA 1
#define DAMA 2
#define NORMAL 1
//The attributes of the screen
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int SCREEN_BPP = 32;
//The surfaces that will be used
SDL_Surface *pecaPreta = NULL;
SDL_Surface *pecaBranca = NULL;
SDL_Surface *pecaDamaPreta = NULL;
SDL_Surface *pecaDamaBranca = NULL;
SDL_Surface *background = NULL;
SDL_Surface *screen = NULL;
SDL_Event event;
SDL_Surface *load_image(char * filename )
{
SDL_Surface* loadedImage = NULL;
SDL_Surface* optimizedImage = NULL;
loadedImage = SDL_LoadBMP(filename);
if( loadedImage != NULL )
{
optimizedImage = SDL_DisplayFormat( loadedImage );
SDL_FreeSurface( loadedImage );
if( optimizedImage != NULL )
{
Uint32 colorkey = SDL_MapRGB( optimizedImage->format, 0, 0xFF, 0xFF );
SDL_SetColorKey( optimizedImage, SDL_SRCCOLORKEY, colorkey );
}
}
return optimizedImage;
}
void apply_surface( int x, int y, SDL_Surface* source, SDL_Surface* destination )
{
SDL_Rect offset;
offset.x = x;
offset.y = y;
SDL_BlitSurface( source, NULL, destination, &offset );
}
void inserePeca(int tipo, int posX, int posY, int cor)
{
switch(cor)
{
case 1:
switch (tipo)
{
case 1:
apply_surface(posX, posY, pecaPreta, screen);
break;
case 2:
apply_surface(posX, posY, pecaDamaPreta, screen);
break;
}
break;
case 2:
switch (tipo)
{
case 1:
apply_surface(posX, posY, pecaBranca, screen);
break;
case 2:
apply_surface(posX, posY, pecaDamaBranca, screen);
break;
}
break;
}
}
int main()
{
int quit = 0;
if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 )
{
return 1;
}
screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE );
if( screen == NULL )
{
return 1;
}
//Set the window caption
SDL_WM_SetCaption( "Jogo de Damas 0.1b", NULL );
//Load the images
pecaPreta = load_image( "pecapreta.bmp" );
pecaBranca = load_image("pecabranca.bmp");
pecaDamaPreta = load_image("pecadamapreta.bmp");
pecaDamaBranca = load_image("pecadamabranca.bmp");
background = load_image( "tabuleiro.bmp" );
//Apply the background to the screen
apply_surface( 0, 0, background, screen );
inserePeca(DAMA, 0,0, BRANCA);
inserePeca(NORMAL, 80,0, PRETA);
//Update the screen
if( SDL_Flip( screen ) == -1 )
{
return 1;
}
while( quit == 0 )
{
//While there's an event to handle
while( SDL_PollEvent( &event ) )
{
//If the user has Xed out the window
if( event.type == SDL_QUIT )
{
//Quit the program
quit = -1;
}
}
}
//Free the surfaces
SDL_FreeSurface( pecaPreta );
SDL_FreeSurface( background );
//Quit SDL
SDL_Quit();
return 0;
}
as you can see I add a block on "inserePeca", I want to move it after I create it
The buffer for the screen doesn't keep all the things you draw on it as separate items -- it just holds the end result of all the drawing operations. So, you can't just draw the background, then draw a piece on it, then move the piece around -- you need to redraw the affected parts of the screen with the required changes.
You still have the images of the pieces, and you still have the background image; the way to move a piece you've drawn is simply to restore the background to the old position by blitting it again, and then blit the piece in the new position. Rather than drawing the whole screen and all the pieces over again, though, you can just draw the changed areas: blit just a part of the background to erase the old square, and then blit the piece onto the new square.
The following function is similar to your apply_surface() function, but instead of copying the whole source image to the the given coordinates of the destination, it copies a region of a given width and height from the given coordinates of the source image to the same coordinates of the destination. This can then be used to restore the background for a small part of the screen.
/* Blit a region from src to the corresponding region in dest. Uses the same
* x and y coordinates for the regions in both src and dest. w and h give the
* width and height of the region, respectively.
*/
void erase_rect( int x, int y, int w, int h, SDL_Surface *src, SDL_Surface *dest)
{
SDL_Rect offset;
offset.x = x;
offset.y = y;
offset.w = w;
offset.h = h;
SDL_BlitSurface( src, &offset, dest, &offset );
}
So if your squares are 50x50, and you need to move a piece from a square at (120, 40) to the square at (170, 90), you could do something like the following:
/* erase old 50x50 square at (120,40) (to background image) */
erase_rect( 120, 40, 50, 50, background, screen );
/* draw piece at new position of (170,90) */
inserePeca(NORMAL, 170, 90, PRETA);

Resources