Menu: IRC based Chat is now completely implemented using QuakeC. It already works quite well but will need a lot more testing!

This commit is contained in:
Marco Cawthorne 2020-06-30 17:14:06 +02:00
parent d8f9c545a6
commit 081d541e9e
11 changed files with 465 additions and 98 deletions

View file

@ -18,6 +18,8 @@ games:
cd server/rewolf && $(MAKE)
cd client/gearbox && $(MAKE)
cd server/gearbox && $(MAKE)
# cd client/wastes && $(MAKE)
#cd server/wastes && $(MAKE)
mods:
cd client/cstrike && $(MAKE)

View file

@ -55,6 +55,7 @@ CSQC_Init(float apilevel, string enginename, float engineversion)
registercommand("+showscores");
registercommand("-showscores");
registercommand("buildcubemaps");
registercommand("_fnchat_msg");
precache_model("sprites/640_pain.spr");
precache_model("sprites/crosshairs.spr");
@ -656,6 +657,9 @@ CSQC_ConsoleCommand(string sCMD)
case "slot10":
HUD_SlotSelect(9);
break;
case "_fnchat_msg":
CSQC_Parse_Print(argv(1), PRINT_CHAT);
break;
default:
return Game_ConsoleCommand();
}

View file

@ -24,7 +24,8 @@ vector col_refresh_title;
vector col_refresh_text;
vector col_refresh_bg;
string Colors_RGB8_to_HEX(vector color)
string
Colors_RGB8_to_HEX(vector color)
{
string out = "^x";
@ -59,6 +60,12 @@ string Colors_RGB8_to_HEX(vector color)
return out;
}
string
Colors_RGB255_to_HEX(vector color)
{
return Colors_RGB8_to_HEX(color / 255);
}
void Colors_Init(void)
{
int c;

View file

@ -163,6 +163,9 @@ m_draw(vector screensize)
Menu_AutoScale();
}
/* to prevent TCP timeouts */
menu_chatrooms_keepalive();
if (!g_active) {
return;
}

View file

@ -22,35 +22,255 @@ CMainButton cr_btnListRooms;
CMainButton cr_btnSearch;
CMainButton cr_btnServers;
CMainButton cr_btnDone;
CScrollbar cr_sbHistory;
CTextBuffer cr_lbHistory;
CListBox cr_lbUsers;
CDialog cr_dgConnect;
void crl_addroom(string);
void crl_clearrooms(void);
void crl_roomsdone(void);
/* Ladies and gentlemen, here's the very first IRC client written purely
* in QuakeC. I have no regrets. */
typedef struct
{
string cur_tab;
string show_tab;
int channel_grabbed;
float user_refresh;
float timer;
} ircsession_t;
ircsession_t g_irc;
string m_strChannel;
string m_strTopic;
int m_iStatus;
int m_iReady;
string m_strNick;
} ircroom_t;
ircroom_t g_ircroom;
tcpinfo_t tcp_irc;
var string g_crIRCchannel;
var int g_iIRCActive;
/* we've got a Internet servers button on here, so we require these */
/* we've got a Internet servers button in this menu therefore */
void(void) cr_btnservers_start;
void
cr_print(string buffer)
{
print(sprintf("%s\n", buffer));
cr_lbHistory.Insert(buffer);
}
/* tempstrings and fwrite == not a good idea. we need to manually copy all
* the chars. sigh.
* for static strings however, we can just use TCP_Send as is. */
void
irc_send(string msg)
{
string out;
out = (string)memalloc(strlen(msg));
for (float i = 0; i < strlen(msg); i++)
out[i] = str2chr(msg, i);
TCP_Send(&tcp_irc, out);
}
void
irc_adduser(string user)
{
int present = FALSE;
user = strreplace("@", "", user);
user = strreplace("+", "", user);
for (int i = 0; i < cr_lbUsers.GetCount(); i++) {
if (cr_lbUsers.GetItem(i) == user) {
present = TRUE;
}
}
if (present == FALSE) {
cr_lbUsers.AddEntry(user);
}
}
void
irc_remuser(string user)
{
user = strreplace("@", "", user);
user = strreplace("+", "", user);
for (int i = 0; i < cr_lbUsers.GetCount(); i++) {
if (cr_lbUsers.GetItem(i) == user) {
int last = cr_lbUsers.GetCount()-1;
cr_lbUsers.SetItem(i, cr_lbUsers.GetItem(last));
cr_lbUsers.DelEntry(last);
}
}
}
void
irc_clear(void)
{
cr_lbUsers.Clear();
cr_lbHistory.Clear();
g_ircroom.m_iReady = 0;
}
void
irc_autoname(void)
{
g_ircroom.m_strNick = sprintf("Guest%d", rint(random(0,9999)));
irc_send(sprintf("NICK %s\n", g_ircroom.m_strNick));
}
/* irc processing functions */
void
irc_receive(string buffer)
{
int l;
string src;
if (!buffer)
return;
l = tokenize(buffer);
/* IRC tokenization goes like this:
[SOURCE] [CODE] [TARGET] [DATA]
example would be something like:
A message 'test' from eukara to channel #debug:
:eukara!eukara@irc.won.net PRIVMSG #debug :test
A message 'hello' from eukara to user Frank:
:eukara!eukara@irc.won.net PRIVMSG Frank :hello
*/
print(buffer);
print("\n");
if (substring(buffer, 0, 4) == "PING") {
irc_send(sprintf("PONG :%s\n", substring(buffer, 6, -1)));
return;
}
/* define the source */
src = substring(argv(1), 0, strstrofs(argv(1), "!"));
if (src == "")
src = "Server";
/* process the code */
switch (argv(2)) {
case "PRIVMSG": /* a message */
cr_print(
sprintf("%s<%s>%s %s",
Colors_RGB255_to_HEX([192,192,192]),
src,
Colors_RGB255_to_HEX([255,255,255]),
substring(buffer, strstrofs(buffer, ":", 1) + 1, -1)
)
);
localcmd(sprintf("_fnchat_msg \"[%s] %s: %s\"\n", g_ircroom.m_strChannel, src, argv(2)));
break;
case "321":
crl_clearrooms();
break;
case "322":
crl_addroom(argv(4));
break;
case "323":
crl_roomsdone();
break;
case "332": /* topic upon joining channel */
case "TOPIC": /* topic change */
tokenizebyseparator(buffer, ":");
tokenizebyseparator(argv(2), " - ");
g_ircroom.m_strTopic = argv(0);
break;
case "NOTICE": /* server notice */
break;
case "JOIN": /* a player joined */
if (src == g_ircroom.m_strNick) {
cr_print(sprintf("You are now speaking in %s", g_ircroom.m_strChannel));
break;
}
irc_adduser(src);
cr_print(sprintf("%s joined the chat.", src));
break;
case "QUIT": /* a player quit */
case "PART": /* a player left the channel */
if (src == g_ircroom.m_strNick)
break;
irc_remuser(src);
cr_print(sprintf("%s left the chat.", src));
break;
case "353": /* channel user list */
tokenizebyseparator(buffer, ":");
int c = tokenize(argv(2));
for (int i = 0; i < c; i++)
irc_adduser(argv(i));
break;
case "366": /* end of user list */
g_ircroom.m_iReady = 1;
break;
case "431": /* no nickname given */
case "432": /* erroneus nickname */
case "433": /* nick already in use */
irc_autoname();
break;
case "475": /* password protected/wrong */
cr_print(sprintf("%s is a password protected channel. Access denied.", g_ircroom.m_strChannel));
g_ircroom.m_iReady = 1;
break;
case "376": /* logging done */
irc_send(sprintf("JOIN %s\n", g_ircroom.m_strChannel));
break;
case "NICK": /* nick changed */
tokenizebyseparator(buffer, ":");
for (int i = 0; i < cr_lbUsers.GetCount(); i++) {
if (cr_lbUsers.GetItem(i) == src) {
cr_lbUsers.SetItem(i, argv(2));
break;
}
}
cr_print(sprintf("%s is now known as %s", src, argv(2)));
}
}
/* initial connect */
void cr_makeconnection(void)
{
int i;
i = TCP_Connect(&tcp_irc, "tcp://irc.frag-net.com:6667");
g_ircroom.m_strChannel = sprintf("#%s", cvar_string("game"));
TCP_Send(&tcp_irc, "USER guest fn irc.won.net :Player\n");
/* attempt to force our nickname to be the same as in-game.
* we'll probably have to keep track of event 433 though. */
irc_send(sprintf("NICK %s\n", cvar_string("name")));
}
/* when ENTER is pressed on the message box */
void cr_input_enter(string text)
{
if (!text)
return;
cr_print(
sprintf("%s<%s>%s %s",
Colors_RGB255_to_HEX([128,100,0]),
g_ircroom.m_strNick,
Colors_RGB255_to_HEX([180,128,55]),
text
)
);
irc_send(sprintf("PRIVMSG %s :%s\n", g_ircroom.m_strChannel, text));
cr_tbInput.SetText("");
}
void cr_closeconnection(void)
{
if (!g_iIRCActive) {
return;
}
/* how is this meant to work? neither do! */
con_printf(g_irc.show_tab, "/clear\n");
con_getset(g_irc.show_tab, "clear");
localcmd("irc /disconnect irc.frag-net.com:6667\n");
g_iIRCActive = FALSE;
TCP_Disconnect(&tcp_irc);
}
void cr_btndone_start(void)
@ -73,6 +293,9 @@ void cr_btnlistrooms_start(void)
static void cr_btnlistrooms_end(void) {
g_menupage = PAGE_CHATROOMS_LIST;
}
irc_send("LIST\n");
localsound("../media/launch_dnmenu1.wav");
header.SetStartEndPos(30,70,45,45);
header.SetStartEndSize(156,26,460,80);
@ -85,27 +308,9 @@ void cr_btnlistrooms_start(void)
/* 'Done' button */
void cr_btnservers_prepare(void)
{
//cr_closeconnection();
cr_btnservers_start();
}
/* initial connect */
void cr_makeconnection(void)
{
localcmd("plug_load irc\n");
localcmd(sprintf("seta irc_nick %.9s\n", cvar_string("name")));
localcmd(sprintf("seta irc_altnick %.5s%.4d\n", cvar_string("name"), rint(random(1000,9999))));
g_crIRCchannel = "#lobby";
localcmd(sprintf("irc /open irc.frag-net.com:6667 %s\n", g_crIRCchannel));
}
/* when ENTER is pressed on the message box */
void cr_input_enter(string text)
{
localcmd(sprintf("irc /msg %s %s\n", g_crIRCchannel, text));
cr_tbInput.SetText("");
}
void menu_chatrooms_init(void)
{
fn_chatrooms = spawn(CWidget);
@ -150,6 +355,18 @@ void menu_chatrooms_init(void)
cr_frUsers.SetSize(128,337);
Widget_Add(fn_chatrooms, cr_frUsers);
cr_lbHistory = spawn(CTextBuffer);
cr_lbHistory.SetPos(33,104);
cr_lbHistory.SetSize(450,331);
//cr_lbHistory.SetChanged(inet_lb_clicked);
Widget_Add(fn_chatrooms, cr_lbHistory);
/*cr_sbHistory = spawn(CScrollbar);
cr_sbHistory.SetPos(486,101);
cr_sbHistory.SetHeight(337);
cr_sbHistory.SetCallback(cr_sbhistory_changed);
Widget_Add(fn_chatrooms, cr_sbHistory);*/
cr_lbUsers = spawn(CListBox);
cr_lbUsers.SetPos(505,104);
cr_lbUsers.SetSize(122,331);
@ -160,75 +377,50 @@ void menu_chatrooms_init(void)
string menu_chatrooms_gettopic(void)
{
string t = cvar_string("irc_currenttopic");
if (t == "") {
return "No topic";
} else {
tokenizebyseparator(t, " - "); /* strip long descriptions */
return argv(0);
}
if (g_ircroom.m_strTopic)
return g_ircroom.m_strTopic;
else
return "No topic.";
}
void menu_chatrooms_draw(void)
{
int tab_id;
string tmp;
static float timeout;
Widget_Draw(fn_chatrooms);
drawpic([g_menuofs[0]+550,g_menuofs[1]+10], "gfx/shell/fragnet",[80,80], [1,1,1], 1.0f, 0);
/* we need to figure out which console buffer belongs to our chat. */
g_irc.show_tab = g_irc.cur_tab;
for (tmp = "", tab_id = 0; tmp; tmp = con_getset(tmp, "next")) {
if (substring(tmp, 0, 3) == "IRC") {
con_getset(tmp, "hidden", "1");
string title = con_getset(tmp, "title");
}
}
if not (g_irc.channel_grabbed)
for (tmp = ""; tmp; tmp = con_getset(tmp, "next")) {
if (substring(tmp, 0, 3) == "IRC" && substring(tmp, -strlen(g_crIRCchannel), -1) == g_crIRCchannel) {
g_irc.show_tab = tmp;
g_irc.channel_grabbed = TRUE;
break;
}
}
if (!g_irc.show_tab) {
for (tmp = ""; tmp; tmp = con_getset(tmp, "next")) {
if (substring(tmp, 0, 3) == "IRC" && substring(tmp, -1, -1) == ":") {
g_irc.show_tab = tmp;
break;
}
}
}
g_irc.cur_tab = g_irc.show_tab;
/* establish the connection if nothing is found */
if (!g_iIRCActive && !g_irc.show_tab) {
if (!g_ircroom.m_iStatus) {
cr_makeconnection();
g_iIRCActive = TRUE;
g_irc.timer = 10.0f;
timeout = 10.0f;
g_ircroom.m_iStatus = TRUE;
}
/* draw the irc-log buffer when ready */
if (g_irc.show_tab) {
if (TCP_GetState(&tcp_irc) == STATE_CONNECTED) {
drawsetcliparea(g_menuofs[0] + 33, g_menuofs[1] + 104, 450,331);
con_draw(g_irc.show_tab, [g_menuofs[0] + 33, g_menuofs[1] + 104], [450,331], 12);
drawresetcliparea();
} else {
} else if (TCP_GetState(&tcp_irc) == STATE_CONNECTING) {
/* connecting... dialog */
cr_dgConnect.Draw();
WField_Static(162, 180, m_reslbl[IDS_WON_LOGIN], 320, 260,
col_prompt_text, 1.0f, 2, font_label_p);
WField_Static(162, 280, sprintf(m_reslbl[IDS_CHAT_JOIN], g_crIRCchannel), 320, 260,
WField_Static(162, 280, sprintf(m_reslbl[IDS_CHAT_JOIN], g_ircroom.m_strChannel), 320, 260,
col_prompt_title, 1.0f, 2, font_label_p);
g_irc.timer -= frametime;
if (g_irc.timer < 0.0) {
timeout -= frametime;
if (timeout < 0.0) {
cr_btndone_start();
}
}
if (!g_ircroom.m_iReady) {
cr_dgConnect.Draw();
WField_Static(162, 180, "Connected to Frag-Net", 320, 260,
col_prompt_text, 1.0f, 2, font_label_p);
WField_Static(162, 280, sprintf("Loading room info for %s", g_ircroom.m_strChannel), 320, 260,
col_prompt_title, 1.0f, 2, font_label_p);
}
/* draw the labels */
WLabel_Static(30, 38, m_reslbl[IDS_MULTI_CHATROOMCAPTION], 22, 22, [0.4,0.4,0.4],
1.0f, 0, font_label_p);
@ -236,17 +428,14 @@ void menu_chatrooms_draw(void)
1.0f, 0, font_label_p);
WLabel_Static(30, 446, m_reslbl[IDS_CHAT_PROMPT], 12, 12, [1,1,1],
1.0f, 0, font_arial);
}
/* update the user list periodically */
if (g_irc.user_refresh > time) {
return;
}
int c = tokenize(cvar_string("irc_currentusers"));
g_irc.user_refresh = time + 2.0f;
cr_lbUsers.Clear();
for (int i = 0; i < c; i++) {
cr_lbUsers.AddEntry(argv(i));
}
/* this function is run, even when the menu is visibly closed. we need to keep
* the TCP session with the IRC server alive afterall */
void menu_chatrooms_keepalive(void)
{
TCP_Frame(&tcp_irc);
irc_receive(TCP_Receive(&tcp_irc));
}
void menu_chatrooms_input(float evtype, float scanx, float chary, float devid)

View file

@ -19,11 +19,47 @@ CMainButton crl_btnJoin;
CMainButton crl_btnCreateRoom;
CMainButton crl_btnCancel;
var string g_crIRCchannel;
CFrame crl_frRooms;
CListBox crl_lbRooms;
CScrollbar crl_sbRooms;
var int crl_iLoading;
void
crl_addroom(string room)
{
/* skip this thing. */
if (room == "&SERVER")
return;
crl_lbRooms.AddEntry(room);
crl_sbRooms.SetMax(crl_lbRooms.GetCount());
}
void
crl_clearrooms(void)
{
crl_lbRooms.Clear();
crl_sbRooms.SetMax(0);
crl_iLoading = TRUE;
}
void
crl_roomsdone(void)
{
crl_iLoading = FALSE;
}
void crl_btnjoin_start(void)
{
static void cr_btncancel_end(void) {
/* part the current channel, clear textbuffer and user list */
irc_send(sprintf("PART %s\n", g_ircroom.m_strChannel));
irc_clear();
/* set the new current channel, attempt to join */
g_ircroom.m_strChannel = crl_lbRooms.GetSelectedItem();
irc_send(sprintf("JOIN %s\n", g_ircroom.m_strChannel));
g_menupage = PAGE_CHATROOMS;
}
localsound("../media/launch_dnmenu1.wav");
@ -49,6 +85,11 @@ void crl_btncancel_start(void)
header.SetExecute(crl_btncancel_end);
}
void crl_rooms_changed(int val)
{
crl_lbRooms.SetScroll(val);
}
void menu_chatroomslist_init(void)
{
fn_chatroomslist = spawn(CWidget);
@ -63,6 +104,22 @@ void menu_chatroomslist_init(void)
//crl_btnCreateRoom.SetExecute(cr_btncancel_start);
crl_btnCreateRoom.SetPos(50,172);
Widget_Add(fn_chatroomslist, crl_btnCreateRoom);
crl_frRooms = spawn(CFrame);
crl_frRooms.SetPos(382,172);
crl_frRooms.SetSize(208,288);
Widget_Add(fn_chatroomslist, crl_frRooms);
crl_lbRooms = spawn(CListBox);
crl_lbRooms.SetPos(384,175);
crl_lbRooms.SetSize(202-16,282);
Widget_Add(fn_chatroomslist, crl_lbRooms);
crl_sbRooms = spawn(CScrollbar);
crl_sbRooms.SetPos(571,175);
crl_sbRooms.SetHeight(282);
crl_sbRooms.SetCallback(crl_rooms_changed);
Widget_Add(fn_chatroomslist, crl_sbRooms);
crl_btnCancel = spawn(CMainButton);
crl_btnCancel.SetImage(BTN_CANCEL);
@ -76,6 +133,14 @@ void menu_chatroomslist_draw(void)
Widget_Draw(fn_chatroomslist);
drawpic([g_menuofs[0]+45,g_menuofs[1]+45], g_bmp[HEAD_ROOMS],[460,80], [1,1,1], 1.0f, 1);
drawpic([g_menuofs[0]+550,g_menuofs[1]+10], "gfx/shell/fragnet",[80,80], [1,1,1], 1.0f, 0);
if (crl_iLoading) {
cr_dgConnect.Draw();
WField_Static(162, 180, "Connected to Frag-Net", 320, 260,
col_prompt_text, 1.0f, 2, font_label_p);
WField_Static(162, 280, "Retrieving Room List...", 320, 260,
col_prompt_title, 1.0f, 2, font_label_p);
}
}
void menu_chatroomslist_input(float evtype, float scanx, float chary, float devid)

View file

@ -42,7 +42,6 @@ void create_btnok_start(void)
localcmd(sprintf("map %s\n", startmap));
g_menupage = PAGE_LANGAMES;
}
/* Strip .bsp extension before submitting */
startmap = substring(create_lbMaps.GetSelectedItem(), 0, -5);

View file

@ -29,6 +29,7 @@ void createinet_btnok_start(void)
localcmd(sprintf("password %s\n", create_tbPassword.m_text));
localcmd(sprintf("map %s\n", startmap));
g_menupage = PAGE_INTERNETGAMES;
cr_input_enter(sprintf("ACTION is now hosting '%s' on the map %s\n", create_tbHostname.m_text, startmap));
}
/* Strip .bsp extension before submitting */

View file

@ -25,6 +25,7 @@ w_frame.cpp
w_label.cpp
w_combobox.cpp
w_listbox.cpp
w_textbuffer.cpp
w_servers.cpp
w_mainbutton.cpp
w_modetab.cpp

View file

@ -29,7 +29,8 @@ class CListBox:CWidget
virtual void(void) Draw;
virtual void(float type, float x, float y, float devid) Input;
virtual void(string m) AddEntry;
virtual void(string) AddEntry;
virtual void(int) DelEntry;
virtual void(void) Clear;
virtual void(int, int) SetSize;
virtual void(void(int val) func) SetChanged;
@ -62,8 +63,10 @@ void CListBox::Draw(void)
drawfill([g_menuofs[0] + pos[0] - 2, g_menuofs[1] + pos[1] - 2], [m_size[0], 15],
[84/255,45/255,0], 1.0f);
}
drawsetcliparea(g_menuofs[0] + m_x, g_menuofs[1] + m_y, m_size[0], m_size[1]);
WLabel_Static(pos[0], pos[1], m_entries[i], 12, 12, [1,0.5,0.1],
1.0f, 0, font_label);
drawresetcliparea();
pos[1] += 15;
}
}
@ -101,6 +104,14 @@ void CListBox::AddEntry(string m)
}
}
void CListBox::DelEntry(int i)
{
if (m_entries[i] != __NULL__) {
m_entries[i] = __NULL__;
m_count--;
}
}
void CListBox::Clear(void)
{
for (int i = 0; i < LB_MAX_ENTRIES; i++) {

View file

@ -0,0 +1,85 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#define TB_MAX_ENTRIES 128
class CTextBuffer:CWidget
{
int m_size[2];
string m_entries[TB_MAX_ENTRIES];
virtual void(int val) m_execute = 0;
void(void) CTextBuffer;
virtual void(void) Draw;
virtual void(float type, float x, float y, float devid) Input;
virtual void(string m) Insert;
virtual void(void) Clear;
virtual void(int, int) SetSize;
};
void CTextBuffer::CTextBuffer(void)
{
}
void CTextBuffer::Draw(void)
{
int visible;
int pos[2];
drawfill([g_menuofs[0] + m_x, g_menuofs[1] + m_y], [m_size[0], m_size[1]],
[0,0,0], 1.0f);
visible = floor(m_size[1] / 15);
pos[0] = m_x + 2;
pos[1] = m_y + 2 + ((visible - 1) * 15);
for (int i = (TB_MAX_ENTRIES - 1); i > (TB_MAX_ENTRIES - visible) - 1; i--) {
drawsetcliparea(g_menuofs[0] + m_x, g_menuofs[1] + m_y, m_size[0], m_size[1]);
WLabel_Static(pos[0], pos[1], m_entries[i], 12, 12, [1,1,1],
1.0f, 0, font_label);
drawresetcliparea();
pos[1] -= 15;
}
}
void CTextBuffer::Input(float type, float x, float y, float devid)
{
}
void CTextBuffer::Insert(string m)
{
for (int i = 0; i < TB_MAX_ENTRIES; i++) {
if (i == TB_MAX_ENTRIES - 1) {
m_entries[i] = m;
} else {
m_entries[i] = m_entries[i+1];
}
}
}
void CTextBuffer::Clear(void)
{
for (int i = 0; i < TB_MAX_ENTRIES; i++) {
m_entries[i] = __NULL__;
}
}
void CTextBuffer::SetSize(int w, int h)
{
m_size[0] = w;
m_size[1] = h;
}