I have a problem with glut, I would like to have a callback to know when the user is moving the window of my application, and I didn't found anything in glut.
My goal is to make an application only on windows, is it possible to do this with MFC keeping my glut code?
Thanks in advance
I couldn't find a call back function but you could do it by hand with glutGet:
int glutGet(GLenum state);
An example of what you might do is:
bool window_change(void)
{
int init_x = glutGet(GLUT_INIT_WINDOW_X);
int init_y = glutGet(GLUT_INIT_WINDOW_Y);
int pos_x = glutGet(GLUT_WINDOW_X);
int pos_y = glutGet(GLUT_WINDOW_Y);
return (init_x != pos_x || init_y != pos_y);
}
This will return true if it's moved from it's initial spot. If you want to see if it's moved since the last check, try:
bool window_change(void)
{
static int init_x = glutGet(GLUT_INIT_WINDOW_X);
static int init_y = glutGet(GLUT_INIT_WINDOW_Y);
int pos_x = glutGet(GLUT_WINDOW_X);
int pos_y = glutGet(GLUT_WINDOW_Y);
bool result = init_x != pos_x || init_y != pos_y;
init_x = pos_x;
init_y = pos_y;
return result;
}
You can set the window position by using the function: glutPositionWindow
void glutPositionWindow(int x, int y);
the idea from Bruce is very good. i think there is not another option while using GLUT.
i think this scenario is something that GLUT was not developed for. GLUT is a toolkit for OpenGL, which wraps window- and input-management across platforms. it has a lot of uses,
but why should it care, when its window is dragged?
i think if you (or your program) care, then you should implement your own window- and input-management anyway.
which leads me to your second question. you can use OpenGL with MFC (although my recommendation strongly depends on what you are planing). you should not use GLUT then, because MFC has its own way of handling input, windows, event management, rendering/drawing ...
if you really want to do it:
http://www.codeproject.com/KB/openGL/OpenGL_MFC_AppWizard.aspx
You might try using the glutTimerFunction to periodically call Bruce's example function. It will have to take an integer as a parameter used to identify the source of the callback request. The glutTimerFunction is also designed to only be called once, then it deletes itself. However, it can schedule a call on itself. I ran into this problem using PyOpenGL so I'm not going to go through the C agony of getting this to compile. From Bruce's generous example altered. Obviously a hack, but better than scrapping.
int main(void)
{
...
glutTimerFunc(0, window_change, 0);
}
void window_change(int id)
{
int init_x = glutGet(GLUT_INIT_WINDOW_X);
int init_y = glutGet(GLUT_INIT_WINDOW_Y);
int pos_x = glutGet(GLUT_WINDOW_X);
int pos_y = glutGet(GLUT_WINDOW_Y);
...
/* call back again after 1 second has passed */
glutTimerFunc (1000, window_change, id);
}
http://www.opengl.org/resources/faq/technical/glut.htm
GLUT is actually fairly limited, and does not expose all window events to the client. However it does provide a lot of boiler code plate for WGL (on Windows) and GLX (on X11) that is probably not worth rewriting.
When I had a hobby project that was using GL, and there were certain events that I couldn't handle via GLUT, what I did is fork the open source freeglut. That is, download the tarball, and edit the library's WindowProc (Windows) or XGetEvent() loop (on X) and simply add the missing callbacks to the library.
You'll have a dependency on your own GLUT modifications, but it'll work, and you won't have to write as much boiler-plate code as if you were targeting WGL or GLX directly.
You'll probably want to link it statically so it doesn't conflict with any other freeglut.
Related
Background: I've got a Qt/C++ application that currently runs on (and is deployed on) MacOS/X, Windows, and Linux. In one of the application's windows is a view of several dozen audio meters that needs to update frequently (i.e. at 20Hz or faster), so I implemented that view using a QOpenGLWidget and some simple OpenGL routines (see example code below).
This all works fine, however Apple has recently deprecated OpenGL and wants all developers to convert their applications over to Apple's own "Metal" API instead; with the implication that eventually any program that uses OpenGL will stop working on MacOS/X.
I don't mind doing a little #ifdef-magic inside my code to support a separate API for MacOS/X, if I must, however it's not clear if coding to Metal is something that can actually be done in Qt currently. If Metal-inside-Qt is possible, what is the proper approach to use? If not, should I wait for a future release of Qt with better Metal support (e.g. Qt 5.12?) rather than waste my time trying to make Metal work in my current Qt version (5.11.2)?
// OpenGL meters view implementation (simplified for readability)
class GLMetersCanvas : public QOpenGLWidget
{
public:
GLMetersCanvas( [...] );
virtual void initializeGL()
{
glDisable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
glDisable(GL_COLOR_MATERIAL);
glDisable(GL_LIGHTING);
glClearColor(0, 0, 0, 0);
}
virtual void resizeGL(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, w, 0, h, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
virtual void paintGL()
{
const float meterWidth = [...];
const float top = [...];
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_QUADS);
float x = 0.0f;
for (int i=0; i<numMeters; i++)
{
const float y = _meterHeight[i];
glColor3f(_meterColorRed[i], _meterColorGreen[i], _meterColorBlue[i]);
glVertex2f(x, top);
glVertex2f(x+meterWidth, top);
glVertex2f(x+meterWidth, y);
glVertex2f(x, y);
x += meterWidth;
}
glEnd();
}
};
Yes, it is possible to do what you want. It probably won't be a straightforward transition due to the fact that the code you posted uses very old deprecated features of OpenGL. Also, you might be better off just using CoreGraphics for the simple drawing you're doing. (It looks like a number of solid-colored, quads are being drawn. That's very easy and fairly efficient in CoreGraphics.) Metal seems like overkill for this job. That said, here are some ideas.
Metal is an inherently Objective-C API, so you will need to wrap the Metal code in some sort of wrapper. There are a number of ways you could write such a wrapper. You could make an Objective-C class that does your drawing and call it from your C++/Qt class. (You'll need to put your Qt class into a .mm file so the compiler treats it as Objective-C++ to call Objective-C code.) Or you could make your Qt class be an abstract class that has an implementation pointer to the class that does the real work. On Windows and Linux it could point to an object that does OpenGL drawing. On macOS it would point to your Objective-C++ class that uses Metal for drawing.
This example of mixing OpenGL and Metal might be informative for understanding how the 2 are similar and where they differ. Rather than having a context where you set state and make draw calls like in OpenGL, in Metal you create a command buffer with the drawing commands and then submit them to be drawn. Like with more modern OpenGL programming where you have vertex arrays and apply a vertex and fragment shader to every piece of geometry, in Metal you will also submit vertices and use a fragment and vertex shader for drawing.
To be honest, though, that sounds like a lot of work. (But it is certainly possible to do.) If you did it in CoreGraphics it would look something like this:
virtual void paintCG()
{
const float meterWidth = [...];
const float top = [...];
CGRect backgroundRect = CGRectMake(...);
CGContextClearRect(ctx, backgroundRect);
float x = 0.0f;
for (int i=0; i<numMeters; i++)
{
const float y = _meterHeight[i];
CGContextSetRGBFillColor(ctx, _meterColorRed[i], _meterColorGreen[i], _meterColorBlue[i]);
CGRect meterRect = CGRectMake(x, y, meterWidth, _meterHeight[i]);
CGContextFillRect(ctx, meterRect);
x += meterWidth;
}
glEnd();
}
It just requires that you have a CGContextRef, which I believe you can get from whatever window you're drawing into. If the window is an NSWindow, then you can call:
NSGraphicsContext* nsContext = [window graphicsContext];
CGContextRef ctx = nsContext.CGContext;
This seems easier to write and maintain than using Metal in this case.
I've got a serious problem with my SFML game.
I've been trying whole day to find a solution, tried diffrent things but nothing worked for me so far.
These are my .h files:
Bullet.h
#pragma once
#include <SFML\Graphics.hpp>
#include <iostream>
#include <vector>
class Bullet
{
friend class Player;
friend class Game;
float width;
float height;
float x;
float y;
std::vector<Bullet*> projectiles;
sf::RectangleShape bullet;
void draw_projectiles(sf::RenderWindow &window);
void make_projectiles();
public:
void check();
Bullet();
~Bullet();
};
Game.h
#pragma once
#include <SFML\Graphics.hpp>
#include "Player.h"
#include "Bullet.h"
#include <vector>
//#include "Enemy.h"
class Game
{
friend class Player;
sf::RenderWindow* window;
sf::Event* evnt;
Player* player;
Bullet* bullet;
public:
void Loop();
void game_func();
Game();
~Game();
};
Player.h
#pragma once
#include <SFML\Graphics.hpp>
#include <iostream>
#include "Game.h"
#include "Bullet.h"
class Player
{
sf::RectangleShape player;
Bullet* bullet;
int ammo;
float width;
float height;
int x;
int y;
float vel;
public:
void draw(sf::RenderWindow &window);
void move(sf::Event &evnt, sf::RenderWindow &window);
Player();
~Player();
};
Here come cpp files
Bullet.cpp
#include "Bullet.h"
void Bullet::check()
{
x = bullet.getPosition().x;
y = bullet.getPosition().y;
}
void Bullet::draw_projectiles(sf::RenderWindow &window)
{
for (int i = 0; i < 10; i++)
{
window.draw(projectiles[i]->bullet);
}
}
void Bullet::make_projectiles()
{
projectiles.push_back(new Bullet());
}
Bullet::Bullet()
{
std::cout << "zostal utworzony nowy obiekt" << std::endl;
width = 50;
height = 50;
bullet = sf::RectangleShape(sf::Vector2f(width, height));
bullet.setFillColor(sf::Color::Yellow);
bullet.setPosition(0, 0);
x = bullet.getPosition().x;
y = bullet.getPosition().y;
}
Bullet::~Bullet(){}
Game.cpp
#include "Game.h"
Game::Game()
{
window= new sf::RenderWindow(sf::VideoMode(1280, 720), "SFML Game",
sf::Style::Close);
player = new Player();
}
Game::~Game(){}
void Game::Loop()
{
while (window->isOpen())
{
sf::Event evnt;
while (window->pollEvent(evnt))
{
//events
if (evnt.type==sf::Event::Closed)
window->close();
player->move(evnt, *window);
window->clear();
player->draw(*window);
window->display();
bullet->draw_projectiles(*window);
}
}
}
void Game::game_func()
{
Game::Loop();
}
Player.cpp
#include "Player.h"
void Player::draw(sf::RenderWindow &window)
{
window.draw(player);
}
void Player::move(sf::Event &evnt, sf::RenderWindow &window)
{
x = player.getPosition().x;
y = player.getPosition().y;
float width = window.getSize().x;
float height = window.getSize().y;
Bullet obj;
if (evnt.type == sf::Event::KeyPressed)
{
//movement
if (evnt.key.code == sf::Keyboard::Key::W)
{
if (y <= 0)
{
return;
}
player.move(0, -1 * vel);
}
if (evnt.key.code == sf::Keyboard::Key::S)
{
if (y >= height - Player::height)
{
return;
}
player.move(0, 1 * vel);
}
if (evnt.key.code == sf::Keyboard::Key::A)
{
if (x <= 0)
{
return;
}
player.move(-1 * vel, 0);
}
if (evnt.key.code == sf::Keyboard::D)
{
if(x>width-Player::width)
{
return;
}
player.move(1 * vel, 0);
}
if (evnt.key.code == sf::Keyboard::Space)
{
obj.make_projectiles();
}
}
}
Player::Player()
{
width = 100;
height = 100;
vel = 10;
player = sf::RectangleShape(sf::Vector2f(width, height));
player.setFillColor(sf::Color::Red);
player.setPosition(sf::Vector2f(15, 20));
}
Player::~Player(){}
And main.cpp
#include <SFML/Graphics.hpp>
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <vector>
#include "Game.h"
int main()
{
Game gme;
gme.game_func();
return 0;
}
I tried many diffrent things and can't figure it out why it's not working. Im running in on Visual Studio 15.
So here is error that I'm getting:
Exception thrown: read access violation.
std::_Vector_alloc<std::_Vec_base_types<Bullet *,std::allocator<Bullet *> >
>::_Mylast(...) returned 0x18.
I'm aware that code is not perfect and little messy but I'm just a begginer and trying to learn new stuff.
I will appreciate any help!
I answered your question in my last paragraphs, you can skip to that paragraph but I sugest you take a look at all of this. First of all you should understand how should a basic game look like in code.
The Game Logic
You can separate the game logic in 2 main functions. The initialization and the loop.
Initialization
In the initialization function, you basically load everything needed for your game to run (that is only available for small games, since loading tens of gigs of sprites in memory may not be the best solution for bigger ones. With time you'll figure out the right time to load and release resources).
The loop
This is called the main loop or the game loop. This loop should execute 3 main functions. Handle user input, update world, and render the world. This loop should execute while the game is running (i.e. while the window is open)
So your main in pseudo-c++ should look something like this:
Init();
while (window.isOpen())
{
HandleEvents(window); //user input
Update(elapsedTime);
Render(window);
}
I'll explain what the functions do, what the arguments mean and how this functions are mapped to your code. Keep in mind that every function has one specific task and only that. I won't check if the user is pressing a button while I'm drawing the sprites on the screen.
User input
Everything from button pressing and mouse clicking to pressing the exit button and resizing the window is called user input. User's actions generate the so called events, which we handle at the beginning of each loop. Now this events are window specific(you can't control the player if the window is minimized or unfocused). That means that the window generates the events (if I'm wrong with this one technically, please correct me). This is the reason that when you are handling events you need to pass the window.
Events
Before handling the events, you need to understand how sf::Event is made (see more on the sfml page). Long story short the sf::Event is an union (only one field is valid at a time). That is, if you try to access event.key when the window.pollEvent() returned an sf::Event::JoystickEvent you will get an undefined behavior (I lived a long happy life without knowing what unions are, never used them and probably never will, but they are quite an interesting concept that is worth at least reading about). Ok so an event object is created by calling window.pollEvent() and passing to it an sf::Event instance. This function will give you events from the queue until there are no more events to be given, that's when it returns false. With that in mind, your Event handling code would look something like:
sf::Event ev;
while (window.pollEvent(ev))
{
switch (ev.type)
{
//code for each type needed by your application
}
}
Keep in mind that key events do not handle real time input (sf::Keyboard::isKeyPressed does that). This means that if you want your character to move when you hold a button, handling it by events will result in a delay that can be the best explained by the way typing works(when you hold down 'a' for example the first character is written immediately, the rest of the input is delayed by a second before registering). This is a way of explaining it, but maybe not the most technical one(I'm asking for a little help here :) ). Anyway, this problem can be solved either by using the static methods of sf::Keyboard or by keeping a bool in your Player class that answers to the events KeyPressed and KeyReleased(the update will be handled based on that bool).
World Update
Here is your logic code(although player movement may also be handled in the events section, since it's based on them). Here you update your entities(move the enemy one more block based on his AI), move the sun around the map etc. Keep in mind that this has nothing to do with the drawing part, in this section you only change the state of your objects. In your game it means, after you launched a projective through an event triggered by the user, each frame you move the projectile. This code usually requires some sort of frame counting method.
Frames
A frame is an iteration of the loop, you can say that the game updates and draws itself each frame. Frames are a very important concept because they arise some issues. If the game updates itself each frame, that means that each frame the projectile is moving, so that means that his movement is dependent to the FPS your pc can run. This is a problem, because while your game may run as you want on your pc, at a stable 60 FPS rate, on mine it might run at 53, or some other random value. That means that the projectiles on my pc will move slower, and we don't want that.
Frame independent movement
This can be achieved by counting the frames. One way you can do that is by counting the seconds it passed since the last frame, with that in mind you can get the amount of space your entity needs to move in that specific frame. For example, you want to move your projectile with 100px/sec. If you have 2FPS that means that in 2 frames it needs to move 100px, so each frame moves 100 / 2 px. So the formula is finalDistance / framerate. There are more ways of doing this, but in my opinion this is the simplest to understand at the beginning. So how is this implemented in SFML? You basically keep a clock that you restart at the end of each update. getElapsedTime and restart does that, but restart returns the elapsedTime so it is better to call it once, since calling them one by one may result in different times and desyncs.
sf::Clock clock;
while (window.isOpen())
{
HandleEvents(window);
Update(clock.restart());
Render(window);
}
And you simply move your entities with move(vector * clock.getElapsedTime().asSeconds()) since sf::Vector has operator* overloaded for floats(the return type of asSeconds()).
Rendering
The rendering part may be very complicated, but sfml makes it "simple and fast". Basically it works like that: You clear the screen, you draw your entities, you display the screen. The more technical answer is the following: the window consists of 2 buffers, one visible and one hidden. The visible one is the one you see on the screen. When you call clear() you basically clear the hidden one, draw() draws also on the hidden window, and finally display() swaps the buffers.
That means that you won't see any results unless you call window.display(), and you'll get a window xp experience if you don't call clear() before drawing. So the Render function might look like this:
window.clear();
window.draw(player); //or player.draw(window) based on your implementation
//other draws
window.display();
Your question
What happens in your code is that you try to access things that don't exist. You add one projectile at a time, but each frame you draw 10 of them.
The solution
Keep a counter of your objects. Since you are using a vector that is already provided, you have std::vector::size that returns exactly what you expect, so your code will turn into something like:
for (int i = 0; i < yourProjectiles.size(); i++)
{
window.draw(yourProjectiles[i]->bullet);
}
Alternatively you can use iterators(look them up):
for (auto it = yourProjectiles.begin(); it != yourProjectiles.end(); ++it)
{
window.draw(it->bullet);
}
Memory management
You don't deallocate memory. You have to look into dynamic memory allocation. The base principle is that for every new there should be a delete. The deallocation part should be handled most of the time in the destructor of the class. I think someone may suggested to use smart pointers(std::shared_ptr) so manage your memory, but I can't recommend you that since you are at the beginning. Smart pointers are a concept you should keep in mind, but as you started out it is better to face the struggles of manual memory management(until you get used to it).
Code organizing
A class should be made for only one purpose. When you create a class called Bullet, it is expected that this Bullet will represent one projectile in your game, but when your Bullet makes "projectiles" and stores projectiles, it becomes a paranormal entity. Your bullet atm holds pointers to instances of other bullets that hold pointers to instances of other bullets. This is a total mess. Unless you want to create a graph or a tree of some sort you don't have any reason to store pointers of instances of the same class.
Too many friends
If every class is friend with every class, what is your reason of creating private fields? Friend is a very powerful concept and should be used with care, only in cases you DON'T have other options. The only reason I would avoid this keyword is the messiness it creates. It creates the same effect as public attributes. When everything is accessible from everywhere, everything can be destroyed from everywhere. When you create a small set of methods that manipulate your attributes, you know where the problem is.
Conclusion
I might suggest looking a little more into c++ and after that debug your game, or recreate it from scratch. While I know how it feels to try something new, you should always be careful to not shoot yourself in the leg, and don't be afraid to go back to the basics when you stumble into such errors. You have problems managing memory? Read more about dynamic memory allocation, do some example apps using it. Besides that I noticed you are still at the beginning with using classes. I'd say practice makes perfect. Look at other people code, even these 3rd party libraries like sfml may give you some hints on good class practices. The good thing is that it is not needed to look at the source code of those libraries, you just use their interface. If you like it, it means it is good written and you may borrow a part of that style and implement in your classes. I'll conclude this by saying that I am very happy and eager to help you via email if you have any other question regarding anything.
I believe you are attempting to access ten projectiles:
for (int i = 0; i < 10; i++)
{
window.draw(projectiles[i]->bullet);
}
But you only add one at a time:
projectiles.push_back(new Bullet());
Is there any difference between calling glutPostRedisplay() at the end of my display function and using an idle function callback that does nothing but call my display function? I have seen both ways used in examples and cannot tell the difference by observation.
A main loop generally looks like this:
Process and handle events
calling stuff like glutKeyboardFunc/glutMouseFunc.
Advance/update 3D state (physics/animation etc)
typically in glutIdleFunc
Re-draw the scene if needed
use glutDisplayFunc
glutPostRedisplay simply sets a flag, that tells glut to call the display callback on the next loop iteration. It doesn't actually call display [1] [2].
If you have a game, which always updates every frame this might not be that useful. Maybe if you're alt-tabbed or dragging the window you don't need to be calling display. Or you might be frame limiting by dropping frames (although I'd suggest this).
void idle()
{
...
animatedThing.value += deltaTime
glutPostRedisplay(); //scene is always changing. always call display
}
Having a "dirty" flag becomes more useful when you don't need to re-render continuously. Maybe in something like a 3D modelling package where there isn't any animation and you only move the camera occasionally. Or a GUI where you only need to update when you hover and click on stuff.
void mousedown(int button, int state, int x, int y)
{
if (clickedGUI(x, y))
glutPostRedisplay();
}
void idle()
{
...
if (myKeys[MOVE_VIEW_FORWARD])
{
view.z -= deltaTime;
glutPostRedisplay();
}
}
Anyway, to answer your question, no, there's probably not much difference. However...
I'd put the glutPostRedisplay in idle as above. Calling from within display works but gives up some control you might want later. It's essentially this:
bool shouldDraw = true;
while (1)
{
// check events, input etc
// idle/update state
if (shouldDraw)
{
shouldDraw = false;
// draw
shouldDraw = true;
}
}
I also wouldn't call display from idle from a design perspective as it removes some control from glut. For example if there's a case where glut needs to override the post-redisplay (not that I know of one) it won't be able to.
While trying to create a nice wrapper around Win32 specific GUI components, I eventually ran into a problem. The problem is that I'm unable to close the application after the windows I created no longer exist.
My API works like this:
/// ----------------------------
/// #author God
/// #project Helixirr Widgets
/// ----------------------------
#include <helixirrwidgets/HelixirrWidgets.hpp>
int main(void){
HelixirrWidgets::Window __windows[2] = {HelixirrWidgets::Window("Big Window"), HelixirrWidgets::Window()};
__windows[0].position(200, 200);
__windows[0].size(800, 600);
__windows[0].visible(true);
__windows[0].save_changes();
__windows[1].name("Tiny Window");
__windows[1].position(10, 100);
__windows[1].size(400, 200);
__windows[1].visible(true);
__windows[1].save_changes();
while(__windows[0].active() || __windows[1].active()){
if(__windows[0].visible()){
__windows[0].show();
}
if(__windows[1].visible()){
__windows[1].show();
}
}
return 0;
}
In method of HelixirrWidgets::Window called "active", which is declared like this
inline bool active(void) const noexcept;
I can check, whether my window is active or not.
This method basically return a const reference to a boolean member variable of an instance. This member variable is modified in "show"-method of the same class. Here's the definition:
void Window::show(void){
if(GetMessage(&_m_opHelper->message, _m_opHelper->handle_window, 0, 0)){
if(_m_opHelper->message.message == WM_CLOSE){
_m_bActive = false;
return;
}
TranslateMessage(&_m_opHelper->message);
DispatchMessage(&_m_opHelper->message);
ShowWindow(_m_opHelper->handle_window, SW_SHOWDEFAULT);
UpdateWindow(_m_opHelper->handle_window);
_m_bActive = true;
return;
}
_m_bActive = false;
}
Do note I use pimpl-idiom to hide platform-specific structures ("_m_opHelper" is pointer to implementation).
It may look like it works, but it doesn't and I can't understand why. It all comes down to a simple question: how can I close my window implemented using WINAPI specific functions and structures to be closed appropriately by a user of my application?
I guess the cause of the issue is related to the fact WM_CLOSE simply is not last message HWND gets. Messages like WM_DESTROY, WM_NCDESTROY and possibly more (depending on the particlar window and its state) will come after WM_CLOSE, leading to the assignment _m_bActive = TRUE.
I.e. the window becomes inactive for very short time, and (likely) they will never be inactive at the same time, causing an endless loop in main().
I am working on a small game and game engine in C++ using DirectX. The purpose is educational & recreational.
My next goal is to build a simple world editor that uses the game engine. For this I will need to move the engine into a dll so it can be consumed by the game and/or by the editor. The world editor will be a stand-alone tool and not part of the game. The main purpose of the world editor will be to read in and display my (custom) scene file, and allow me to annotate/modify properties on world objects (meshes), clone objects, pick up and move objects about and drop them, scale objects, etc., and then save out the modified scene so it can later be read by the game.
It has been recommended that I use wxWidgets for the editor. A bit of research makes me feel that wxWidgets is a bit old and clunky, though I am sure very fine GUIs can be written using it. It's just a steep learning curve that I don't look forward to. I have gotten the samples to build and run, but it was a headache.
A little more research and I find that I can integrate DirectX into a WPF app using a D3DImage. I have done a little with WPF and do not find it too intimidating and there are plenty of good books available (there is only one old one for wxWidgets), as well as scads of information on the web. I have gotten the rotating triangle example working and it seemed pretty straightforward.
So my question is:
Will WPF allow me to build a decent little world editor app that re-uses my game engine?
My game engine currently uses RawInput for mouse and keyboard; how will this work with WPF?
How does WPF affect my message pump?
It looks like I will have to write a lot of functions (facade pattern?) to allow WPF to interact with my game engine. Is there an easy way to factor this out so it doesn't get compiled into the game?
Any other tips or ideas on how to proceed would be greatly appreciated!
Thank you.
You need to create a wrapper class that exposes certain functionality of your game.
For example. This function is in my c++ game engine editor wrapper.
extern "C" _declspec(dllexport) void SetPlayerPos(int id, const float x, const float y, const float z);
Then in your c# wpf application you can create a static class allowing you to use those functions
[DllImport(editorDllName, CallingConvention = CallingConvention.Cdecl)]
public static extern void SetPlayerPos(int id, float x, float y, float z);
You will have to have functions for your basic functionality of the game engine through the dll.
things like
EditorMain
RenderFrame / Update
DXShutdown
So then you can call editormain in your wpf app constructor
System.IntPtr hInstance = System.Runtime.InteropServices.Marshal.GetHINSTANCE(this.GetType().Module);
IntPtr hwnd = this.DisplayPanel.Handle;
NativeMethods.EditorMain(hInstance, IntPtr.Zero, hwnd, 1, this.DisplayPanel.Width, this.DisplayPanel.Height);
You will need to create a message filter class and initialize it in the constructor as well
m_messageFilter = new MessageHandler(this.Handle, this.DisplayPanel.Handle, this);
here's how your message filter class could look
public class MessageHandler : IMessageFilter
{
const int WM_LBUTTONDOWN = 0x0201;
const int WM_LBUTTONUP = 0x0202;
IntPtr m_formHandle;
IntPtr m_displayPanelHandle;
EngineDisplayForm m_parent;
public MessageHandler( IntPtr formHandle, IntPtr displayPanelHandle, EngineDisplayForm parent )
{
m_formHandle = formHandle;
m_displayPanelHandle = displayPanelHandle;
m_parent = parent;
}
public bool PreFilterMessage(ref Message m)
{
if (m.HWnd == m_displayPanelHandle || m.HWnd == m_formHandle)
{
switch (m.Msg)
{
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
{
NativeMethods.WndProc(m_displayPanelHandle, m.Msg, m.WParam.ToInt32(), m.LParam.ToInt32());
if (m.Msg == WM_LBUTTONUP)
{
m_parent.SelectActor();
}
return true;
}
}
}
return false;
}
public void Application_Idle(object sender, EventArgs e)
{
try
{
// Render the scene
NativeMethods.RenderFrame();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
for doing win forms and wpf interop look here
http://msdn.microsoft.com/en-us/library/ms742474.aspx