I am sorry for a vague title, but the question is also. I suppose this question is more directed at people who do not use Libraries, maybe. Anyway I'll try to put up my question. I was wondering how you create the base for your application. For example, I have been having trouble with "Creating A Window", not for the fact that it is hard (using Windows API), but the fact I have no idea how to organize it. Also I am unsure whether I want to use C or C++. Yeah, not which one is better (so no flaming) but in fact which one I can use better. C I understand much more, C++ just looks cool. C++'s errors can drive me crazy, and get me into interesting situations. C I understand quite a bit (been using it for a long time) and understand how to do everything I need to do. Now, when I was prototyping some ideas for the C++ version, I wasn't sure how to code the beginning of the system. I wasn't wanting to create a whole Engine for the game, just wanted the game to have the functionality that was nessary. For this, I had the idea...
CWindow - Basic Win32 Window
CRenderWindow - Inherited From CWindow, Applies OpenGL Onto Window
* 2 Event-Trigger Methods
1. Inherit CRenderWindow onto a generic class such as GameCore class, which controls all (doesn't look right though, because why would the core be a type of a window).
2. Function Pointers creating a callback system from events. I tried this one and the c++ version was acting very very strange, honestly not the slightest idea why. Ex: Setting a private variable to true, later on I check it and it is always false, even if nothing else modifies it).
So basically, having GameCore inherit CRenderWindow makes no sense, so #1 is out. #2 would crash every time I try to implement the system. I only blame myself for not understanding the deeper complexities of C++.
So I was really wondering how you guys name your classes. I know beginning a class with C is suppose to be bad (forget why but it even looks ugly!). I just couldn't come up with better names.
Finally, tonight, I started re-writing my mini-game in C. I implemented a Window system, which OpenGL can be selectivly applied to it, and few other features. I was able to implement the callback system with ease, and works flawlessly. A few functions I have question on though, for the fact they don't make sense how their named.
Example: I implemented CreateRenderWindow which will basically call Win32's CreateWindow (With other stuff too). The problem is, it isn't necessarily a RENDER window. Of course CreateWindow is out of the question, because it is already used (hah, of course!). So basically, I am having difficulty in naming my routines. Of course many of them I have an easy time, and describe the functionality very well. It is just the fact that simple and basic routines I can't name.
For the sake of how I am implementing the system now, I'll give you the code. I am NOT asking you to not complain about my code. I would like to know what you guys think. I know, programming is like an art, but the type of paint/resources used can always give an artist a new perspective on things. ;) This isn't a simple question->answer thread, more of a "what is your opinion" thread. I am just asking that no one disagrees with anything anyone else says. No one is wrong. ;)
Anyways, the quick 2-hour whipped up code...
***** Code From: Window.c *****
#include <windows.h>
#include "window.h"
#include "application.h"
LRESULT CALLBACK MessageCallback(HWND, UINT, WPARAM, LPARAM);
//####################################################################################################
//# Global Functions Programming #
//# * Function prototypes can be found on the 'module's include file. #
//####################################################################################################
//============================================================
// Function: CreateRenderWindow
// Params: RE_Window Struct Pointer
// Return: None
//============================================================
void CreateRenderWindow(SE_Window *Window, const char *Title)
{
WNDCLASSEX sWindowClass;
// Fail-Safe
if (!Window)
return;
memset(Window, 0, sizeof(SE_Window));
// Register Window Class (Ewww, Might Need Updated!)
sWindowClass.cbSize = sizeof(WNDCLASSEX);
sWindowClass.style = 0;
sWindowClass.lpfnWndProc = MessageCallback;
sWindowClass.cbClsExtra = 0;
sWindowClass.cbWndExtra = 0;
sWindowClass.hInstance = Application.Instance;
sWindowClass.hIcon = (HICON)LoadIcon(0, IDI_WINLOGO);
sWindowClass.hCursor = (HCURSOR)LoadCursor(0, IDC_ARROW);
sWindowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
sWindowClass.lpszMenuName = 0;
sWindowClass.lpszClassName = "Flare";
sWindowClass.hIconSm = (HICON)LoadIcon(0, IDI_WINLOGO);
if (!RegisterClassEx(&sWindowClass))
{
MessageBox(0, "Class Registeration Failed", "Debug", MB_OK);
return;
}
// Create Interface Window
Window->Handle = CreateWindow("Flare", Title, WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, 0, 0, Application.Instance, 0);
if (Window->Handle == 0)
{
MessageBox(0, "Window Creation Failed", "Debug", MB_OK);
return;
}
// Setup Misc. Material
SetWindowLong(Window->Handle, GWL_USERDATA, (LONG)Window);
Window->Active = TRUE;
}
//============================================================
// Function: ProcessWindowMessages
// Params: None
// Return: None
//============================================================
void ProcessWindowMessages(SE_Window *Window)
{
MSG sMessage;
if (PeekMessage(&sMessage, 0, 0, 0, PM_NOREMOVE))
{
if (!GetMessage(&sMessage, 0, 0, 0))
Window->Active = FALSE;
TranslateMessage(&sMessage);
DispatchMessage(&sMessage);
}
}
//============================================================
// Function: RegisterWindowEvent
// Params: Callback Type, Function Pointer
// Return: None
//============================================================
void RegisterWindowEvent(SE_Window *Window, BYTE bType, void (*fp))
{
switch (bType)
{
case WINDOW_CALLBACK_KEYPRESS:
Window->cp_OnKeyPress = fp;
break;
case WINDOW_CALLBACK_KEYRELEASE:
Window->cp_OnKeyRelease = fp;
break;
case WINDOW_CALLBACK_MOUSEMOVE:
Window->cp_OnMouseMove = fp;
break;
}
}
//============================================================
// Function: SetWindowParam
// Params: Window Pointer, Param Type, Param A, Param B
// Return: None
//============================================================
void SetWindowParam(SE_Window *Window, BYTE ParamType, DWORD ValueA, DWORD ValueB)
{
DEVMODE sScreenSettings;
DWORD Result;
switch (ParamType)
{
case WINDOW_PARAM_POSITION:
Window->X = ValueA;
Window->Y = ValueB;
SetWindowPos(Window->Handle, 0, ValueA, ValueB, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
break;
case WINDOW_PARAM_SIZE:
Window->Width = ValueA;
Window->Height = ValueB;
if (Window->Fullscreen)
SetWindowParam(Window, WINDOW_PARAM_FULLSCREEN, WINDOW_ENABLE, 0);
else
SetWindowPos(Window->Handle, 0, 0, 0, ValueA, ValueB, SWP_NOZORDER | SWP_NOMOVE);
break;
case WINDOW_PARAM_FULLSCREEN:
if (ValueA == WINDOW_ENABLE)
{
sScreenSettings.dmSize = sizeof(DEVMODE);
sScreenSettings.dmPelsWidth = Window->Width;
sScreenSettings.dmPelsHeight = Window->Height;
sScreenSettings.dmBitsPerPel = 16;
sScreenSettings.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
Result = ChangeDisplaySettings(&sScreenSettings, CDS_FULLSCREEN);
if (Result != DISP_CHANGE_SUCCESSFUL)
return;
SetWindowLong(Window->Handle, GWL_style, WS_POPUP | WS_VISIBLE);
SetWindowPos(Window->Handle, HWND_TOP, 0, 0, Window->Width, Window->Height, SWP_SHOWWINDOW);
Window->Fullscreen = TRUE;
}
else
{
SetWindowLong(Window->Handle, GWL_style, WS_OVERLAPPEDWINDOW | WS_VISIBLE);
SetWindowPos(Window->Handle, HWND_TOP, Window->X, Window->Y, Window->Width, Window->Height, SWP_SHOWWINDOW);
ChangeDisplaySettings(0, 0);
Window->Fullscreen = FALSE;
}
break;
}
}
//============================================================
// Function: DestroyRenderWindow
// Params: Window Struct Pointer
// Return: None
//============================================================
void DestroyRenderWindow(SE_Window *Window)
{
// Fail-Safe Check
if (!Window)
return;
// Restore Resolution
if (Window->Fullscreen)
ChangeDisplaySettings(0, 0);
}
//####################################################################################################
//# Local Functions Programming #
//# * Function prototypes are at top of file. #
//####################################################################################################
//============================================================
// Function: MessageCallback (Private to Module)
// ** I think we all know the params ;) **
// ** Or is there just too many to list? Hmmm... **
//============================================================
LRESULT CALLBACK MessageCallback(HWND Handle, UINT Message, WPARAM wParam, LPARAM lParam)
{
SE_Window *Window = (SE_Window*)GetWindowLong(Handle, GWL_USERDATA);
switch (Message)
{
case WM_CREATE:
/* ALERT: Window Not Referenced Yet On WM_CREATE!!!!!!! */
break;
case WM_KEYDOWN:
if (Window && Window->cp_OnKeyPress)
(Window->cp_OnKeyPress)(Window,Message,wParam);
break;
case WM_KEYUP:
if (Window && Window->cp_OnKeyRelease)
(Window->cp_OnKeyRelease)(Window,Message,wParam);
break;
case WM_MOUSEMOVE:
if (Window && Window->cp_OnMouseMove)
(Window->cp_OnMouseMove)(Window,Message,wParam,LOWORD(lParam),HIWORD(lParam));
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(Handle, Message, wParam, lParam);
}
return 0;
}
***** Code From: main.c *****
#include <windows.h>
#include "system/application.h"
#include "system/window.h"
void Game_OnKeyPress(SE_Window *Window, DWORD Event, BYTE Key)
{
if (Key == 'Q')
SendMessage(Window->Handle, WM_CLOSE, 0, 0);
}
void Game_OnKeyRelease(SE_Window *Window, DWORD Event, BYTE Key)
{
//MessageBox(0, "Event: Key Released", "Event Debugger", MB_OK);
}
void Game_OnMouseMove(SE_Window *Window, DWORD Event, BYTE Special, WORD MouseX, WORD MouseY)
{
char Buffer[128];
sprintf(Buffer, "Mouse(%u:%u)", MouseX, MouseY);
SetWindowText(Window->Handle, Buffer);
}
void EntryPoint(void)
{
SE_Window Window;
CreateRenderWindow(&Window, "Flare Game");
SetWindowParam(&Window, WINDOW_PARAM_SIZE, 1680, 1050);
SetWindowParam(&Window, WINDOW_PARAM_FULLSCREEN, WINDOW_ENABLE, 0);
RegisterWindowEvent(&Window, WINDOW_CALLBACK_KEYPRESS, &Game_OnKeyPress);
RegisterWindowEvent(&Window, WINDOW_CALLBACK_KEYRELEASE, &Game_OnKeyRelease);
RegisterWindowEvent(&Window, WINDOW_CALLBACK_MOUSEMOVE, &Game_OnMouseMove);
while(Window.Active)
{
ProcessWindowMessages(&Window);
//Sleep(1);
}
}