Ok, Panels in C++ are quite doable, as is digits,texts,buttons,radiobuttons,sliders,etc...

I am going to try and provide enough example here to
demystify its syntax as much as possible. It took a good bit
of fiddling to get it working right as I'm sure you are
experiencing right now, if your reading this...

I will cover the methods used thru making an actual C++ app
NOT making a DLL for calling from the script langz, so thats
why you see an entire program (still quite small). All the
same code really, just no worrying about making it into a
DLL.

Firstly, let me say, Everything is different in C++. Most of
you already know this, things like using v(camera).x instead
of camera.x and passing all crazy like (VECTOR*)&v(player).x
stuff...... But panels and how we define them and declare
them is totally ass backwards if you are still stuck in the
c-script/lite-c way of thinking about them. Its not really
backwards it actually makes perfect sense its just a bit of
twiddling to get the swing of how it works... for us it was
anyway.


So, To DECLARE our panel we arent going to DEFINE it at the
same time like in script.. we still declare it globally
unless you have some reason not to for your app. Panels/menus
/buttons for the most part would benefit from being global
anyway so you can call on em from anywhere regardless of
scope.

By not DEFINING it i mean we dont do:

Code:
PANEL* mypan = { panel elements; and such; }


We simply do:
Code:
PANEL* mypan;


Once inside some function (likely after setting up the window
and before entering the main while loop) we will define it
using pan_create (A7 only I think). Like this:


Code:
mypan = pan_create("bmap=MainMenuBmap.jpg; \
button(10,10,Quit.jpg,Quit.jpg,Quit.jpg,NULL,NULL,NULL); \
button(10,80,OptionsBmap.jpg,OptionsBmap.jpg,OptionsBmap.jpg,NULL,NULL,NULL);",_VAR(1));


There is alot going on here. But lets try and look at it very
simple-like.

If you look carefully you can see pan_create takes only 2
parameters:


A string(err const char* whatever use the "" thingies :P )
which is known by us
as content. This string of characters gets passed to acknex
script engine(i think) when it is told to make the panel. You
can see it is EXACTLY the same as what would be in the
brackets if we had done inline definition of the panel when
we declared it (remember what I told you not to do?). So, if
you have a script panel you want to convert to c++ you simply
declare it globally and then copy and paste the code that
defined your panel in script into this here string(gahhhh
const char*!!).


ATTN: See how I passed the filenames for all the images to
buttons and whatnot
in that definition/pan_create? Thats cuz if you do it the
normal way of making
a BMAP* and then loading a file into it with bmp_create() and
then passing the actual BMAP over there (which would work in
lite-c if i remember correctly) it gives an ingame error
dialog saying something like "bad argument in function: BMAP"
so just remember in C++ panels like the filename so no need
to preload them with BMAP*'s. Im gonna go out on a limb here
and maybe a dev can verify this but I wager its cuz since its
being constructed on the other side of the "virtual wall"
between my c++ and the engine that all it wants from us it
instructions on building it, not the actual materials to do
so(ie our BMAP*).


One more thing about that first parameter, this is c++ and we
are sending a long ass character array and typing it in so we
can use '\' the escape character
to essentially 'escape sequence' our newlines so the
compiler/ide knows this is
just for us human readers to break the lines and it keeps it
all as one single line as far as the compiler is concerned.
Makes reading (AND WRITING) it easier.




After you close your quote " and put a comma , its time for
parameter #2.
The Layer: this ones easy... just tell it the layernumber you
want this panel on. (hint: You will need to pass that
layernumber thru the c++ _VAR() macro like I did in the
example above).



ie: layer 1 = pan_create("content_here;",_VAR(1));
ie: layer 2 = pan_create("content_here;",_VAR(2));
etc...

Thats all fine and good but wtf about all the other stuff we
need to do..

Acknex gives us some C++ funcs to handle that.


FIRST THO, lets set a few things:
Code:
	mypan->pos_x=0;
        mypan->pos_y=0;
	mypan->scale_x = _VAR((float)v(screen_size).x / bmap_width(MainMenu->bmap));
	mypan->scale_y = _VAR((float)v(screen_size).y / bmap_height(MainMenu->bmap));
	mypan->flags |= OVERLAY;


Now, we could have included this in our pan_create but I
prefer to just make the elements and then tweak this stuff
manually. We set our x and y positions and calculate scale_x
and scale_y by dividing our screen width and height by our
panels background bmp height and width. ie: 1280x1024 res and
our panel background bmp is 1024x768 we do 1280 / 1024 = 1.25
so we know if we set scale_x to this that the bmp will get
stretched to fit our screen on x axis and so on so forth(you
prolly knew that but just trying to be complete for the nubz).


Then we turn on our panels OVERLAY flag here cuz this ones
gonna have some transparency. In c++ we turn on flags by
doing

mypan->flags |= OVERLAY;

and off by

mypan->flags &= ~OVERLAY;

and check it by doing

if (mypan->flags & OVERLAY) { etc..etc..

This is all in the manual (although kinda hidden).
Turn it on by OR-EQUALing it, OFF by AND-EQUALing it with ~ (antecedant?? idk)
and check it by ANDing it with the flag you wanna know returns 1 if set.
very easy stuff.

Finally, you prolly noticed we passed our Button elements
NULL for there function pointers. I never could get it to
send the func the right way in
the content string, I would guess its another "other side of
the wall" issue.
I imagine thats why they provided us with this lovely
function.


Code:
pan_setevent(mypan,_VAR(3),_VAR(1),(EVENT)cya);
pan_setevent(mypan,_VAR(3),_VAR(2),(EVENT)options);


Just make a normal function (void myfunc()). then pass its
name with (EVENT) typecast in front of it. Ooopz thats the
last arg, sorry.. first one is the panel (duh) second is
type, hit the manual for this one, type 3 is button, second
one is the element number in the order they were created.


So the first one sez "set mypans event for the FIRST element
of TYPE button to the function cya()"


See? Not so hard.

A word about vars: Anytime you start mixing in a dll or api
or lib or sdk or whatever that has custom datatypes (like the
almight var) you will need to be careful with your math. Just
keep in mind that doing this wrong will give you the gremlin
results (wacky numbers). So if you use _VAR() on something
and the numbers go crazy, then dont use _VAR on it there.


Sometimes I even have to assign with = _VAR(something) then
later do the math on the thing and then mything =
_VAR(mything); to get the result to show in my
digits again after the calculations are done on it so my
debug panel works. its wacky, its nuts, it can be figured out
if you jiggle the handle.


Hope this helps. Oh heres the whole code for the program
these examples are from. I changed the name of Mainmenu to
mypan for the example code but the rest is just as it is
here. ignore the sound stuff.. still messin with that.


Code:
// Include the usual Windows headers
#define WIN32_LEAN_AND_MEAN		
#include <windows.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>

// Include the engine data types, variables, and functions
#include "adll.h"

BMAP *arrow;
BMAP *MainMenuBmap;
BMAP *QuitBmap;
BMAP *OptionsBmap;
BMAP *OptionsMainPnlBmap;
PANEL *MainMenu;
PANEL *Options;
SOUND *music;
var musichndl;

void options();
void optionsback();
void cya();
void res_1280_full();
void res_1024_full();
void res_1024_win();
//void sndlvl();

//void sndlvl() {}
	

void res_1280_full() {
	
	video_switch (_VAR(7),_VAR(0),_VAR(2));
	engine_frame();
	video_switch (_VAR(9),_VAR(32),_VAR(1));
	engine_frame();
	
}

void res_1024_full() {
	
	video_switch (_VAR(7),_VAR(0),_VAR(2));
	engine_frame();
	video_switch (_VAR(8),_VAR(32),_VAR(1));
	engine_frame();
	
}
void res_1024_win() {
	
	video_switch (_VAR(7),_VAR(0),_VAR(2));
	engine_frame();
	video_switch (_VAR(8),_VAR(32),_VAR(2));
	engine_frame();
	
}void cya() {
	sys_exit("");
}


void optionsback() {
	pan_setevent(MainMenu,_VAR(3),_VAR(2),(EVENT)options);

}

void options() {
		
		OptionsMainPnlBmap = bmap_create("OptonsMainPnl.bmp");
		Options = pan_create("bmap=OptionsMainPnl.bmp;\
							 digits(400,80,\"VIDEO OPTIONS\",\"Arial#24bi\",0,0);\
							 button_radio(100, 200, rdobtnon.jpg, rdobtnoff.jpg, rdobtnover.jpg, NULL, res_1280_win, NULL);\
							 digits(145,200,\"1280 X 1024 Full Screen\",\"Arial#24bi\",0,0);\
							 button_radio(100, 250, rdobtnon.jpg, rdobtnoff.jpg, rdobtnover.jpg, NULL, res_1280_full, NULL);\
							 digits(145,250,\"1024 X 768 Windowed\",\"Arial#24bi\",0,0);\
							 button_radio(100, 300, rdobtnon.jpg, rdobtnoff.jpg, rdobtnover.jpg, NULL, res_1024_win, NULL);\
							 digits(145,300,\"1024 X 768 Full Screen\",\"Arial#24bi\",0,0);\
							 digits(400,400,\"SOUND OPTIONS\"\"Arial#24bi\",0,0);\
							 hslider(145, 500, 200, sndsldr.jpg, 0, 100, master_vol);\
							 digits(150,450,\"Master Volume\",\"Arial#24bi\",0,0);",_VAR(2));
		pan_setevent(MainMenu,_VAR(3),_VAR(2),(EVENT)optionsback);
		
		Options->pos_x = _VAR(200);
		Options->pos_y = _VAR(10);
		Options->scale_x = _VAR(.78125);
		Options->scale_y = _VAR(.78125);
		Options->flags |= VISIBLE;
		Options->flags |= OVERLAY;
		pan_setevent(Options,_VAR(3),_VAR(1),(EVENT)res_1280_full);
		engine_frame();
		pan_setevent(Options,_VAR(3),_VAR(2),(EVENT)res_1024_win);
		engine_frame();
		pan_setevent(Options,_VAR(3),_VAR(3),(EVENT)res_1024_full);
		engine_frame();
}



int APIENTRY WinMain(HINSTANCE hInstance,	// application instance handle
                     HINSTANCE hPrevInstance, // always zero
                     LPSTR    lpCmdLine,	// application command line
                     int       nShowCmd)	// window flags
{

	ENGINE_VARS *ev = engine_open(NULL);
	if (!ev) return  1; //acknex.dll not found
	//engine_open("");
	add_folder("images");
	add_folder("music");
// The engine_open() function initializes the GameStudio engine,
// and accepts a command line string with the name of a script, 
// or an entity file to be loaded upon initialization. For instance, 
// we could hand over the application command line (char*)lpCmdLine.
// We could also pass options to start in client or server mode.
// Here we're just loading the arena level. 
	level_load("");
	engine_frame();
	
	//Initialize The Graphics Environment
	SETV(fps_max,60);
	video_set(_VAR(1280),_VAR(1024),_VAR(32),_VAR(1));
	arrow = bmap_create("brokenarrow.pcx");
	ev->mouse_map = arrow;
	v(mouse_mode)=2;
	music = snd_create("blackno1.mp3");
	musichndl = snd_play(music, 100, 0);
	//while (snd_playing(musichndl)) { engine_frame(); };
	
	
	
	
	




// After loading a level we're ready to render it. The engine_frame() 
// function executes the scripts and physics, and renders the 
// current camera position to the screen if a level is loaded. 
// The function returns zero when a script calls exit() or an Abort 
// button is clicked. 
	v(camera).z = _VAR(400);
	QuitBmap = bmap_create("quit.jpg");
	MainMenuBmap = bmap_create("MainMenuBmap.jpg");
	OptionsBmap = bmap_create("OptonsBmap.jpg");
	MainMenu = pan_create("bmap=MainMenuBmap.jpg;button(10,10,Quit.jpg,Quit.jpg,Quit.jpg,NULL,NULL,NULL);button(10,80,OptionsBmap.jpg,OptionsBmap.jpg,OptionsBmap.jpg,NULL,NULL,NULL);",_VAR(1));
	MainMenu->pos_x=0;
	MainMenu->pos_y=0;
	MainMenu->scale_x = _VAR((float)v(screen_size).x / bmap_width(MainMenu->bmap));
	MainMenu->scale_y = _VAR((float)v(screen_size).y / bmap_height(MainMenu->bmap));
	MainMenu->flags |= OVERLAY;
	

	pan_setevent(MainMenu,_VAR(3),_VAR(1),(EVENT)cya);
	pan_setevent(MainMenu,_VAR(3),_VAR(2),(EVENT)options);
	
	while (engine_frame()){
		v(camera).z += (v(key_e ) - v(key_c)) * v(time_step); 
		v(camera).x += (v(key_w ) - v(key_s)) * v(time_step); 
		v(camera).y += (v(key_a ) - v(key_d)) * v(time_step); 
		v(camera).pan += _VAR((v(key_force).x) * 9 * v(time_step));
		v(camera).tilt += _VAR((v(key_force).y) * 6 * v(time_step));
		v(mouse_pos).x = v(mouse_cursor).x;
		v(mouse_pos).y = v(mouse_cursor).y;
		if (v(key_esc)) {
			if ((MainMenu->flags & VISIBLE)) {
				MainMenu->flags &= ~VISIBLE;
				if((Options->flags & VISIBLE)) {
					Options->flags &= ~VISIBLE;
				}
				while(v(key_esc)) {engine_frame();};
		} else {
				MainMenu->flags |= VISIBLE;
				while(v(key_esc)) {engine_frame();};
			}
		}						
		
	};
	

// For rendering the level, we are just repeating engine_frame() until 
// a 0 value is returned. This is normally our main loop, all 
// the interesting stuff happens here. However, when an entity file 
// name is given for engine_open(), the engine acts as a viewer.
// A default walkthrough movement is activated and we don't want 
// to do anything else at the moment.

	

// Someone pressed the Exit icon. Our application is about to end. 
// Before that, the engine must be closed by engine_close().
	engine_close();
	return 0;	
};



Last edited by Neurosys; 09/02/08 21:23.

See more code and crap @ www.neuroticnetworks.com