pp0.png
[Hide]  (34.2KB, 804x638) pp1.png
[Hide]  (35KB, 804x638) pp2.png
[Hide]  (35.4KB, 804x638) crate.png
[Hide]  (11.8KB, 128x128) goblin16.png
[Hide]  (4.3KB, 128x256) >>562
Implemented one of the vertical slice/proof-of-concept features today - pixel-perfect object selection. The selection is done in two steps: the first is to see if the mouse click coordinates are within an object's axis-aligned bounding box (AABB), for which I'm just using the texture size for right now (eventually I will use a per-image settable AABB, to reduce the number of pixel-selected searches, since they are far more expensive. The second step is to load the image data from the GPU texture back into main RAM, then query the pixel at the click location to see if it's alpha channel value is higher than 0 - in other words, is not a transparent pixel. When an object is selected, I then use a shader (taken unedited from Raylib example ht tps://github.com/raysan5/raylib/blob/master/examples/shaders/shaders_texture_outline.c) to draw an outline around it. main.cpp is as follows:
#include "main.h"
#include "raylib.h"
#include "debug.h"
#include "rlgl.h" 
void DrawTextureSimple(Texture2D & texture, Vector2 origin, Color tint, float scale)
{
    
    if (texture.id > 0)
    {
        float width = (float)texture.width * scale;
        float height = (float)texture.height * scale;
        rlSetTexture(texture.id);
        rlBegin(RL_QUADS);
            rlColor4ub(tint.r, tint.g, tint.b, tint.a);
            rlNormal3f(0.0f, 0.0f, 1.0f); 
            
            rlTexCoord2f(0.0f, 0.0f);
            rlVertex2f(origin.x, origin.y);
            
            rlTexCoord2f(0.0f, 1.0f);
            rlVertex2f(origin.x, origin.y + height);
            
            rlTexCoord2f(1.0f, 1.0f);
            rlVertex2f(origin.x + width, origin.y + height);
            
            rlTexCoord2f(1.0f, 0.0f);
            rlVertex2f(origin.x + width, origin.y);
        rlEnd();
        rlSetTexture(0);
    }
}
class PickableObject
{
    public:
        std::string name;
        
        Texture2D texture;
        
        Shader outline_shader;
        
        Vector2 center;
        
        bool within_aabb = false;
        bool selected = false;
        
        
        PickableObject(std::string name, std::string texture_file, Vector2 center);
        
        
        void draw(void);
        
        void check_collision(Vector2 mouse_coords);
};
PickableObject::PickableObject(std::string name, std::string texture_file, Vector2 center)
{
    
    this->name = name;
    
    
    this->center = center;
    
    
    #ifdef DEBUG
    debug_out("ATTEMPT TO OPEN PATH: " + std::string(TextFormat("data/%s.png", texture_file.c_str())));
    #endif
    
    Image img = LoadImage(TextFormat("data/%s.png", texture_file.c_str()));
    
    
    
    
	texture = LoadTextureFromImage(img);
    
    UnloadImage(img);
    
    
    outline_shader = LoadShader(0, "data/shaders/outline.fs");
    
    float outlineSize = 2.0f;
    float outlineColor[4] = {1.0f, 0.0f, 0.0f, 1.0f}; 
    float textureSize[2] = { (float)texture.width, (float)texture.height };
    
    
    int outlineSizeLoc = GetShaderLocation(outline_shader, "outlineSize");
    int outlineColorLoc = GetShaderLocation(outline_shader, "outlineColor");
    int textureSizeLoc = GetShaderLocation(outline_shader, "textureSize");
    
    
    SetShaderValue(outline_shader, outlineSizeLoc, &outlineSize, SHADER_UNIFORM_FLOAT);
    SetShaderValue(outline_shader, outlineColorLoc, outlineColor, SHADER_UNIFORM_VEC4);
    SetShaderValue(outline_shader, textureSizeLoc, textureSize, SHADER_UNIFORM_VEC2);
}
void PickableObject::draw(void)
{
    
    float draw_x = center.x - ((float)texture.width / 2);
    float draw_y = center.y - ((float)texture.height / 2);
    
    if (selected)
    {
        
        BeginShaderMode(outline_shader);
        
        DrawTextureSimple(texture, {draw_x, draw_y}, WHITE, 1.0f);
        
        EndShaderMode();
    }
    else
    {
        
        DrawTextureSimple(texture, {draw_x, draw_y}, WHITE, 1.0f);
        
    }
    
    if (within_aabb)
    {
        
        DrawRectangleLines(draw_x, draw_y, texture.width, texture.height, WHITE);
    }
}
void PickableObject::check_collision(Vector2 mouse_coords)
{
    
    if (mouse_coords.x > (center.x - ((float)texture.width / 2)) && mouse_coords.x < (center.x + ((float)texture.width / 2)))
    {
        if (mouse_coords.y > (center.y - ((float)texture.height / 2)) && mouse_coords.y < (center.y + ((float)texture.height / 2)))
        {
            #ifdef DEBUG
            debug_out("CLICKED WITHIN AABB OF " + std::string(TextFormat("%s", name.c_str())));
            #endif
            
            within_aabb = true;
            
            
            
            Image img = LoadImageFromTexture(texture);
            
            
            int pixel_x = (int)mouse_coords.x - ((int)center.x - (texture.width / 2));
            int pixel_y = (int)mouse_coords.y - ((int)center.y - (texture.height / 2));
            
            #ifdef DEBUG
            debug_out("CLICKED IMAGE PIXEL COORDS: " + std::to_string(pixel_x) + ", " + std::to_string(pixel_y));
            #endif
            
            Color pixel = GetImageColor(img, pixel_x, pixel_y);
            
            if (pixel.a > 0) 
            {
                #ifdef DEBUG
                debug_out(std::string(TextFormat("%s", name.c_str())) + " SELECTED");
                #endif
                
                selected = true;
            }
            else
            {
                selected = false;
            }
            
            UnloadImage(img);
            
            return;
        }
    }
    
    within_aabb = false;
    selected = false;
}
int main(int argc, char *argv[])
{
    
    
    SetWindowState(FLAG_MSAA_4X_HINT);
    SetWindowState(FLAG_VSYNC_HINT);
    
    
    InitWindow(WIN_WIDTH, WIN_HEIGHT, "PIXEL PICKING"); 
    
    center_window();
    
    
    PickableObject gob = {"goblin", "goblin16", {250, 300}};
    PickableObject crate = {"crate", "crate", {550, 300}};
    
    
    
    while (!WindowShouldClose()) 
    {
        
        
        if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT))
        {
            Vector2 mouse = GetMousePosition();
        
            gob.check_collision(mouse);
            crate.check_collision(mouse);
        }
        
        
        
        
        BeginDrawing();
        
        ClearBackground(BLACK);
        
        
        gob.draw();
        crate.draw();
        
        EndDrawing();
        
        
    }
    
    
    CloseWindow(); 
}
void center_window(void)
{
    int display = GetCurrentMonitor();
    int display_width = GetMonitorWidth(display);
    int display_height = GetMonitorHeight(display);
    
    SetWindowPosition((display_width / 2) - (GetScreenWidth() / 2), (display_height / 2) - (GetScreenHeight() / 2));
}
The shader code file, outline.fs, is from the example:
#version 330
in vec2 fragTexCoord;
in vec4 fragColor;
uniform sampler2D texture0;
uniform vec4 colDiffuse;
uniform vec2 textureSize;
uniform float outlineSize;
uniform vec4 outlineColor;
out vec4 finalColor;
void main()
{
    vec4 texel = texture(texture0, fragTexCoord);   
    vec2 texelScale = vec2(0.0);
    texelScale.x = outlineSize/textureSize.x;
    texelScale.y = outlineSize/textureSize.y;
    
    vec4 corners = vec4(0.0);
    corners.x = texture(texture0, fragTexCoord + vec2(texelScale.x, texelScale.y)).a;
    corners.y = texture(texture0, fragTexCoord + vec2(texelScale.x, -texelScale.y)).a;
    corners.z = texture(texture0, fragTexCoord + vec2(-texelScale.x, texelScale.y)).a;
    corners.w = texture(texture0, fragTexCoord + vec2(-texelScale.x, -texelScale.y)).a;
    float outline = min(dot(corners, vec4(1.0)), 1.0);
    vec4 color = mix(vec4(0.0), outlineColor, outline);
    finalColor = mix(color, texel, texel.a);
}
You're gonna need the attached images to make it run too.