I'm having a few problems with Eclipse's C++ parser. I've been using it with Emscripten and found the code completion, call hierarchy, documentation popup, code analysis and related features to be very useful, but it's been bothering me that the parser isn't totally working. Especially with this new problem with using vectors.
The first parsing error is on std::vector<SDL_Rect> box; with the error being:
Symbol 'vector' could not be resolved
And then on emscripten_set_main_loop(game_loop, 60, 1); I get this error:
Function 'usleep' could not be resolved
Here's the full code:
#include <stdio.h>
#include <stdlib.h>
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include <emscripten.h>
#include <stdarg.h>
#include <libcxx/vector>
///GLOBAL VARIABLES
SDL_Surface* bitmap;
SDL_Surface* screen;
SDL_Rect source;
SDL_Rect destination;
///second sprite
SDL_Surface* bitmap2;
SDL_Rect source2;
SDL_Rect destination2;
/// Side Scrolling variables:
SDL_Rect camera;
SDL_Rect offset;
SDL_Rect offset2;
int level_width = 480 * 5;
int level_height = 640;
bool gameRunning = true;
class buttonpresses {
public:
bool leftButton;
bool rightButton;
bool jumpButton;
};
int movementspeed = 5;
int jumpspeed = 2;
bool jumpenabled = false;
int jumpduration = 0;
int maxjump = 20;
int leftmomentum = 1;
int rightmomentum = 1;
int lastdestination;
int countDestination = 0;
int maxmomentum = 5;
buttonpresses charactermovement;
/// Collision detection
std::vector<SDL_Rect> box;
///MAIN LOOP
void game_loop() {
// EVENT HANDLING
SDL_PumpEvents();
Uint8 *keystate = SDL_GetKeyboardState(NULL);
if (keystate[SDLK_ESCAPE]) {
gameRunning = false;
printf("Game Stopping!!!!!!\n");
SDL_Quit();
exit(0);
}
if (keystate[SDLK_LEFT]) {
// printf("Left Key\n");
charactermovement.leftButton = true;
}
if (keystate[SDLK_LEFT] == false) {
charactermovement.leftButton = false;
}
if (keystate[SDLK_RIGHT]) {
// printf("Right Key\n");
charactermovement.rightButton = true;
}
if (keystate[SDLK_RIGHT] == false) {
charactermovement.rightButton = false;
}
if (keystate[SDLK_SPACE]) {
// printf("Space Key\n");
charactermovement.jumpButton = true;
}
if (keystate[SDLK_SPACE] == false) {
charactermovement.jumpButton = false;
}
// printf("Game Running..\n");
// LOGIC
//character movement
if (charactermovement.rightButton) {
destination.x = destination.x + movementspeed;
}
if (charactermovement.leftButton) {
destination.x = destination.x - movementspeed;
}
if (charactermovement.jumpButton && jumpenabled) {
destination.y = destination.y - jumpspeed;
jumpduration++;
}
destination.x = destination.x + rightmomentum - leftmomentum;
if (destination.y >= 200) {
jumpenabled = true;
// printf ("jump enabled\n");
}
if (jumpduration >= maxjump) {
jumpenabled = false;
}
if (destination.y >= 200) {
// printf ("destination y:");
// printf ("%d\n", destination.y);
jumpduration = 0;
}
//if (jumpenabled != true){
// printf ("jump disabled\n");
//}
//if (jumpenabled == true){
// printf ("jump enabled\n");
// printf ("jump duration: ");
// printf ("%d\n", jumpduration);
//}
//momentum
//save position every 5 interations
if (countDestination > 5) {
lastdestination = destination.x;
countDestination = 0;
} else {
countDestination++;
}
//printf ("last location: ");
//printf ("%d\n", destination.x);
//
//printf ("current location: ");
//printf ("%d\n", lastdestination);
// increase momentum in direction your moving in (relative to previous location)
if (lastdestination > destination.x) {
// printf ("right if running \n ");
if (rightmomentum > 0) {
rightmomentum--;
} else if (leftmomentum < maxmomentum) {
leftmomentum++;
}
}
if (lastdestination < destination.x) {
// printf ("left if running \n ");
if (leftmomentum > 0) {
leftmomentum--;
} else if (rightmomentum < maxmomentum) {
rightmomentum++;
}
}
if (lastdestination == destination.x) {
if (leftmomentum > 0) {
leftmomentum--;
}
if (rightmomentum > 0) {
rightmomentum--;
}
}
printf("left momentum: ");
printf("%d\n", rightmomentum);
printf("right momentum: ");
printf("%d\n", leftmomentum);
//gravity
if (destination.y <= 200) {
destination.y++;
}
offset.x = destination.x - camera.x;
offset2.x = destination2.x - camera.x;
offset.y = destination.y - camera.y;
offset2.y = destination2.y - camera.y;
// RENDERING
SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
SDL_BlitSurface(bitmap, &source, screen, &offset);
// RENDER SECOND SPRITE
SDL_BlitSurface(bitmap2, &source2, screen, &offset2);
//blank screen
SDL_Flip(screen);
camera.x++;
}
int main() {
SDL_Init( SDL_INIT_VIDEO);
// LOAD FILES
bitmap = IMG_Load("ninjagaiden3sheet1.png");
screen = SDL_SetVideoMode(640, 480, 0, SDL_HWSURFACE | SDL_DOUBLEBUF);
/// camera variables
camera.x = 0;
camera.y = 0;
camera.w = 640;
camera.h = 480;
/// end camera variables
// Part of the bitmap that we want to draw
source.x = 37;
source.y = 4;
source.w = 17;
source.h = 32;
// Part of the screen we want to draw the sprite to
destination.x = 100;
destination.y = 100;
destination.w = 65;
destination.h = 44;
//// second sprite
bitmap2 = IMG_Load("bat_transparent.png");
source2.x = 24;
source2.y = 63;
source2.w = 65;
source2.h = 44;
destination2.x = 940;
destination2.y = 100;
destination2.w = 65;
destination2.h = 44;
//// end second sprite
lastdestination = destination.x;
offset = destination;
offset2 = destination2;
charactermovement.leftButton = false;
charactermovement.rightButton = false;
charactermovement.jumpButton = false;
//START MAIN LOOP
emscripten_set_main_loop(game_loop, 60, 1);
return 0;
}
My includes tab for C++ in the "Paths and Symbols" properties looks like:
C:\Program Files\Emscripten\emscripten\1.12.0\system\include
C:\Program Files\Emscripten\emscripten\1.12.0\system\include\libc
C:\Program Files\Emscripten\emscripten\1.12.0\system\include\emscripten
C:\Program Files\Emscripten\emscripten\1.12.0\system\include\libcxx
In the Indexer settings I have the following enabled:
Index source files not included in the build
Index unused headers
Index all header variants
Index source and header files opened in editor
Allow heuristic resolution of includes
Skip files larger than: 8 MB
Does anyone know what's going on? Or what I can do to fix it?
Update:
I've fixed the error on parsing std::vector. It turns out that some of llvm/clang libraries use _LIBCPP_BEGIN_NAMESPACE_STD and _LIBCPP_END_NAMESPACE_STD definitions instead of using namespace std; and those defines are invisible to the parser unless __clang__ is defined.
So the solution is to go into the "Symbols" tab for C++ in the "Paths and Symbols" properties and add:
__clang__
In the "Add" dialog that pops up just put it in the Name: input field and press OK. This will also add many of the missing std namespace functions like cout cin etc.
I haven't found a fix for the usleep/emscripten_set_main_loop issue yet but this should be good enough to get the IDE's code completion and several related features to work. Though I'm still having some weird complicated parser issues with Eclipse so I think I'm going to abandon the search for a solution here and work with NetBeans for which I think I have every thing set up.
Related
I'm coding a C++ program that makes a certain movement with the mouse by itself when I press the left mouse button, it has F1, F2, F3 keys and each key has a different movement, and then I press the left mouse button to execute that movement , but what is happening is that I have to hold down the F1 key and the left mouse button at the same time for it to work, I wanted to press the F1 key just once and then just hold down the left mouse button !
#include <iostream>
#include <string>
#include <Windows.h>
#include "patterns.h"
#define getLen(x) (sizeof(x)/sizeof(x[0]))
using namespace std;
typedef struct $ {
string name;
long **pattner;
int len;
int rpm;
}weapon_t;
weapon_t *LoadWeapon(string name, long recoil[][2], int len, int rpm);
float GetK(float dpi, float sensi);
DWORD GetTime(float rpm);
void ExecControl(weapon_t gun);
float K;
int main()
{
K = GetK(800, 0.95);
weapon_t *ak47 = LoadWeapon("AK-47", ak47_pattern, getLen(ak47_pattern), 600);
weapon_t *m4a4 = LoadWeapon("M4A4", m4a4_pattern, getLen(m4a4_pattern), 666);
weapon_t *ump45 = LoadWeapon("UMP-45", ump45_pattern, getLen(ump45_pattern), 666);
weapon_t* m4a1s = LoadWeapon("M4A1S", m4a1s_pattern, getLen(m4a1s_pattern), 600);
weapon_t* famas = LoadWeapon("FAMAS", famas_pattern, getLen(famas_pattern), 600);
while (true) {
if (GetAsyncKeyState(VK_F1)) {
ExecControl(*ak47);
}
if (GetAsyncKeyState(VK_F2)) {
ExecControl(*m4a4);
}
if (GetAsyncKeyState(VK_F3)) {
ExecControl(*m4a1s);
}
if (GetAsyncKeyState(VK_F4)) {
ExecControl(*ump45);
}
if (GetAsyncKeyState(VK_F5)) {
ExecControl(*famas);
}
Sleep(150);
}
return 0;
}
void ExecControl(weapon_t gun) {
system("cls");
cout << "Weapon:\t" << gun.name << "\nShots:\t" << gun.len << "\nVelocity:\t" << gun.rpm << "\n\n\n";
DWORD delay = GetTime(gun.rpm);
int index = 0;
while (GetAsyncKeyState(VK_LBUTTON) && index != gun.len) {
mouse_event(MOUSEEVENTF_MOVE, long(gun.pattner[index][0] * K), long(gun.pattner[index][1] * K), 0, 0);
index++;
Sleep(delay);
}
index = 0;
}
weapon_t *LoadWeapon(string name, long recoil[][2], int len, int rpm) {
int i;
weapon_t *gun = new weapon_t();
gun->name = name;
gun->len = len;
gun->rpm = rpm;
gun->pattner = new long*[len];
for (i = 0; i < len; i++) {
gun->pattner[i] = new long[2];
}
for (i = 0; i < len; i++) {
gun->pattner[i][0] = recoil[i][0];
gun->pattner[i][1] = recoil[i][1];
}
return gun;
}
float GetK(float dpi, float sensi) {
return (1140 / (dpi*sensi));
}
DWORD GetTime(float rpm) {
return DWORD((60 / rpm) * 1000);
}
The problem is that your code is looking at the mouse left button only while any F1..F5 key is currently held down, and then you are not looking at the keyboard again until the left button is released or the current gun is exhausted.
You need a different approach, such as a state machine. Keep track of the current gun that is equipped at any given time. On each iteration of the main loop, check for state changes first (ie, check if any F1..F5 key is held down, and if so then equip the associated gun), and then act on the current state (ie, regardless of the keyboard state, if the left button is down, and a gun is equipped, then advance the gun to its next position). Let the loop handle the repetitive work for you. This will allow you to check the keyboard for gun changes while the left button is held down.
Try something more like this:
#include <iostream>
#include <string>
#include <Windows.h>
#include "patterns.h"
#define getLen(x) (sizeof(x)/sizeof(x[0]))
using namespace std;
typedef struct $ {
string name;
long **pattner;
int len;
int rpm;
}weapon_t;
weapon_t* LoadWeapon(string name, long recoil[][2], int len, int rpm);
float GetK(float dpi, float sensi);
DWORD GetTime(float rpm);
float K = GetK(800, 0.95);
int main()
{
weapon_t *ak47 = LoadWeapon("AK-47", ak47_pattern, getLen(ak47_pattern), 600);
weapon_t *m4a4 = LoadWeapon("M4A4", m4a4_pattern, getLen(m4a4_pattern), 666);
weapon_t *ump45 = LoadWeapon("UMP-45", ump45_pattern, getLen(ump45_pattern), 666);
weapon_t *m4a1s = LoadWeapon("M4A1S", m4a1s_pattern, getLen(m4a1s_pattern), 600);
weapon_t *famas = LoadWeapon("FAMAS", famas_pattern, getLen(famas_pattern), 600);
weapon_t* guns[] = {ak47, m4a4, m4a1s, ump45, famas};
int gun_keys[] = {VK_F1, VK_F2, VK_F3, VK_F4, VK_F5};
weapon_t *gun = nullptr;
int gun_index = -1;
DWORD gun_delay = 150;
bool is_mouse_down = false;
while (true) {
for(int i = 0; i < 5; ++i) {
if (GetAsyncKeyState(gun_key[i]) && (gun != guns[i])) {
gun = guns[i];
system("cls");
cout << "Weapon:\t" << gun->name << "\nShots:\t" << gun->len << "\nVelocity:\t" << gun->rpm << "\n\n\n";
gun_delay = GetTime(gun->rpm);
gun_index = 0;
break;
}
}
if (GetAsyncKeyState(VK_LBUTTON) < 0) {
if (!is_mouse_down) {
is_mouse_down = true;
if (gun != nullptr)
gun_index = 0;
}
if (gun != nullptr && gun_index != gun->len) {
mouse_event(MOUSEEVENTF_MOVE, long(gun->pattner[gun_index][0] * K), long(gun->pattner[gun_index][1] * K), 0, 0);
++gun_index;
Sleep(gun_delay);
continue;
}
}
else
is_mouse_down = false;
Sleep(150);
}
return 0;
}
weapon_t* LoadWeapon(string name, long recoil[][2], int len, int rpm) {
weapon_t *gun = new weapon_t();
gun->name = name;
gun->len = len;
gun->rpm = rpm;
gun->pattner = new long*[len];
for (int i = 0; i < len; i++) {
gun->pattner[i] = new long[2];
gun->pattner[i][0] = recoil[i][0];
gun->pattner[i][1] = recoil[i][1];
}
return gun;
}
float GetK(float dpi, float sensi) {
return (1140 / (dpi*sensi));
}
DWORD GetTime(float rpm) {
return DWORD((60 / rpm) * 1000);
}
I have a textbox class that works nicely with wider characters such as a,b,c... but with characters like 'f' and 'l' it seems to incorrectly get the sizing of those characters, yet correctly get the sizing of the others? Here is the code for the 'highlighting' of the text for the textbox class, its a bit long ill fix that up later, but should documented enough to understand easily.
void Textbox::Highlight_Text(SDL_Renderer *renderer)
{
if (clickedOn == true){
int currentCharacterWidth = 0;
int currentCharacterHeight = 0;
int totalSize = 0;
SDL_Rect currentCharacterRect;
string currentCharacter, tempText;
if (highlightedCharacters.size() >= 1){ ///To make sure only 1 thing is highlighted, in conjunction with next part
highlighted = true;
}
if (highlighted == true){ /// if a part is highlighted, and is left highlighted, next time clicked, remove the highlighting and redo it
if (EVENTS.mouseClicked == false){
resetHighlightingNextClick = true;
}
}
if (resetHighlightingNextClick == true){
if (highlighted == true){
if (EVENTS.mouseClicked == true){ ///actually remove the highlighting
highlightedCharacters.clear();
indexOfCharactersHighlighted.clear();
highlighted = false;
resetHighlightingNextClick = false;
}
}
}
for (int i=0; i < textboxText.Get_Text().size(); i++){
currentCharacter = textboxText.Get_Text()[i];
TTF_SizeText(textboxText.fonts[textboxText.fontIndex], currentCharacter.c_str(), ¤tCharacterWidth, ¤tCharacterHeight);
///the totalSize added to rectangle is not making it wider, its adjusting its x value offset
currentCharacterRect = {textboxText.x + totalSize, textboxText.y + int(textboxText.textSize*0.1), currentCharacterWidth, currentCharacterHeight};
totalSize += currentCharacterWidth; ///"current" size of text in loop to get x value of specific character clicked on
///If mouse is touching any of the characters in the text
if ( SDL_PointInRect(&EVENTS.mousePos, ¤tCharacterRect) ){
EVENTS.Change_Cursor(SDL_SYSTEM_CURSOR_IBEAM);
if (EVENTS.mouseClicked == true){ ///Clicking on the text to highlight
if (In_Array(highlightedCharacters, currentCharacterRect.x) == false ){
highlightedCharacters.push_back(currentCharacterRect); ///If there is no duplicates
indexOfCharactersHighlighted.push_back(i); ///Get index of text being highlighted, its always in order too
}
if ( currentCharacterRect.x != highlightedCharacters[highlightedCharacters.size()-1].x){ ///So they don't stack up highlights, ie, you can remove them
/// If the mouse is not highlighting the last one, say second last on the right for example, delete the one in front of it (last one)
///Like when highlighting text with mouse, it adapts to how you move it, so it unhighlights text not being highlighted
highlightedCharacters.pop_back();
indexOfCharactersHighlighted.pop_back();
}
}
}
}///End for loop
if (highlighted == true ){
if (EVENTS.backspacePressed == true || EVENTS.currentKey != ""){
tempText = textboxText.Get_Text();
///remove highlighted characters
if (indexOfCharactersHighlighted.size() != 0){
///the range of values highlighted will always be in a sorted order
tempText.erase( Min(indexOfCharactersHighlighted) , Max(indexOfCharactersHighlighted)-Min(indexOfCharactersHighlighted)+1 ); ///erase the range of values highlighted
textboxText.Change_Text(renderer, tempText);
///once removed text, clear every highlighted related thing
highlightedCharacters.clear();
indexOfCharactersHighlighted.clear();
highlighted = false;
resetHighlightingNextClick = false;
EVENTS.backspacePressed = false;
EVENTS.currentKey = "";
}
}
}
} ///End if for clicked on
///fit with scrolling offsets
if (EVENTS.scrolled == true){
for (int p=0; p < highlightedCharacters.size(); p++){
highlightedCharacters[p].y += EVENTS.scrollVal;
}
}
///Drawing the highlighted text
if (highlighted == true && clickedOn == true){
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(renderer, 55,60,65, 75);
for (int j=0; j < highlightedCharacters.size(); j++){
SDL_RenderFillRect(renderer, &highlightedCharacters[j]);
}
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE);
}
///when clicked off textbox, clear everything/highlighting
if (clickedOn == false){
highlightedCharacters.clear();
indexOfCharactersHighlighted.clear();
highlighted = false;
}
}
For reference in the font passed in, here is how i obtain it in the text class
fontIndex = textSize-lowestFontSize -1;
///One time setups
if (numOfInstances == 1){
try{
TTF_Init();
//cout << "Initialised ttf" << endl;
}
catch (exception &err){
cout << "Could not initialise ttf for text \"" << text << "\". Error from SDL is: " << TTF_GetError() << ". Error from C++ is: " << err.what() << endl;
}
for (int i=lowestFontSize; i <= highestFontSize; i++){
TTF_Font *currentFont = TTF_OpenFont(fontType.c_str(), i);
if (!currentFont){
cout << "Error with font in text \"" << txt << "\" Error is: " << SDL_GetError() << endl;
}
fonts.push_back(currentFont);
}
}
and so if i pass in, say 25 as my text size, i have my lowestFontSize = 10 and highestFontSize = 100, so the index i need for size 25 would be (25-10 -1 = 14), as indexing begins at 0, which is that first line before i create my static vector of fonts in the text class. Here is a snippet of what i'm trying to explain:
This is clearly working properly.
But now, it is completely inaccurate. If i select a random character towards the end of the text, it is not correctly highlighted, only from the beginning the first one looks pretty much perfect, but then it seems as if the inaccuracy is compounded, hence making the total grey highlighting much wider than it is supposed to be.
The problem with your method is that individual character widths are meaningless. The renderer adjusts them depending on context (their neighbours in the rendered string). So the width of i in the rendered string bit is not necessarily the same as the width of i in the rendered string fil.
The method to find text selection coordinates needs to take context into account.
Say we have the width of the three strings:
prefixWidth is the size of the prefix (the original line of text up to but not including the selection)
selWidth is the width of the selection itself
totalWidth is the width of the prefix and the selection concatenated
(we don't care about the portion after the selection). The first two widths will be close to the third, but will not add up because of the kerning between the last character of the prefix and the first character of the selection. The difference is the correction you need to apply to the X coordinate of the rendered selection. So we need to start rendering selection at the X coordinate which is not prefixWidth, but
prefixWidth + (totalWidth - (prefixWidth + selWidth))
which is the same as
totalWidth - selWidth
so you don't really need to calculate prefixWidth at all.
A full (semi-)working example program below. The arguments are (1) font file full path (2) font size (3) string to render (4) selection start (5) selection length. The selection is rendered on top of the original text, shifted 1 pixel down and right, so it is easy to see if there is any deviation.
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
char* substr(const char* src, int fromChar, int subLen)
{
if (subLen < 0 || fromChar < 0 || fromChar + subLen > (int)strlen(src))
{
fprintf (stderr, "invalid substring\n");
exit (EXIT_FAILURE);
}
char* z = (char*)malloc(subLen);
strncpy(z, src + fromChar, subLen);
z[subLen] = '\0';
return z;
}
void textExtent(TTF_Font* font, const char* text,
int fromChar, int subLen, int* w, int* h)
{
int l = strlen(text);
if (subLen == -1) subLen = l;
if (fromChar < 0 || subLen > l)
{
fprintf (stderr, "Bad text extent\n");
exit (EXIT_FAILURE);
}
char* z = substr(text, fromChar, subLen);
TTF_SizeUTF8(font, z, w, h);
free(z);
}
int textWidth(TTF_Font* font, const char* text,
int fromChar, int subLen)
{
int w, h;
textExtent(font, text, fromChar, subLen, &w, &h);
return w;
};
int main(int argc, char ** argv)
{
bool quit = false;
SDL_Event event;
SDL_Init(SDL_INIT_VIDEO);
TTF_Init();
if (argc != 6)
{
fprintf (stderr, "usage: %s font text from length\n", argv[0]);
exit(EXIT_FAILURE);
}
const char* fontpath = argv[1];
int fontSz = atoi(argv[2]);
const char* txt = argv[3];
int from = atoi(argv[4]);
int len = atoi(argv[5]);
int tsize = strlen(txt);
if (from < 0 || from + len >= tsize)
{
fprintf (stderr, "Invalid text portion to highlight\n");
exit (EXIT_FAILURE);
}
if (fontSz < 2 || fontSz > 300)
{
fprintf (stderr, "Invalid font size\n");
exit (EXIT_FAILURE);
}
// open font to render with
TTF_Font * font = TTF_OpenFont(fontpath, fontSz);
if (!font)
{
fprintf (stderr, "Could not open font %s\n", fontpath);
exit (EXIT_FAILURE);
}
// Query text size
int textW, textH;
textExtent(font, txt, 0, -1, &textW, &textH);
SDL_Window * window = SDL_CreateWindow("SDL_ttf in SDL2",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, textW, textH, 0);
// Query selection coords
//
int selWidth = textWidth(font, txt, from, len);
int totalWidth = textWidth(font, txt, 0, from+len);
// Render portions of text
SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);
SDL_Color color = { 255, 128, 0, 0 };
SDL_Surface * surface = TTF_RenderUTF8_Blended(font, txt, color);
SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, surface);
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
SDL_Rect dstrect = { 0, 0, textW, textH };
SDL_Color color2 = { 0, 128, 255, 128 };
char* s = substr(txt, from, len);
SDL_Surface * surface2 = TTF_RenderUTF8_Blended(font, s, color2);
free(s);
SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
SDL_Texture * texture2 = SDL_CreateTextureFromSurface(renderer, surface2);
SDL_SetTextureAlphaMod(texture2, 128);
SDL_SetTextureBlendMode(texture2, SDL_BLENDMODE_BLEND);
SDL_Rect dstrect2 = {totalWidth - selWidth + 1, 1, selWidth, textH };
while (!quit)
{
SDL_WaitEvent(&event);
switch (event.type)
{
case SDL_QUIT:
quit = true;
break;
}
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, texture, NULL, &dstrect);
SDL_RenderCopy(renderer, texture2, NULL, &dstrect2);
//Update screen
SDL_RenderPresent(renderer);
}
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_DestroyTexture(texture);
SDL_FreeSurface(surface);
TTF_CloseFont(font);
TTF_Quit();
SDL_Quit();
return 0;
}
I am making a program in C++ that uses SDL to display text boxes. I've made the basic functions of my text boxes like typing text, limitations, copy/paste, etc. but I am stuck at make it able to highlight text.
Here's how I draw textboxes:
void draw_text_box(SDL_Surface *screan, char *message, struct textbox *text_box, int r, int g, int b)
{
int temp_width;
int temp_frame;
SDL_Surface *text;
SDL_Color textcolor = {0,0,0,0};
SDL_Rect temp_location, clr_box;
temp_width = text_box->location.w; //preserve the correct width
temp_location = text_box->location;
temp_location.y += 4;
temp_location.h = 12;
clr_box = text_box->location;
//colors!
textcolor.r = r;
textcolor.g = g;
textcolor.b = b;
//text = TTF_RenderText_Solid(ttf_font, text_box->prev_message, textcolor);
//SDL_BlitSurface( text, NULL, screan, &text_box->location);//<-changes "location" width to width of text
//clear
SDL_FillRect(screan, &clr_box, SDL_MapRGB(screen->format, 0, 0, 0));
//strcpy(text_box->prev_message, message);
//set the text
text = TTF_RenderText_Solid(ttf_font, message, textcolor);
if(!text) return;
//set the offset
temp_location.x = text_box->last_shift;
temp_location.y = 0;
temp_location.h = text->h;
if(text_box->cursor_loc - text_box->last_shift > temp_location.w)
temp_location.x = text_box->cursor_loc - temp_location.w;
if(text_box->cursor_loc - 3 < text_box->last_shift)
temp_location.x = text_box->cursor_loc - 3;
if(temp_location.x < 0) temp_location.x = 0;
text_box->last_shift = temp_location.x;
//draw
SDL_BlitSurface( text, &temp_location, screan, &text_box->location);//<-changes "location" width to width of text
text_box->location.w = temp_width;
}
Setting the text:
void set_text_box_text(SDL_Surface *screan, struct textbox *text_box, char *message)
{
if(text_box->message != message)
strcpy(text_box->message, message);
text_box->char_amt = strlen(message);
text_box->cursor = text_box->char_amt;
text_box->last_shift = 0;
if (screan) //if not NULL
{
if (text_box->selected)
select_text_box(screan,text_box);
else
unselect_text_box(screan,text_box);
}
else
{
;//text_box->prev_message[0] = '\0';
}
}
Select and deselect the textbox:
void select_text_box(SDL_Surface *screan, struct textbox *text_box)
{
char temp_message[405] = "";
char temp_left[405];
int i;
text_box->selected = 1;
if (text_box->pass_char == '\0')
{
if (text_box->cursor != 0)
{
left(temp_left, text_box->message, text_box->cursor);
strcat(temp_message, temp_left);
}
temp_message[text_box->cursor] = '|';
temp_message[text_box->cursor + 1] = '\0';
right(temp_left, text_box->message, text_box->cursor);
strcat(temp_message, temp_left);
}
else
{
for(i=0;i<text_box->cursor;i++)
temp_message[i] = text_box->pass_char;
temp_message[i] = '|';
for(i++;i<text_box->char_amt + 1;i++)
temp_message[i] = text_box->pass_char;
temp_message[i] = '\0';
}
draw_text_box(screan, temp_message, text_box, 250, 250, 250);
}
void unselect_text_box(SDL_Surface *screan, struct textbox *text_box)
{
char temp_message[405];
int i;
text_box->selected = 0;
if (text_box->pass_char == '\0')
draw_text_box(screan, text_box->message, text_box, 250, 250, 250);
else
{
for(i=0;i<text_box->char_amt;i++)
temp_message[i] = text_box->pass_char;
temp_message[i] = '\0';
draw_text_box(screan, temp_message, text_box, 250, 250, 250);
}
}
there seemed to be a lot of people with the segmentation fault problem but I couldn't seem to find any that related to my program, if there is a thread I'm sorry, I looked through multiple though and couldn't find it.
pretty much everything so far:
#include <SDL.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <time.h>
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int maxLandMass = SCREEN_WIDTH * SCREEN_HEIGHT;
const int landPercentage = 30;
const int maxHeight = 200;
const int numAnts = 10;
int main(int argc, char **argv)
{
int currentLandMass = 0;
int ants[numAnts][3]={{0}}; //x,y,pDir (0123,NESW)
std::string rules[numAnts]={0};
std::string rule;
int states = 2;
std::cout << "Which rule would you like to use? ";
std::cin >> rule;
if(rule == "")
{
rule = "RL";
}
else if(rule == "RND" || rule == "rnd")
{
std::cout << "How many states? ";
std::cin >> states;
}
srand(time(NULL));
for(int i = 0;i < numAnts;i++)
{
ants[i][0] = rand() % SCREEN_WIDTH;
ants[i][1] = rand() % SCREEN_HEIGHT;
ants[i][2] = rand() % 4;
if(rule != "RND" && rule != "rnd")
{
rules[i] = rule;
}
else
{
std::string tempRule;
for(int s = 0; s < states; s++)
{
int r = rand() % 2;
if(r == 0){ tempRule += "L"; }
if(r == 1){ tempRule += "R"; }
}
rules[i] = tempRule;
}
std::cout << rules[i] << "\n";
}
SDL_Window* window = NULL;
SDL_Surface* surface = NULL;
if(SDL_Init(SDL_INIT_VIDEO) < 0)
{
printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());
}
else
{
window = SDL_CreateWindow("SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
if( window == NULL )
{
printf("Window could not be created! SDL_Error: %s\n", SDL_GetError());
}
else
{
surface = SDL_GetWindowSurface(window);
SDL_FillRect(surface, NULL, SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
SDL_UpdateWindowSurface(window);
}
}
//Uint16 *pixels = (Uint16 *) surface->pixels;
/////////////////////////////
int grid[SCREEN_HEIGHT][SCREEN_WIDTH]={{0}};
int heights[SCREEN_HEIGHT][SCREEN_WIDTH]={{0}};
int prevState = 0;
for(int a = 0; a < numAnts; a++)
{
//TODO add stuff here
}
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
When it runs it should start with a console window to get some input from the user then switch to an SDL window and do its thing, but the console window tells me:
terminate called after throwing an instance of 'std::logic_error'
what():basic_string::_S_construct null not valid
I have a feeling its something to do with how I have initialised (or at least tried to) the arrays.
The part that I added last was the bit below the ////// line I made.
let me know if you will need more info, Ill get it as soon as I can, and I apologise for my programs current state, its messiness is driving me a bit mad too but (until I broke it) it worked :P
You are initializing your array of strings with zeros. That's an invalid initialization.
Interestingly, had you picked any other number, you'd get a clearer error message, telling you that you're doing an invalid conversion from int to const char* (which is a c-style string, and the closest valid input type std::string has a constructor for).
Unfortunately, the zero initialization is confusing your compiler to think you're actually assigning a pointer, which it may convert, but luckily it checks and sees that the pointer is NULL, and therefore bails out with the error message you saw: basic_string::_S_construct null not valid.
I took your code and removed all the SDL part, it compiled and reproduced the error.
I then replaced
std::string rules[numAnts]={0};
with
std::string rules[numAnts];
which uses the default constructor to create empty strings for all elements, and now it seems to work.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
i made a program to move a dot around on the screen. i was basically just recreating lazyfoo sdl tutorial.
the problem is my program eats memory. its memory usage is slowly increasing at like 200kb/s rate. it grows bigger overtime.
i tested it using visual leak detector, it says no memory leak.
so what did i do wrong??
please help me. it's driving me crazy.
here is the code: credit to lazyfoo.
if the code is too long or unclear i will edit it as necessary.
thank you.
//Main Stage
int main(int argc, char* args[])
{
if (!init())
{
printf("failed to init! \n");
}
else
{
cTile *tileSet[TOTAL_TILES];
if (!loadMedia(tileSet))
{
printf("failed to load media! \n");
}
else
{
bool running = true;
SDL_Rect wall;
wall.x = 200;
wall.y = 200;
wall.h = 150;
wall.w = 70;
cDot Dot1(1270, 720);
cDot Dot2(SCREEN_HEIGHT / 4, SCREEN_WIDTH / 4);
cTimer timer;
SDL_Event e;
SDL_Color textColor = { 0, 0, 120, 120 };
std::vector<SDL_Rect> camera;
camera.resize(1);
camera[0] = { 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT };
Uint32 startTime = 0;
std::stringstream timeText;
int countedFrames = 0;
timer.start();
while (running)
{
while (SDL_PollEvent(&e) != 0)
{
if (e.type == SDL_QUIT)
{
running = false;
}
Dot1.handleEvent(e);
for (int i = 0; i < TOTAL_BUTTONS; i++)
{
buttons[i].buttonEvent(&e);
}
}
float avgFPS = countedFrames / (timer.getTicks() / 1000.f);
if (avgFPS > 2000)
{
avgFPS = 0;
}
if (!textTexture.loadTextFromFile(timeText.str().c_str(), textColor))
{
printf("unable to render text ypoooooo");
}
timeText.str("");
timeText << "fps " << avgFPS;
Dot1.move(tileSet);
Dot1.setCamera(camera[0]);
/*camera.x = (Dot1.getPosX() + cDot::DOT_WIDTH / 2) - SCREEN_WIDTH / 2;
camera.y = (Dot1.getPosY() + cDot::DOT_HEIGHT / 2) - SCREEN_HEIGHT / 2;*/
/*if (camera.x < 0){ camera.x = 0; }
if (camera.y < 0){ camera.y = 0; }
if (camera.x > LEVEL_WIDTH - camera.w){ camera.x = LEVEL_WIDTH - camera.w; }
if (camera.y > LEVEL_HEIGHT - camera.h){ camera.y = LEVEL_HEIGHT - camera.h; }*/
SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF);
SDL_RenderClear(renderer);
//SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0xFF);
//SDL_RenderDrawRect(renderer, &wall);
for (int i = 0; i < TOTAL_TILES; ++i)
{
tileSet[i]->render(camera);
}
//BGTexture.render(0, 0, &camera);
Dot1.render(camera[0]);
textTexture.render(250, 250);
timeTextTexture.render(250, 250 + textTexture.getWidth());
for (int i = 0; i < 2; i++)
{
//buttons[i].render();
}
//Dot2.render(camera.x, camera.y);
SDL_RenderPresent(renderer);
if (timer.started())
{
countedFrames++;
}
else if (!timer.started())
{
countedFrames = 0;
}
}
}
close(tileSet);
}
return 0;
}
EDIT:
solution is so simple THANKS TO PAUL AND WEATHER VANE !!!! apparently i put these lines of code inside a loop. where its main function is basically creating texture. and it loads texture over and over again because it's inside a loop. i just need to delete it.
these lines:
if (!textTexture.loadTextFromFile(timeText.str().c_str(), textColor))
{
printf("unable to render text ypoooooo");
}
THANK YOU GUYS!!! :)
sorry i can't vote up, apparently it needs more reputation to vote an answer up. :|
I suspect this which only deletes when NULL.
for (int i = 0; i < TOTAL_TILES; ++i)
{
if (tiles[i] == NULL)
{
delete tiles[i];
tiles[i] = NULL;
}
}
EDIT:
Here is another shot: you call loadTextFromFile() in your main loop repetition, but only call SDL_DestroyTexture() in the final close().
And here is a similar question, Memory leak SDL while using SDL_CreateTextureFromSurface