New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Seperate console rendering and window present routines. #18
Comments
I would like to support this enhancement. Currently I have a use-case where I'd like to print some libtcod elements (frame, text etc) on top of the SDL surface (that I have accessed via the callback method). To do this currently I have to work out where the libtcod elements will go in advance, and change the alpha of the SDL surface in those regions to fully transparent so that the callback blit won't overwrite the contents. Doable, but clunky. Ideally, I suppose, I'd like access to the surface either at any point before flush, or alternatively be able to do SDL-based rendering before as well as after libtcod rendering. |
So far I've recently added alpha values to consoles, but the renderers don't support them yet. Once it does have support you should be able to mimic that screenshot with very careful tileset design. For example, the center banner frame tiles would need to be solid black on the inside and fully transparent on the outside. |
Oh yes, I'd anticipate a bit of jiggery-pokery with tile positioning and design, but that functionality would be most appreciated and welcomed! |
Small issue with the new method when trying it out in a noddy app (using the latest repository version). Or maybe I'm missing something, but I am getting a weird error with mismatched types when using
Here's the rest of the (mainly boilerplate) code, where I'm doing standard stuff with an offscreen console that I've done dozens of times before.
Apologies if I'm doing something dumb, this functionality of libtcod will be wonderful for me when I get it to work. |
In the long term
|
Works wonderfully, thank you. I'll upload some sample code to github so others can see how it is used (ignore the frame character issue in the image below, that's because I'm using a ttf font for the tileset and not a mapped font graphic) One thing I'd like is for the option to make the console appear transparent. Is there any way for libtcod to optionally take into account the keycolour of the console when doing the rendering into a texture? I could read the pixels of the resultant texture with ReadPixels etc and change it there before rendering but that's a very slow operation. |
Libtcod supports alpha rather than key colors. You can set the alpha of the tile background directly. I think most of the C++ drawing and printing functions other than blit will remove transparency, so you'll need to change the alpha last: // Set the background tile at x,y transparent.
off_console->get_data()->at(y, x).bg.a = 0; // Set all 'magic pink' background tiles transparent.
static const struct TCOD_ColorRGBA MAGIC_PINK{255, 0, 255, 255};
for (struct TCOD_ConsoleTile& tile : *off_console->get_data()) {
if (tile.bg == MAGIC_PINK) { tile.bg.a = 0; }
}
|
Excellent, thank you! Especially looking forward to libcod v2 now too! Keep going, its coming on wonderfully! |
I've been looking into doing something like that too, but I had to do multiple modifications to the sample code of Davemoore22 to make it work. So to anybody with the same wish as me here's a functional demo to print a console on an SDL window base on the information that Davemoore22 gave a few messages up: #include "libtcod.hpp"
#include <SDL.h>
int main(int argc, char* argv[]) {
// Setup the SDL Window
int window_width = 1080;
int window_height = 720;
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* SDL_window = SDL_CreateWindow("libtcod + SDL", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, window_width, window_height, SDL_WINDOW_SHOWN);
SDL_Surface* SDL_surface = SDL_GetWindowSurface(SDL_window);
SDL_Renderer* SDL_renderer = SDL_GetRenderer(SDL_window);
SDL_SetRenderDrawBlendMode(SDL_renderer, SDL_BLENDMODE_NONE);
// Setup the TCOD Tileset and prepare it to be rendered to the window
TCOD_Tileset* tileset = TCOD_load_truetype_font_("font/monaco.ttf", 16, 16);
TCOD_TilesetAtlasSDL2* tileset_atlas = TCOD_sdl2_atlas_new(SDL_renderer, tileset);
// Create a sample TCOD console
std::unique_ptr<TCODConsole> off_console = std::make_unique<TCODConsole>(17, 3);
while (1) { // Game loop.
off_console->setDefaultBackground(TCODColor::black);
off_console->setDefaultForeground(TCODColor::lightRed);
off_console->printFrame(0, 0, 17, 3, true, TCOD_BKGND_OVERLAY, nullptr);
off_console->setDefaultForeground(TCODColor::white);
off_console->printf(1, 1, "libtcod overlay");
SDL_SetRenderDrawColor(SDL_renderer, 255, 255, 255, 255);
SDL_RenderClear(SDL_renderer);
// Now render the TCOD console to SQL
SDL_Texture* libtcod_SDL_texture = SDL_CreateTexture(SDL_renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, 17 * 16, 3 * 16);
TCOD_sdl2_render_texture_setup(tileset_atlas, (off_console->get_data()), nullptr, &libtcod_SDL_texture);
TCOD_sdl2_render_texture(tileset_atlas, (off_console->get_data()), nullptr, libtcod_SDL_texture);
SDL_Rect dest = {0, 0, 276, 48};
SDL_RenderCopy(SDL_renderer, libtcod_SDL_texture, NULL, &dest);
SDL_RenderPresent(SDL_renderer);
SDL_Event event;
SDL_WaitEvent(&event);
switch (event.type) {
case SDL_QUIT:
return 0; // Exit.
}
}
} Adapt the font name for one that you have or change it for an image font with Thanks to @davemoore22 for the base and @HexDecimal for the extra info to fix part of the code! And good luck to everyone else on your projects! |
@belug23, superb! Nice one! |
Here's an incremental update of the above. I've tested this version: #include <SDL.h>
#include <libtcod.h>
int main(int argc, char* argv[]) {
// Setup the SDL Window
const int window_width = 1080;
const int window_height = 720;
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* sdl_window = SDL_CreateWindow(
"libtcod + SDL",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
window_width,
window_height,
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
SDL_Renderer* sdl_renderer =
SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE);
SDL_SetRenderDrawBlendMode(sdl_renderer, SDL_BLENDMODE_NONE);
// Setup the TCOD Tileset and prepare it to be rendered to the window
TCOD_Tileset* tileset = TCOD_tileset_load("dejavu16x16_gs_tc.png", 32, 8, 256, TCOD_CHARMAP_TCOD);
TCOD_TilesetAtlasSDL2* tileset_atlas = TCOD_sdl2_atlas_new(sdl_renderer, tileset);
// Create a sample TCOD console
tcod::ConsolePtr off_console = tcod::new_console(17, 3);
// Used for console to texture rendering.
TCOD_Console* cache_console = nullptr;
SDL_Texture* libtcod_sdl_texture = nullptr;
while (1) { // Game loop.
tcod::print_frame(
*off_console, 0, 0, off_console->w, off_console->h, "", &TCOD_light_red, &TCOD_black, TCOD_BKGND_OVERLAY, true);
tcod::print(*off_console, 1, 1, "libtcod overlay", &TCOD_white, &TCOD_black, TCOD_BKGND_SET, TCOD_LEFT);
SDL_SetRenderDrawColor(sdl_renderer, 255, 255, 255, 255);
SDL_RenderClear(sdl_renderer);
// Now render the TCOD console to SQL
TCOD_sdl2_render_texture_setup(tileset_atlas, off_console.get(), &cache_console, &libtcod_sdl_texture);
TCOD_sdl2_render_texture(tileset_atlas, off_console.get(), cache_console, libtcod_sdl_texture);
const SDL_Rect dest = {0, 0, 276, 48};
SDL_RenderCopy(sdl_renderer, libtcod_sdl_texture, NULL, &dest);
SDL_RenderPresent(sdl_renderer);
SDL_WaitEvent(nullptr);
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
return 0; // Exit.
}
}
}
} Better handling of the SDL2 renderer. SDL surface stuff was mostly an SDL1 thing. This font is from libtcod's font directory, which is easier for me to find. Prevents a memory leak where a new
The event loop was modified to exhaust all events before the next loop. Reading only one event per grame loop is a common cause of lag issues. |
Thanks @HexDecimal for all the improvements! I've seen so many examples with the single event loop on the internet so now I'll keep this as the base loop for my future SDL projects. What is the use of the cache_console? |
I'm not sure how well other event loops work in SDL, but I've gotten very familiar with event queue issues from how libtcod's event API accesses SDL events. It's a common problem in some libtcod games. So if you've ever experienced keyboard lag in a libtcod game then it was likely related to this. |
@HexDecimal , I'd like permission to upload your example to my own github (appropriately credited of course!), as this is incredibly very useful functionality! |
@davemoore22, I just modified belug23's example a little. That said you can consider those edits public domain. Keep in mind that the experimental functions I mentioned are provisional. Although C++ overloads make it easier for me to not break them later. |
I've found a problem with the revised version, those 2 lines:
Where replaced by:
I found that not using the window renderer would cause rendering order issues, the console would always be rendered over the other SDL elements you render. You don't need to assign the Surface to remove the ghosting so I ended up using it like that:
The source code of SDL indicates that the framebuffer could be created at that point https://github.com/libsdl-org/SDL/blob/main/src/video/SDL_video.c#L2447 I've tried calling |
https://wiki.libsdl.org/SDL_GetWindowSurface Remarks:
Window surfaces are not compatible with the rendering API which libtcod uses. You'd have to use
There's not much I can add unless you show what you did. I've followed the SDL2 documentation rather than looking at the sources. The way I initialized the renderer is pretty standard for SDL2. Be sure to stick to the 2D Accelerated Rendering API. Surfaces should be converted into textures before you render them to the screen. |
Ok I've been working a lot on a game using this way of rendering the console and I have an extra tip to solve the alpha issue, it's quite simple, but you need to set the blending mode on the texture before copying it:
It wasn't complex, but if it helps someone. P.S. HexDecimal Sorry if I didn't answer your previous comment, I suppose my problem came from the fact that I'm using an OpenGL enabled SDL_Window, that's probably the reason I need to call |
I really thought I'm not sure what to do about supporting OpenGL. OpenGL's early API is really bad and isn't helpful when trying to extend it to support new features. |
Hi! Have you considered just exposing Let me know if I can help or send a PR! |
I have thought of it. The issue with accumulate is that it's sensitive to the window size and the method you use to add a custom overlay to it will break if the renderer isn't what you expected. Libtcod will automatically fallback to using OpenGL1 or SDL2 if the faster API's are not supported by the OS. You'd have to force it to use the SDL2 renderer in most cases where you have a manual overlay. At that point it's best to use |
libtcod can be possessive of the SDL window sometimes, making it hard to add any kind of drawing routine in the middle of libtcod's console_flush function.
Splitting
console_flush
into arender_console
anddisplay_flip
function would make any custom drawing onto SDL much easier.This would also mean libtcod should be able to return the pointer to its SDL window and renderer, so that the user can access them.
The text was updated successfully, but these errors were encountered: