Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/serge-rgb/Milton
Browse files Browse the repository at this point in the history
  • Loading branch information
serge-rgb committed Sep 25, 2015
2 parents bfc77df + 59ae04c commit 29aa974
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 53 deletions.
18 changes: 8 additions & 10 deletions TODO.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,47 +5,45 @@ To-Do
- Bugs
- :)

- (Immediate-mode) UI
- x-form color picker code into immediate mode API.
- GUI
- Image Button (hover & click)
- Brush / Eraser buttons
- Text (stb)
- F1 help widget
- GUI toggle key
- History slider.
- Text input box.
- Selection rectangle
- "Export" button
- Sliders for brush size & opacity / eraser
- LRU color list
- Layers
- Drag-and-drop

- Engine
- Wacom:
- Pressure levels (only OSX left)
- Windows buttons
- Windows stylus buttons

- Performance:
- Live profiler
- memcpy when Panning
- Write perf logger to make informed decision.
- Undo/Redo: Only redraw necessary area.
- Amdahl's curse... Parallelize color picker rendering
- ??? Trim strokes: we've got too many points
- ??? Stroke Level-of-Detail downsampling based on relative size.
- Amdahl's curse... Parallelize GUI rendering
- Stress the renderer with a huge drawing.
- Robust save
- Export
- JPEG (tiny_jpeg)
- PNG (stb)
- PNG (stb? hand written?)
- Playback
- Store view changes in persist file
- Playback mode? Separate viewer?

- Brush
- Support for general, implicitly defined brushes

- Not replicable yet
- It sometimes sticks in low-quality mode.
- Debug
- Input recorder for bug replication

============================================================
==== 1.0 Beta Milestone ====
Expand Down
121 changes: 86 additions & 35 deletions src/gui.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,24 +154,31 @@ func b32 is_inside_picker_active_area(ColorPicker* picker, v2i point)
return result;
}

func b32 is_inside_picker_button_area(ColorPicker* picker, v2i point)
func Rect picker_color_buttons_bounds(ColorPicker* picker)
{
static b32 rect_is_cached;
static Rect button_rect;
if (!rect_is_cached) {
button_rect = (Rect) { 0 };
ColorButton* button = &picker->color_buttons;
while (button) {
button_rect = rect_union(button_rect,
color_button_as_rect(button));
button = button->next;
}
Rect bounds = {
.right = INT_MIN,
.left = INT_MAX,
.top = INT_MAX,
.bottom = INT_MIN,
};
ColorButton* button = &picker->color_buttons;
while (button) {
bounds = rect_union(bounds,
color_button_as_rect(button));
button = button->next;
}
return bounds;
}

func b32 is_inside_picker_button_area(ColorPicker* picker, v2i point)
{
Rect button_rect = picker_color_buttons_bounds(picker);
b32 is_inside = is_inside_rect(button_rect, point);
return is_inside;
}

func b32 is_picker_accepting_input(ColorPicker* picker, v2i point)
func b32 picker_is_accepting_input(ColorPicker* picker, v2i point)
{
// If wheel is active, yes! Gimme input.
if (picker->flags & ColorPickerFlags_WHEEL_ACTIVE) {
Expand Down Expand Up @@ -219,15 +226,24 @@ func v3f picker_hsv_from_point(ColorPicker* picker, v2f point)
return hsv;
}

func b32 point_hit_picker_button(ColorPicker* picker, v2i point)
func b32 picker_hit_history_buttons(ColorPicker* picker, v2i point)
{
b32 hits = false;
ColorButton* button = &picker->color_buttons;
ColorButton* first = &picker->color_buttons;
ColorButton* button = first;
while (button) {
if (button->color.a != 0 &&
is_inside_rect(color_button_as_rect(button), point)) {
picker->info = button->picker_data;
if ( button->color.a != 0 &&
is_inside_rect(color_button_as_rect(button), point) ) {
hits = true;
picker->info = button->picker_data;
// Swap info with the first.
v4f swp_color = button->color;
PickerData swp_data = button->picker_data;
button->color = first->color;
button->picker_data = first->picker_data;
first->color = swp_color;
first->picker_data = swp_data;

break;
}
button = button->next;
Expand Down Expand Up @@ -303,6 +319,7 @@ func void picker_init(ColorPicker* picker)
struct MiltonGui_s {
b32 active; // `active == true` when gui currently owns all user input.
b32 did_change_color;
b32 did_hit_button; // Avoid multiple clicks.

ColorPicker picker;
};
Expand All @@ -313,12 +330,25 @@ func v3f gui_get_picker_rgb(MiltonGui* gui)
return rgb;
}

func b32 picker_is_active(ColorPicker* picker)
{
b32 is_active = (picker->flags & ColorPickerFlags_WHEEL_ACTIVE) ||
(picker->flags & ColorPickerFlags_TRIANGLE_ACTIVE);

return is_active;
}

// Returns true if the GUI consumed input. False if the GUI wasn't affected
func b32 gui_consume_input(MiltonGui* gui, MiltonInput* input)
{
v2i point = input->points[0];
b32 accepts = is_picker_accepting_input(&gui->picker, point);
accepts |= point_hit_picker_button(&gui->picker, point);
b32 accepts = picker_is_accepting_input(&gui->picker, point);
if ( !gui->did_hit_button &&
!picker_is_active(&gui->picker) &&
picker_hit_history_buttons(&gui->picker, point)) {
accepts = true;
gui->did_hit_button = true;
}
return accepts;
}

Expand Down Expand Up @@ -389,27 +419,47 @@ func void gui_init(Arena* root_arena, MiltonGui* gui)
// button list.
func b32 gui_mark_color_used(MiltonGui* gui, v3f stroke_color)
{
b32 added = false;
ColorButton* button = &gui->picker.color_buttons;

b32 changed = false;
ColorButton* start = &gui->picker.color_buttons;
v3f picker_color = hsv_to_rgb(gui->picker.info.hsv);
if (!equals_v3f(picker_color, button->color.rgb)) {
added = true;
v4f button_color = color_rgb_to_rgba(picker_color,1);
PickerData picker_data = gui->picker.info;
// Pass info to the next one.
while (button) {
v4f tmp_color = button->color;
PickerData tmp_data = button->picker_data;
button->color = button_color;
button->picker_data = picker_data;
button_color = tmp_color;
picker_data = tmp_data;
if ( start->color.a == 0 || !equals_v3f(picker_color, start->color.rgb)) {

// Search for a color that is already in the list
ColorButton* button = start;
while(button) {
if ( button->color.a != 0 && equals_v3f(button->color.rgb, stroke_color) ) {
// Move this button to the start and return.
changed = true;
v4f tmp_color = button->color;
PickerData tmp_data = button->picker_data;
button->color = start->color;
button->picker_data = start->picker_data;
start->color = tmp_color;
start->picker_data = tmp_data;
}
button = button->next;
}
button = start;

if ( !changed ) {
changed = true;
v4f button_color = color_rgb_to_rgba(picker_color,1);
PickerData picker_data = gui->picker.info;
// Pass info to the next one.
while (button) {
v4f tmp_color = button->color;
PickerData tmp_data = button->picker_data;
button->color = button_color;
button->picker_data = picker_data;
button_color = tmp_color;
picker_data = tmp_data;
button = button->next;
}

}
}

return added;
return changed;
}

func void gui_deactivate(MiltonGui* gui)
Expand All @@ -419,4 +469,5 @@ func void gui_deactivate(MiltonGui* gui)
// Reset transient values
gui->active = false;
gui->did_change_color = false;
gui->did_hit_button = false;
}
51 changes: 43 additions & 8 deletions src/rasterizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -1042,6 +1042,36 @@ func void draw_rectangle(u32* raster_buffer,
}
}

// 1-pixel margin
func void draw_rectangle_with_margin(u32* raster_buffer,
i32 raster_buffer_width, i32 raster_buffer_height,
i32 center_x, i32 center_y,
i32 rect_w, i32 rect_h,
v4f rect_color, v4f margin_color)
{
i32 left = max(center_x - rect_w, 0);
i32 right = min(center_x + rect_w, raster_buffer_width);
i32 top = max(center_y - rect_h, 0);
i32 bottom = min(center_y + rect_h, raster_buffer_height);

assert (right >= left);
assert (bottom >= top);

for ( i32 j = top; j < bottom; ++j ) {
for ( i32 i = left; i < right; ++i ) {
i32 index = j * raster_buffer_width + i;

u32 dst_color = raster_buffer[index];
v4f src_color = (i == left || i == right - 1 ||
j == top || j == bottom - 1) ? margin_color : rect_color;

v4f blended = blend_v4f(color_u32_to_v4f(dst_color), src_color);
u32 color = color_v4f_to_u32(blended);
raster_buffer[index] = color;
}
}
}


func void rasterize_color_picker(ColorPicker* picker,
Rect draw_rect)
Expand Down Expand Up @@ -1432,12 +1462,12 @@ func void render_gui(MiltonState* milton_state,
MiltonRenderFlags render_flags)
{
b32 redraw = false;
Rect picker_rect = picker_get_bounds(&milton_state->gui->picker);
Rect picker_rect = rect_union(picker_get_bounds(&milton_state->gui->picker),
picker_color_buttons_bounds(&milton_state->gui->picker));
Rect clipped = rect_intersect(picker_rect, raster_limits);
if ( (clipped.left != clipped.right) && clipped.top != clipped.bottom ) {
redraw = true;
}

MiltonGui* gui = milton_state->gui;
if ( redraw || (render_flags & MiltonRenderFlags_PICKER_UPDATED) ) {
render_canvas(milton_state, raster_buffer, picker_rect);
Expand All @@ -1448,12 +1478,17 @@ func void render_gui(MiltonState* milton_state,

ColorButton* button = &milton_state->gui->picker.color_buttons;
while(button) {
draw_rectangle(raster_buffer,
milton_state->view->screen_size.w, milton_state->view->screen_size.h,
button->center_x, button->center_y,
button->width, button->height,
button->color);
button = button->next;
if (button->color.a == 0) {
break;
}
draw_rectangle_with_margin(raster_buffer,
milton_state->view->screen_size.w, milton_state->view->screen_size.h,
button->center_x, button->center_y,
button->width, button->height,
button->color,
// Black margin
(v4f){ 0, 0, 0, 1 });
button = button->next;
}
// Draw an outlined circle for selected color.
i32 circle_radius = 20;
Expand Down

0 comments on commit 29aa974

Please sign in to comment.