Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Quick question on newlines..

This thread is locked; no one can reply to it. rss feed Print
 1   2 
Quick question on newlines..
blargmob
Member #8,356
February 2007
avatar

Is there a newline sequence that is supported for allegro's text output methods? It seems that \n dudn't work. ???

---
"No amount of prayer would have produced the computers you use to spread your nonsense." Arthur Kalliokoski

kazzmir
Member #1,786
December 2001
avatar

no

blargmob
Member #8,356
February 2007
avatar

Dang, thanks anyways..

---
"No amount of prayer would have produced the computers you use to spread your nonsense." Arthur Kalliokoski

Neil Black
Member #7,867
October 2006
avatar

There isn't? That seems kinda not cool. Brings to mind the fact that Allegro makes cin unusable but offers no replacement...

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Write a wrapper function for multiline text output. Give it the starting string including newlines , parse it into lines , use function parameters for the starting position , justification , vertical line spacing and text color for foreground/background and use the allegro text functions to display each line in the proper placement. ;)

Timorg
Member #2,028
March 2002

Well I don't see what std::cin has to do with text output. :P

And std::cout still works, it outputs data to the console if one is available, otherwise the output is hidden. as with std::cin, it should read from the console, but if is a blocking function, so your game will pause while it gets input.

I am off to check that... -Tim

Edit: It definitely applies to linux, buggering off to windows to test mingw :)
Edit2: It works fine under windows too.

Under both it spawns a console when you call std::cin.

____________________________________________________________________________________________
"c is much better than c++ if you don't need OOP simply because it's smaller and requires less load time." - alethiophile
OMG my sides are hurting from laughing so hard... :D

Neil Black
Member #7,867
October 2006
avatar

It has nothing to do with text output, it's just something that's on my very short list of complaints about allegro. This thread lengthened that list to two things.

Timorg
Member #2,028
March 2002

A way to implement Edgar Reynaldo's idea could be.

You could scan the string, when you find a newline, replace it with '\0', output the string, move your pointer to the character after the newline, move down 10 pixels (with the default font) and repeat til you reach the '\0'. Then run back along the string putting back all the newlines.

If you complain enough, someone will implement it for you, as its quite trivial. If I get bored later, I might even bother.

-Tim

____________________________________________________________________________________________
"c is much better than c++ if you don't need OOP simply because it's smaller and requires less load time." - alethiophile
OMG my sides are hurting from laughing so hard... :D

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Thomas Harte
Member #33
April 2000
avatar

Quote:

I think Timorg's improvement would be faster and pretty easy too.

There's absolutely no way you can justify not using the text_height function though.

OICW
Member #4,069
November 2003
avatar

So the multiline output is solved. Now as far as input goes you can use this.

[My website][CppReference][Pixelate][Allegators worldwide][Who's online]
"Final Fantasy XIV, I feel that anything I could say will be repeating myself, so I'm just gonna express my feelings with a strangled noise from the back of my throat. Graaarghhhh..." - Yahtzee
"Uhm... this is a.cc. Did you honestly think this thread WOULDN'T be derailed and ruined?" - BAF
"You can discuss it, you can dislike it, you can disagree with it, but that's all what you can do with it"

Audric
Member #907
January 2001

Just a little warning on Timorg's version: It's extremely efficient but you had better document on your function that it modifies the string it received as input.
(If you pass static data that is normally in 'const' area, a touchy OS or a memory protector is allowed to complain. loudly.)

OICW
Member #4,069
November 2003
avatar

That depends whether you are doing those operations on the input string or you're copying it to some teporary string.

[My website][CppReference][Pixelate][Allegators worldwide][Who's online]
"Final Fantasy XIV, I feel that anything I could say will be repeating myself, so I'm just gonna express my feelings with a strangled noise from the back of my throat. Graaarghhhh..." - Yahtzee
"Uhm... this is a.cc. Did you honestly think this thread WOULDN'T be derailed and ruined?" - BAF
"You can discuss it, you can dislike it, you can disagree with it, but that's all what you can do with it"

Timorg
Member #2,028
March 2002

1#include <allegro.h>
2 
3void textout_ml_ex(BITMAP *bmp, const FONT *f, const char *s, int x, int y, int color, int bg)
4{
5 const char *start;
6 char *p, *line_start;
7 int cy;
8 
9 start = s;
10 p = (char *)s;
11 line_start = (char *)s;
12 cy = y;
13 
14 while (1)
15 {
16 if ((*p) == '\0')
17 break;
18 if ((*p) == '\n')
19 {
20 (*p) = '\0';
21 textout_ex(bmp, f, line_start, x, cy, color, bg);
22 line_start = p + 1;
23 cy += text_height(f);
24 }
25 p++;
26 }
27 
28 textout_ex(bmp, f, line_start, x, cy, color, bg);
29 
30 while(p != start)
31 {
32 p--;
33 if ((*p) == '\0')
34 (*p) = '\n';
35 }
36}
37 
38int main()
39{
40 allegro_init();
41 install_keyboard();
42 set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);
43 
44 
45 char str[] = "This is a big long string\nit has quite a few lines of text\nhere is one\nhere is another";
46 
47 textout_ex(screen, font, str, 0, 0, makecol(255, 255, 255), -1);
48 textout_ml_ex(screen, font, str, 0, 20, makecol(255, 255, 255), -1);
49 
50 readkey();
51 set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
52 
53 return 0;
54}
55END_OF_MAIN()

I got bored, and as with what Audric was saying, this code isn't thread safe, if you try to use the string elsewhere at the same time, you will get strange things happening.

As for the other part of what Audric suggested, if your using STL strings, and call std::string.c_str() and pass it to the function, it depends on the implementation of STL to what will happen. Could be fine or yet again strange things might happen.

Thomas Harte: I didn't mention text_height function, cause I was trying to keep the example simple.

-------------

Edit:

I got bored again, here is a c++ implementation that uses std::string

1#include <allegro.h>
2#include <string>
3 
4void textout_ml_ex(BITMAP *bmp, const FONT *f, const std::string s, int x, int y, int color, int bg)
5{
6 std::string leftovers = s;
7 int cy = y;
8 
9 while (1)
10 {
11 int count = leftovers.find("\n");
12 if (count == -1)
13 break;
14 std::string current = leftovers.substr(0, count);
15 leftovers = leftovers.substr(count + 1);
16 textout_ex(bmp, f, current.c_str(), x, cy, color, bg);
17 cy += text_height(f);
18 }
19 textout_ex(bmp, f, leftovers.c_str(), x, cy, color, bg);
20}
21 
22int main()
23{
24 allegro_init();
25 install_keyboard();
26 set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);
27 
28 
29 std::string str("This is a big long string\nit has quite a few lines of text\nhere is one\nhere is another");
30 
31 textout_ex(screen, font, str.c_str(), 0, 0, makecol(255, 255, 255), -1);
32 textout_ml_ex(screen, font, str, 0, 20, makecol(255, 255, 255), -1);
33 
34 readkey();
35 set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
36 
37 return 0;
38}
39END_OF_MAIN()

This is thread safe, and you can pass a null terminated string into it and it will work fine. :)

____________________________________________________________________________________________
"c is much better than c++ if you don't need OOP simply because it's smaller and requires less load time." - alethiophile
OMG my sides are hurting from laughing so hard... :D

Audric
Member #907
January 2001

I like the cleverness of the first solution anyway. My own hack would NOT have changed back the '\0' to '\n' :) Thread-proofness is certainly never an issue here (drawing to bitmap = job for one thread), and as long as the string is writable, the memory managers/watchers have nothing to complain about.

I've been maintaining a codebase which had several..hmm..peculiarities like this, and as long as the prerequisites are listed at the function declaration, it's extremely reliable.

Arthur Kalliokoski
Second in Command
February 2005
avatar

If you guys keep going, you'll come up with textprintf_ex() !

They all watch too much MSNBC... they get ideas.

kazzmir
Member #1,786
December 2001
avatar

Except textprintf_ex doesn't handle newlines which is what prompted the whole debate.

Kitty Cat
Member #2,815
October 2002
avatar

You don't need to scan the string manually for newlines. strchr is your friend:

1int my_textout(BITMAP *bmp, FONT *font, const char *str, int x, int y, int fg, int bg)
2{
3 char *str_copy = strdup(str);
4 char *cur, *next;
5 int i = 0;
6 
7 cur = str_copy;
8 while(cur)
9 {
10 next = strchr(cur, '\n');
11 if(next) *next = 0;
12 i += textout_ex(bmp, font, cur, x, y, fg, bg);
13 if(next) *(next++) = '\n';
14 y += text_height(font);
15 cur = next;
16 }
17 
18 free(str_copy);
19}

--
"Do not meddle in the affairs of cats, for they are subtle and will pee on your computer." -- Bruce Graham

Neil Black
Member #7,867
October 2006
avatar

Quote:

Now as far as input goes you can use this.

Yeah, but that seems a bit much just to let the player name his character...

Timorg
Member #2,028
March 2002

After fixing the errors in Kitty Cat's code. ie. removing the redundant 'i' variable, and changing the return value to void. :P I then made an optimization, where I removed one of the if statements.

I then made a version of my code where it duplicates the string, before messing with it, so that I wouldn't have to put all the '\n's in the right place.

I then stripped out the allegro stuff, and made a program that calls each function 10000000 times.

1#include <string.h>
2#include <stdlib.h>
3 
4void textout_ml_ex0(const char *s, int x, int y)
5{
6 const char *start;
7 char *p, *line_start;
8 int cy;
9 
10 start = s;
11 p = (char *)s;
12 line_start = (char *)s;
13 cy = y;
14 
15 while (1)
16 {
17 if ((*p) == '\0')
18 break;
19 if ((*p) == '\n')
20 {
21 (*p) = '\0';
22 line_start = p + 1;
23 }
24 p++;
25 }
26 
27 
28 while(p != start)
29 {
30 p--;
31 if ((*p) == '\0')
32 (*p) = '\n';
33 }
34}
35 
36void textout_ml_ex1(const char *s, int x, int y)
37{
38 const char *start;
39 char *p, *line_start;
40 int cy;
41 
42 
43 char *copy = strdup(s);
44 
45 start = copy;
46 p = (char *)copy;
47 line_start = (char *)copy;
48 cy = y;
49 
50 while (1)
51 {
52 if ((*p) == '\0')
53 break;
54 if ((*p) == '\n')
55 {
56 (*p) = '\0';
57 line_start = p + 1;
58 }
59 p++;
60 }
61 
62 free(copy);
63}
64 
65void my_textout0(const char *str, int x, int y)
66{
67 char *str_copy = strdup(str);
68 char *cur, *next;
69 
70 cur = str_copy;
71 while(cur)
72 {
73 next = strchr(cur, '\n');
74 if(next) *next = 0;
75 if(next) *(next++) = '\n';
76 cur = next;
77 }
78 
79 free(str_copy);
80}
81 
82void my_textout1(const char *str, int x, int y)
83{
84 char *str_copy = strdup(str);
85 char *cur, *next;
86 
87 cur = str_copy;
88 while(cur)
89 {
90 next = strchr(cur, '\n');
91 if (next)
92 {
93 *next = 0;
94 *(next++) = '\n';
95 }
96 cur = next;
97 }
98 
99 free(str_copy);
100}
101 
102int main()
103{
104 char str[] = "This is a big long string\nit has quite a few lines of text\nhere is one\nhere is another";
105 int c;
106 
107 for (c = 0; c < 10000000; c++)
108 {
109 my_textout0(str, 0, 20);
110 }
111 
112 for (c = 0; c < 10000000; c++)
113 {
114 my_textout1(str, 0, 20);
115 }
116 
117 for (c = 0; c < 10000000; c++)
118 {
119 textout_ml_ex0(str, 0, 20);
120 }
121 
122 for (c = 0; c < 10000000; c++)
123 {
124 textout_ml_ex1(str, 0, 20);
125 }
126 
127 
128 return 0;
129}

I then profiled the program and got the following results.

  %   cumulative   self              self     total           
 time   seconds   seconds    calls  ns/call  ns/call  name    
 58.79      9.67     9.67 10000000   967.05   967.05  textout_ml_ex0
 32.83     15.07     5.40 10000000   540.03   540.03  textout_ml_ex1
  3.83     15.70     0.63 10000000    63.00    63.00  my_textout0
  2.61     16.13     0.43 10000000    43.00    43.00  my_textout1
  1.95     16.45     0.32                             main

As you can see Kitty Cat's function is much more efficent than mine, its actual 15 times faster than my original code.

Then if you optimize it (-O1) the difference is even more pronounced

Each sample counts as 0.01 seconds.
  %   cumulative   self              self     total           
 time   seconds   seconds    calls  ns/call  ns/call  name    
 62.63      4.44     4.44 10000000   444.02   444.02  textout_ml_ex0
 31.31      6.66     2.22 10000000   222.01   222.01  textout_ml_ex1
  2.19      6.82     0.16 10000000    15.50    15.50  my_textout0
  2.05      6.96     0.15 10000000    14.50    14.50  my_textout1
  1.83      7.09     0.13                             main

Which brings me to the final conclusion...

If you want multi-line text output use Kitty Cat's code (after you modify it so that it will actually compile without errors. ;D

-Tim

____________________________________________________________________________________________
"c is much better than c++ if you don't need OOP simply because it's smaller and requires less load time." - alethiophile
OMG my sides are hurting from laughing so hard... :D

OICW
Member #4,069
November 2003
avatar

Quote:

Yeah, but that seems a bit much just to let the player name his character...

With that code you can do pretty much everything you want. I have a working console using that code for input.

[My website][CppReference][Pixelate][Allegators worldwide][Who's online]
"Final Fantasy XIV, I feel that anything I could say will be repeating myself, so I'm just gonna express my feelings with a strangled noise from the back of my throat. Graaarghhhh..." - Yahtzee
"Uhm... this is a.cc. Did you honestly think this thread WOULDN'T be derailed and ruined?" - BAF
"You can discuss it, you can dislike it, you can disagree with it, but that's all what you can do with it"

Neil Black
Member #7,867
October 2006
avatar

I was saying that if the only reason you wanted text input was to get the player's name, that would be a lot of code to do it with. It's worth it if you're actually using a lot of text input, but it's just too much if you only use it once, which is about how much I would use it in a game.

OICW
Member #4,069
November 2003
avatar

As far as I know there's no other simple way of doing this in Allegro.

[My website][CppReference][Pixelate][Allegators worldwide][Who's online]
"Final Fantasy XIV, I feel that anything I could say will be repeating myself, so I'm just gonna express my feelings with a strangled noise from the back of my throat. Graaarghhhh..." - Yahtzee
"Uhm... this is a.cc. Did you honestly think this thread WOULDN'T be derailed and ruined?" - BAF
"You can discuss it, you can dislike it, you can disagree with it, but that's all what you can do with it"

Neil Black
Member #7,867
October 2006
avatar

I know, that's the problem. Allegro include functions to replace (and vastly improve upon) cout, but completely ignores the need for input. I'm going to use the mind control routines in Allegro 5 to make someone put input routines in Allegro 6. ;D

OICW
Member #4,069
November 2003
avatar

The problem is with how the keyboard is managed. You can write your scanf/cin function that will hide that code above from you.

[My website][CppReference][Pixelate][Allegators worldwide][Who's online]
"Final Fantasy XIV, I feel that anything I could say will be repeating myself, so I'm just gonna express my feelings with a strangled noise from the back of my throat. Graaarghhhh..." - Yahtzee
"Uhm... this is a.cc. Did you honestly think this thread WOULDN'T be derailed and ruined?" - BAF
"You can discuss it, you can dislike it, you can disagree with it, but that's all what you can do with it"

 1   2 


Go to: